Pokemon style text list inventory. [SOLVED]

Started by Stranga, Sat 07/11/2020 22:06:23

Previous topic - Next topic

Stranga

Hello everyone,

I'm looking at creating a text list like inventory. I have an idea to use a list box along side an invisible inventory window to select the item in the list and just use an updater to check if the player has an item it would update the name in the list box. But I'm not sure how to implement it exactly (of if it can be done!). Any help would be greatly appreciated :)

Crimson Wizard

#1
This might be quite simple to do, and even without real inventory items if you dont like using them, as you may refer to the list box itself or the array of Strings in the script instead.

InventoryWindow is only necessary in one case: if you want to list items in the order of their pickup and dont want to keep track of that yourself. Since AGS does not give access to that order, the only way to access it is through InvWindow. Otherwise it is not needed. And of course you can also track this order yourself, that's just bit more scripting.

Other than that, it's just filling list box with item names. If you are using InvWindow, then run over InvWindow.ItemAtIndex[] array, using InvWindow.ItemCount to know their total. If you don't use InvWindow, then run over player.InventoryQuantity[] to see which items are present.
Or script your own inventory array and extra functions instead of AddInventory/LoseInventory.

Stranga

#2
Thanks for your reply CW! I'll take a crack at that later this afternoon. I'd rather let the engine do the bulk work of keeping track of the items. I wouldn't mind learning how to script it in total for learning purposes though, could be useful in other game engines.

As for adding the item name to the list box item.I tried last night to extract the item.Name string to listbox.additem() but it errors saying something about cannot convert into to string or something similar. I'm not at the PC now so I can't exactly paste the actual error. But I think there's a way of converting an int to a string...I think.

EDIT: This only happens when I go to remove an item from the listbox. Adding an item works fine.

P.S while I'm on the subject, is there a way to track the list box options with say a button? I thinking of making a listbox like menu and because my games are all keyboard based I was wondering if it could be possible to interact with the listbox via script rather than on mouse clicks.

Crimson Wizard

Quote from: Stranga on Sun 08/11/2020 01:06:00
P.S while I'm on the subject, is there a way to track the list box options with say a button? I thinking of making a listbox like menu and because my games are all keyboard based I was wondering if it could be possible to interact with the listbox via script rather than on mouse clicks.

You can change ListBox.SelectedIndex property, ListBox.TopItem let you set topmost shown item, alternative to which is ListBox.ScrollUp and ScrollDown functions. How do you call these, from key events, mouse clicks, button clicks etc, is all up to you.

eri0o

If you want to use inventory window itself you could auto generate the sprite for each item using dynamic sprites when the inventory opens and blow them up when the inventory closes. This way you get an inventory window with text. :p

Stranga

@CW: I have an idea on how to call each event by using an alternative (invisible) menu using key presses and have the listbox just for show.

@eri0o: That sounds interesting. How would I exactly go about doing something like this? I haven't played with dynamic sprites before(or maybe I have and not noticed, haha) :)

Khris

Exactly, just stick to a regular inventory window and use DynamicSprites with text on them. I'd use persistent sprites (declare an array of them at the top of the global script), loop over the items in game_start, use  DrawingSurface.DrawString  to print the item's description on the sprite, then assign it as  .Graphic.

eri0o

#7
@Stranga, here it is a very simple version of it: Download Here AGS Project

TextInventory.ash
Code: ags
// new module header
struct TextInventory
{
  import static void Open();
  import static void Close();
};



TextInventory.asc
Code: ags
// new module script
DynamicSprite* ItmSpr[MAX_INV];

void _DeleteAllInvSprites()
{
  for(int i=0;i<Game.InventoryItemCount; i++)
  {
    int inv_i = i+1;
    inventory[inv_i].Graphic = 0;
    if(ItmSpr[i] != null)
    {
      ItmSpr[i].Delete();
      ItmSpr[i] = null;
    }
  }   
}

static void TextInventory::Open()
{
  int itm_width = 80, itm_height = 20;
  int text_color = 61113;
  
  InventoryWindow1.ItemWidth = itm_width;
  InventoryWindow1.ItemHeight = itm_height; 
  
  _DeleteAllInvSprites();
  
  for(int i=0;i<Game.InventoryItemCount; i++)
  {
    int inv_i = i+1;
    ItmSpr[i] = DynamicSprite.Create(itm_width, itm_height, true);
    DrawingSurface* surf = ItmSpr[i].GetDrawingSurface();
    surf.DrawingColor = text_color;
    surf.DrawStringWrapped(0, 0, itm_width, eFontFont0, eAlignCenter, inventory[inv_i].Name);
    surf.Release();
    inventory[inv_i].Graphic = ItmSpr[i].Graphic;
  }
    
  gInventory.Visible = true;
}

static void TextInventory::Close()
{
  gInventory.Visible = false;
  
  _DeleteAllInvSprites();
}


The main idea to delete all images when the inventory is closed and regenerating all of them when the inventory is open is because otherwise the sprites are saved with the game save if you are using regular ags save files.

If you have written your own save, then you can disregard and do as Khris says and only generate them once, at game_start. It's also generally ok to have them in your game file, but if your inventory has too many items depending on your game resolution this may be a lot of data to store.

The main idea of all of this are the following lines

  // iterate all available items
  for(int i=0;i<Game.InventoryItemCount; i++)
  {
    int inv_i = i+1; // inventory items count starting from 1, our array to store the sprites starts from 0
    ItmSpr = DynamicSprite.Create(itm_width, itm_height, true); // creates an empty sprite
    DrawingSurface* surf = ItmSpr.GetDrawingSurface();
    surf.DrawingColor = text_color; // our text color
    surf.DrawStringWrapped(0, 0, itm_width, eFontFont0, eAlignCenter, inventory[inv_i].Name); // draws the text, I am center aligning, but you can do whatever here
    surf.Release(); // releases the surface
    inventory[inv_i].Graphic = ItmSpr.Graphic; // pass the sprite we created to the item
  }

Stranga

#8
Thank you both eri0o and khris! This works perfectly! I can interact with the items too! Although, I just need to figure out a way to track them with keyboard functions/GUI button(makeshift cursor) but the bulk of what I was trying to do has been solved! Thank you all who contributed! :)

EDIT: Actually eri0o, while were on the topic of dynamic sprites. Is there a way to track the position of one to uses as a cursor? I was thinking about using one to select an inventory item from the list as I can't figure out a way to make an inventory item active.

Khris

A DynamicSprite doesn't have a position; it's the same as a static (u.e. imported) sprite, the difference is that it doesn't exist before the game runs.

To display one on screen, it has to be drawn, or assigned as .Graphic to an object, or mouse mode, etc. If assigned as mode graphic, it'll move with the cursor just like a regular cursor sprite because in that regard it makes no difference to AGS.

So this means all you need to do is set the generated sprites as graphics for the inventory items, and on a permanent basis so they can be displayed as cursor sprite even while the inventory is closed.

And what do you mean by your last sentence? Are you overriding built-in inventory click handling?

Stranga

Thanks for the response Khris. I've got a much better understanding of dynamic sprites and have some ideas to use in some of my other projects. And yes, I'm using keyboard only for inventory handling. I'm not sure how to go about inventory click/handling without mouse properties. I've looked at controlling the mouse directly but I'd rather not use one at all if possible.

Khris

Right, I forgot about the keyboard controls. In that case you need some type of indicator, like an arrow or frame. To display something like that on top of the inventory window, you can use a small GUI and its background image.
The currently active inventory item is stored as zero-based index, and pressing an arrow key while the inventory is open will change that index, then recalculate the coordinates for the indicator GUI based on the index.

Stranga

That was one of the ideas I had in mind the other was to use a button and to offset an indicator to the right which would have lined up with the inventory items.Although, I'm not sure a button would work as I've tried to use one in the past with no luck so I guess the GUI would work?

eri0o

#13
@Stranga, have you tried my module for arrow controls? It will provide cursor navigation on all GUIs, plus everything else (except dialogs because they dont give me mouse position) -> https://www.adventuregamestudio.co.uk/forums/index.php?topic=57379.0

I pair it with my  controlz module for complete keyboard/joystick navigation on my game. I use then the joystick plugin api mouse click to do mouse clicks on the interface through keyboard/joystick.




Other than this I would do the button way and use an integer to store the "selected" inventory window index, you can also edit the background color of the selected item graphic dynamic sprite or tint it to indicate it is selected on screen.

Stranga

@eri0o I have yes, it's a very useful module! My only concern was that I am using my own keyboard movement script but I may just use it anyway because it is such a timesaver(I can use it just for the menus). Thanks again everyone for the help! I greatly appreciate it :)

SMF spam blocked by CleanTalk