Windows GML Tutorial suggestions for inventory?

C

Chungsie

Guest
Hi folks! I was wondering if anyone could recommend a tutorial for Inventory databasing and equip menus?

I want to use a static image of my character and specialized gear static images to display what is equiped, not really a slotted display. And allow the user to navigate beteween body parts (i.e. left/right arm, chest, head, and legs) to change what is sorted through when hitting another button.

My game will have both keyboard and game pad controls.

As far as what information the items will have, things like weight, attribute bonuses, static attributes for the gear, an adjustable health variable for the armors specific to a slot.

I already got help on the armor health hud.

I tried googling it, but I could not figure what would be best for what I have in mind.

Sorry if this is a stupid question :p

Anyways, thanks for the help if you choose to help figure things out with me. Have a beautiful time.

Chungus
 

geky

Member
I don't really understand what you need help with, is it the item database itself? You would probably want to make use of an array for that. To save a few hundred lines of code in game maker (depending on how many items you plan to add) you could write the item attributes in various files on the disk and fill the array automatically from there. It would also make it possible to change item properties without a need to re-compile. I'm rather new to Game maker, so I am not sure, but I think you can encrypt those files so the player will not be able to cheat as well.

for example one such file could look like
Code:
// info
Name=Weird mage's old helmet
Weight=12
MaxDurability=100
Description=A helmet worn by an old mage with great hatred towards grass.
// equip bonuses
IncSTR=10
DecMaxHP=100
Then the item array could look something like
Code:
var name = 0;
var weight = 1;
var maxDura = 2;
var incSTR = 3;
var decMaxHP = 4;

var cur_item = 0;

item[ cur_item , name ] = str name;
item[ cur_item, weight ] = float weight;

etc.
Then you could have a different array to store your inventory, such as
Code:
var inv_slot = 0;

inventory[ inv_slot  ] = item_id;
 

geky

Member
Well, apparently in Game maker we are limited to files that are included with the .exe ("Included Files" in the treeview). Regardless, it is still possible to do that database with external files if you want, but it would then be easier to just have one single file with all the items stored because, otherwise, you need to keep importing them to your game project... which could be a major pain in the ass if you are like me and prefer automation.

Nevertheless, let me tell you how I did it. Just, keep in mind that you will probably need to optimise it, and tweak it to better suit your needs.

I made two scripts to read a string value from position (1 up to N), and (N to EndOfString) because I could not find a function like that in the help files.
Code:
/// script_string_right( str, pos );
var str = argument0; var pos = argument1;
var length = string_length( str );
var returnStr = "";

for (var n=pos+1; n<=length; n++)
{
    returnStr += string_char_at( str, n );
}

return returnStr;
Code:
/// script_string_left( str, pos );
var str = argument0; var pos = argument1;
var returnStr = "";

for (var n=1; n<pos; n++)
{
    returnStr += string_char_at( str, n );
}

return returnStr;
Next, I created an object to prepare the 'database', in its create event I put the following.
Note: that these constants are not necessarily needed, I just prefer to know what the different numbers mean...
Code:
// constants
    item_total_attributes = 3;
    item_name   = 0;
    item_weight = 1;
    item_slot   = 2;

// array to store keywords when searing 'items.dat' file for info
    item_keyword = script_set_item_keywords();

// read items from 'items.dat'
    item = script_read_items();

// variable to store total item count in database
    total_items = array_length_1d( item ) -1;
and in the Draw event (note: I used a dark background in the room)
Code:
draw_set_colour( c_white );
draw_text( 100, 100, "total items found: "+string( total_items+1 ) );

for (var i=0; i<=total_items; i++)
{
    draw_text( 100, 120+(i*20), item[ i, item_name ] )
    draw_text( 200, 120+(i*20), item[ i, item_weight ] )
    draw_text( 300, 120+(i*20), item[ i, item_slot ] )
}
After that, I made a script to set all the keywords I wanted to use to read from the file, and here you can see the benefit of using constants instead of numbers.
Code:
/// script_set_item_keywords();
var item_keyword = 0;

    item_keyword[ item_name   ] = "name";
    item_keyword[ item_weight ] = "weight";
    item_keyword[ item_slot   ] = "slot";

return item_keyword;
I created one "items.dat" file with these contents in order to test, and imported it to the project "Included Files".
Code:
Name=Sword
slot=Mainhand

name=Torch
weight=99

name=Glove
slot=Hands
weight=1.4
And finally, this script to automatically import all information from the items.dat file into the item[] array
Code:
/// script_read_items
var cur_item = -1;
var item = 0;

var item_file = file_text_open_read( "items.dat" );

    while !(file_text_eof( item_file ))
    {
        var _string  = file_text_read_string( item_file );
      
        if (_string == "")
        {
            // it's an empty line, skip.
          
        }else{
            // find keyword and value
            var _explode = string_pos( "=", _string );
            var _keyword = script_string_left(  _string, _explode );
            var _value   = script_string_right( _string, _explode );
  
            // add new item to array when keyword 'item_name' is found
            if (string_lower(_keyword) == string_lower(item_keyword[ item_name ]))
            {
                cur_item++;
              
                // fill this item slot with 0 data to prevent crash
                for (var _i=0; _i<item_total_attributes; _i++)
                {
                    item[ cur_item, _i ] = "NULL";
                }
            }
          
            // search keywords and apply value to item
            for (var _command=0; _command<array_length_1d(item_keyword); _command++)
            {
                if (string_lower(_keyword) == string_lower(item_keyword[ _command ]))
                {
                    item[ cur_item, _command ] = _value;
                }
            }
        }
      
        file_text_readln( item_file );
    }

file_text_close( item_file );


return item;

Edit: attached a screenshot of how it should look if you are able to follow my exceptionally bad "guide". The background will probably be a different colour though.
 

Attachments

Last edited:
C

Chungsie

Guest
Code:
ou should look into using enums and using arrays, if your wanting more of a static inventory system like Zelda N64 and not a dynamic one like Final Fansty.

You could do something like this,

enum GEAR {
    HELMENT_BRONZE,
    HELMENT_SILVER,
    ARMOR_BRONZE,
    ARMOR_SILVER
}

// Then assign the invtory values
inventory_has[GEAR.HELMENT_BRONZE] = true;
inventory_sprite[GEAR.HELMENT_BRONZE]=spr_helment_bronze;


inventory_has[GEAR.HELMENT_SILVER] = false;
inventory_sprite[GEAR.HELMENT_SILVER]=spr_helment_bronze;

Though even better if you make a script so lets call this inventory set...
/// inventory_set(id, has, sprite)
var argID=argument0, argHAS=argument1, argSPRITE=argument2;
inventory_has[argID] = argHAS;
inventory_sprite[argID]=argSPRITE;

So know you can add the intenory like this with that script
inventory_set(GEAR.HELMENT_BRONZE, true, spr_helment_bronze);
inventory_set(GEAR.HELMENT_SILVER, false, spr_helment_silver);

inventory_set(GEAR.ARMOR_BRONZE, true, spr_armor_bronze);
inventory_set(GEAR.ARMOR_SILVER, false, spr_armor_silver);



All that's just for setting it up then you have to worry about placing all the buttons of course...
Just make a object for each button, I recommend using scripts and arguments instead of just copying each object...

But anyway you can take advantage of those enums in arrays, so like have a varible to set what helment you have

helment = GEAR.HELMENT_BRONZE;

// Draw the sprite?
if sprite_exists (inventory_sprite[helment] )
sprite_index = inventory_sprite[helment];


Lol hope this helps, it is really rough
maybe I don't need an external database file? idk really.

that is what a friend suggested... I don't know tho. it feels hard to explain to people. but it looks like a solution. I am going to force myself away from my pc for the holidays so I won't be back until monday.
 
K

Kreastricon62

Guest
I just use Data structures. They take up memory yet they are so much easier to work with. You can use a ds_list to store a list of ds_maps.

The ds_list is the list of inventory items you have, and the ds_map stores stats on your items such as its name, attack, sprite icon, encumbrance, etc.

Another nice thing about data structures is that you can save them in a .ini file, so when you load your game, you can read it using a function like ds_list_read and save them with ds_list_write.

Remember to destroy them when you are done using them.
 

geky

Member
No, you don't necessarily need to use an external file to store item information, I was only suggesting that because it would be easier to access for example if you need to make quick changes to the game without having to recompile a new executable. That method your friend suggested could work, but I prefer (where possible) to only use one array.

For your cause you would need 4 arrays: 1) to store all the items available (the database). 2) to store all the items that exists in the game / level. 3) to store your player inventory. 4) to store your player equipment.

Using your friend's suggestion, it could look something like this for the [item database] and [item exists info]:

Code:
// create collection of constants for easy access to item information through arrays
    enum ITEM_STORE
    {
        // general item information
        Name,           // string - name of item
        Stackable,      // bool - if item is stackable
        Stackmax,       // integer - how many stacks is the max
        Spriteindex,    // integer
        Description,    // string
        
        // specific for items that exists in game (ITEMS[] array)
        inInventory,    // bool - f the item is in inventory or not
        sourceID        // integer - what ID from ITEMDATA[] this item is
    }

// make test items (can read from external file and import instead)
    cur_item = 0;
    ITEMDATA[ cur_item, ITEM_STORE.Name] = "crazy hat";
    ITEMDATA[ cur_item, ITEM_STORE.Stackable ] = false;
    ITEMDATA[ cur_item, ITEM_STORE.Spriteindex ] = noone;
    ITEMDATA[ cur_item, ITEM_STORE.Description ] = "This crazy hat was once worn by an evil wizard who murdered thousands of ants every year";
    
    cur_item = 1;
    ITEMDATA[ cur_item, ITEM_STORE.Name] = "Potion";
    ITEMDATA[ cur_item, ITEM_STORE.Stackable ] = true;
    ITEMDATA[ cur_item, ITEM_STORE.Stackmax ] = 10;
    ITEMDATA[ cur_item, ITEM_STORE.Spriteindex ] = noone;
    ITEMDATA[ cur_item, ITEM_STORE.Description ] = "You smell a strong fragrance of disgustingness, why would you inspect this potion? WHY?";
    
    cur_item = 2;
    ITEMDATA[ cur_item, ITEM_STORE.Name] = "lobster";
    ITEMDATA[ cur_item, ITEM_STORE.Stackable ] = false;
    ITEMDATA[ cur_item, ITEM_STORE.Spriteindex ] = noone;
    ITEMDATA[ cur_item, ITEM_STORE.Description ] = "This lobster is still alive and kicking, you better let it go.";


// the array which holds information about all items that are spawned in the game / level
    ITEMS[ 0, 0 ] = 0; // first, create the array
    script_kill_boss( 5 ); // spawn random items

Code:
///script_kill_boss( drop_count );

// spawn N number of random items into the room
    var drop_count = argument0;
    var array_size = array_height_2d( ITEMS );

// make sure we start at pos 0 if the array is 'empty'
    if (array_size == 1) array_size = array_size -1;

// add items to game
    for (var _i=0; _i<drop_count; _i++ )
    {
        var pos = array_size+_i;
        
        // find random item from database array   
        var source_id = irandom( array_height_2d( ITEMDATA )-1 );
        
        // add this item to the game room with reference from ITEMDATA database
        ITEMS[ pos, ITEM_STORE.sourceID ]    = source_id;
        ITEMS[ pos, ITEM_STORE.Spriteindex ] = ITEMDATA[ source_id, ITEM_STORE.Spriteindex];
        ITEMS[ pos, ITEM_STORE.Name ]        = ITEMDATA[ source_id, ITEM_STORE.Name];
        ITEMS[ pos, ITEM_STORE.Stackable ]   = ITEMDATA[ source_id, ITEM_STORE.Stackable];
        ITEMS[ pos, ITEM_STORE.Description ] = ITEMDATA[ source_id, ITEM_STORE.Description];
    }
 
C

Chungsie

Guest
Equip-Menu.png so this is my equip menu. the left circle displays the player bust, and the left big blue square with the arrows displays the player facing the camera where items are drawn to display what they look like. and the box on the left displays current selected/highlighted item information.

I would like to use one of the joysticks on the game pad, or even the arrow keys to change which slot is selected on the player sprite and use either l_shift and r_shift or rbumper and lbumper to cycle through the gear in inventory for that given slot. for all purposes of the armor health system, there will be two default starting gear for each slot, so as to allow the player to reset the health values of the gear.

Player-Equip-Display_Temp.png Player-Disp-Helm-1.png both those images have the exact same resolutions, so if you center both equally, there is no need to adjust x or y values. but to show an example of how I was hoping it would work. I already have an idea for changing the color of gear, so I was thinking changing slot selection would change the color of that gear to say black or white and then return them to default drawn colors when going to the next slot.

thank you guys for the help so far. I just will have to wait until after the holidays to mess around with this more. But I thought some graphics would help everyone visualize better the system I have planned for this game.
 
Top