Removing ListBox Items

Started by Slasher, Fri 14/09/2012 19:51:20

Previous topic - Next topic

Slasher

Hi

I need a bit of help regarding a ListBox.

I have set up a list box and added items as the player collects them and removes them when used.

IE Get sandwich and it is added to ListBox. Use sandwich on rat and it gets removed from ListBox.

Sandwich is the only thing in the list you can have at that time and works ok.

Code: AGS
ListBox1.RemoveItem(0);


This is ok but this is where the snag starts.

If you look at the ListBox items and say want to remove the 4th item would you use:

Code: AGS
ListBox1.RemoveItem(3);


Scenerio:

4 spindles, each requires a certain colored reel of wool. The reels can be done in any order and are taken off the Listbox as they are done.

Of course the reels of wool can be got in any colored order!

Is this the correct way of removing an item: if 3rd in list remove(2), if 6th item in the list remove(7) ?

cheers if you can assist me


[EDIT: used this to remove items and it works but should leave the ladder which should be at the top of the list. Will continue....

Code: AGS
ListBox1.RemoveItem(0);
 ListBox1.RemoveItem(0);
 ListBox1.RemoveItem(0);
 ListBox1.RemoveItem(0);



Crimson Wizard

The items in ListBox are zero-based, that means that first is 0, second is 1, and so forth.
Or, generally, the Xth item has index of (X-1).

Quote from: slasher on Fri 14/09/2012 19:51:20
Is this the correct way of removing an item: if 3rd in list remove(2), if 6th item in the list remove(7) ?
I don't know how you got this idea (3rd = 2, 6th = 7). Anyway, it should be:
3rd: 3 - 1 = remove(2);
6th: 6 - 1 = remove(5);

Also, take into consideration that after you remove one item, all the following are being moved up once. So if you want to remove several items in sequence you'll have to recalculate their position after each is removed.
For example, you want to remove 3rd, 6th and 10th items one by one.
Remove(2) - removes 3rd; but the following items are now moved up and the 6th item is now 5th, 10th item is now 9th.
Remove(4) - remove 4th (former 5th); the 9th item (former 10th) is now 8th.
Remove(7) - remove 8th item (that was 10th at the very beginning).

Hopefully my explanation is not very confusing.

Slasher

#2
Thank you for that great explanation Crimson Wizard.

But what if you do not know what the player picks up first?

Fly then sandwich or sandwich then fly.

It would be so easier if you could remove an item as added by name.. ie "Fly" etc.

cheers

Crimson Wizard

#3
Quote from: slasher on Fri 14/09/2012 20:16:30
But what if you do not know what the player picks up first?
That's very good question. In fact, if you want to make a good script, you should assume exactly that - that you don't know the order of those items in the list.
Unfortunately AGS script does not provide direct means to get a listbox item by name. However, you may use following solution.
You may get item's text by the use of ListBox.Items array. For example:
ListBox1.Items[0] - returns first item's text;
ListBox1.Items[ListBox1.SelectedIndex] - returns selected item's text;
If you know what exactly inventory item are you using, you can find a list item that has same name.

Code: ags

int i = 0;
while (i < ListBox1.ItemCount) // search from first to last item
{
   if (ListBox1.Items[i] == "Fly")
   {
      // found it!
      ListBox1.RemoveItem(i); // remove this item
      i = ListBox1.ItemCount; // a trick to end the loop right away
   }
   i++; // next item...
}


Now, how to use this in your game - that depends on how using of inventory items is scripted in there. You gave no details about that, but let's assume that at certain point (when item is being used) you have the item's script name (such as iFly, for example).
We make a separate function that take the used item as parameter and removes it from the list:
Code: ags

function RemoveItem(InventoryItem *used_item)
{
   int i = 0;
   while (i < ListBox1.ItemCount) // search from first to last item
   {
      if (ListBox1.Items[i] == used_item.Name)
      {
         // found it!
         ListBox1.RemoveItem(i); // remove this item
         i = ListBox1.ItemCount; // a trick to end the loop right away
      }
      i++; // next item...
   }
}


Then you call that function, like:
Code: ags

RemoveItem(iFly);


This code is just an example, and may be optimized or used differently depending on how you write your game's script.

EDIT: fixed one mistake in my code.

One more thing though, may I ask why do you use ListBox, and not InventoryWindow GUI? Just want to be sure you are aware of it. InventoryWindow solves all those problems automatically.


Slasher

#4
Hi Crimson Wizard

whilst i am digesting what you have written i would like to add that the listbox is separate from the inv gui which is included in the game. The listbox is more an instant visual thing. I could of course just have inv in view all the time but i don't. The listbox was something i thought would make a nice touch.

I was going to use a label and append it. unfortunately i don't know if you can take text away from that.. sort of opposite of append. Anyhow...

cheers


Crimson Wizard

Quote from: slasher on Fri 14/09/2012 21:54:56
whilst i am digesting what you have written i would like to add that the listbox is separate from the inv gui which is included in the game. The listbox is more an instant visual thing. I could of course just have inv in view all the time but i don't. The listbox was something i thought would make a nice touch.

I was going to use a label and append it. unfortunately i don't know if you can take text away from that.. sort of opposite of append. Anyhow...
Do you mean that the ListBox is simply an extra visual representation of Inventory contents? Well, I can't say that's a bad decision. Probably you may try both ListBox and Label options and find what suits you better.
Regarding working with text in Label. If I understood correctly, you have problem removing parts of text from existing string. Actually there's no other way than to reconstruct the string all over again each time the item is removed. That's not difficult if you use generic algorythm for both adding and removing items, based on loop (similar to what I showed above).
For example, assuming your label is called gInventoryLabel:
Code: ags

function MakeInventoryLabel()
{
   gInventoryLabel.Text = ""; // make string empty first
   int i = 0;
   while (i < Game.InventoryItemCount) // check every possible inventory item in the game
   {
      if (player.InventoryQuantity[i] > 0) // if player has such inventory item
      {
         gInventoryLabel.Text = gInventoryLabel.Text.Append(inventory[i].Name); // append inventory item name to the string
         gInventoryLabel.Text = gInventoryLabel.Text.AppendChar('['); // append special 'linebreak' character to the string
      }
      i++; // next item...
   }
}

Then, you just run this function every time an item is added or removed. This will update label's text. The text is constructed all over again every time, but that's fast operation and won't slow down the game.
There may be a serious problem, however, that the number of items will be too large and won't fit into label. In this case you'll have to somehow limit the number of lines displayed and script scrolling... so it's more work actually.

SMF spam blocked by CleanTalk