GML Large Inventory Design

Wardog

Member
Good Morning,

So I've currently got a functioning inventory, that will be able to read from a large database of hundreds of items. However, each item could impact a number of player stats, and I'm curious if the inventory method I'm usually seeing online using data structures and enumerators is still the most efficient method for this.

ds_items_info = ds_grid_create(16, item.height);

// Item Database (ID #)
enum item {
none = 0,
mana potion = 1,
health potion = 2,
staff = 3,
cape = 4,
wizard hat = 5,
height = 6,
}

// Item ID # - Item Name
// Item Name = 0
// Item Description = 1
// Item Base Value = 2
// Item HP Restore = 3
// Item HP Regen = 4
// Item MP Restore = 5
// Item MP Regen = 6
// Item Move Speed = 7
// Item Damage = 8
// Item Attack Speed = 9
// Item Attack Range = 10
// Item Defense = 11
// Item Heat Resist = 12
// Item Cold Resist = 13
// Item Elec Resist = 14
// Item Poison Resist = 15
// Item Vision Range = 16

This results in needing to create a very large database of items, using the structure below:

// Item ID #0 - Nothing
ds_items_info[# 0, 0] = "Nothing";
ds_items_info[# 1, 0] = "Nothing";
ds_items_info[# 2, 0] = 0;
ds_items_info[# 3, 1] = 0;
ds_items_info[# 4, 1] = 0;
ds_items_info[# 5, 1] = 0;
ds_items_info[# 6, 1] = 0;
ds_items_info[# 7, 1] = 0;
ds_items_info[# 8, 1] = 0;
ds_items_info[# 9, 1] = 0;
ds_items_info[# 10, 1] = 0;
ds_items_info[# 11, 1] = 0;
ds_items_info[# 12, 1] = 0;
ds_items_info[# 13, 1] = 0;
ds_items_info[# 14, 1] = 0;
ds_items_info[# 15, 1] = 0;
ds_items_info[# 16, 1] = 0;

// Item ID #1 - Mana Potion
ds_items_info[# 0, 1] = "Mana Potion";
ds_items_info[# 1, 1] = "You're not a wizard, Harry, the potions make you one.";
ds_items_info[# 2, 1] = 10;
ds_items_info[# 3, 1] = 0;
ds_items_info[# 4, 1] = 0;
ds_items_info[# 5, 1] = 50;
ds_items_info[# 6, 1] = 2;
ds_items_info[# 7, 1] = 0;
ds_items_info[# 8, 1] = 0;
ds_items_info[# 9, 1] = 0;
ds_items_info[# 10, 1] = 0;
ds_items_info[# 11, 1] = 0;
ds_items_info[# 12, 1] = 0;
ds_items_info[# 13, 1] = 0;
ds_items_info[# 14, 1] = 0;
ds_items_info[# 15, 1] = 0;
ds_items_info[# 16, 1] = 0;

Then, should the mana potion be consumed, it impacts the player's stats in the following code:

// Modification of Player Stats
obj_player_stats.currenthp += real(inv_info[# 3, item]);
obj_player_stats.hpregen += real(inv_info[# 4, item]);
obj_player_stats.currentmp += real(inv_info[# 5, item]);
obj_player_stats.mpregen += real(inv_info[# 6, item]);
obj_player_stats.spd += real(inv_info[# 7, item]);
obj_player_stats.damage += real(inv_info[# 8, item]);
obj_player_stats.atkspeed += real(inv_info[# 9, item]);
obj_player_stats.atkrange += real(inv_info[# 10, item]);
obj_player_stats.defense += real(inv_info[# 11, item]);
obj_player_stats.heatresist += real(inv_info[# 12, item]);
obj_player_stats.coldresist += real(inv_info[# 13, item]);
obj_player_stats.elecresist += real(inv_info[# 14, item]);
obj_player_stats.poisonresist += real(inv_info[# 15, item]);
obj_player_stats.visionrange += real(inv_info[# 16, item]);

As you can see from the code, the game modifies the player's current stats by checking every single possible stat of the item consumed, resulting in hundreds of lines of code where for some items, the game will check for a stat with a "0" value.

As such, I'm curious if the Mana Potion in the example above could be written as such:

// Item ID #1 - Mana Potion
ds_items_info[# 0, 1] = "Mana Potion";
ds_items_info[# 1, 1] = "You're not a wizard, Harry, the potions make you one.";
ds_items_info[# 2, 1] = 10;
ds_items_info[# 5, 1] = 50;
ds_items_info[# 6, 1] = 2;

Or, if the original method is the proper, most efficient way of doing this (performance-wise, I can understand needing coding to take longer to result in more efficient game performance), and I should press on with what I have.
 

NightFrost

Member
Well, DS performance only comes to play in practise when you're hitting it many times per step, and item data doesn't sound like something that's under such intense use (though I don't know how abolutely massive DSes degrade in performance). Likewise it wouldn't help to check if value is not zero and only then use it, as in if(grid cell is not zero) add grid cell to variable because the check needs to read the DS anyway. Just adding everything would be tiny bit faster. You could skip zeroes when you define parametes, but then the grid cells will just be at whatever value you cleared the grid with when you set it up - they still exist even if you're not touching them.

If memory usage is a concern, then you'd define each item separately as a ds map instead, where each parameter the item uses is a key on the map, and your master list of items would just be a ds list that contains ds map pointer to each item enumerator. But zeroes don't eat a lot of memory so that wouldn't be worth the minimal gains I think.

Overall, I wouldn't worry about an inventory, performance-wise. Graphic routines are likely to be the ones that eat the most at your game's framerate.
 

Hyomoto

Member
To add a little to what @NightFrost has said, when it comes to performance there is one important rule to follow: ignore "which is more efficient" or "which is faster", what you want to laser-focus on without interruption is how many times do I need to do this. I can write you a bulky, mammoth page of code and as long as I only need to run it once when the room starts, I probably have optimized it as well as I need to. When it comes to inventory performance, almost any data structure is going to be fine as long as you don't need to read from, and write to it constantly. If you do need to do that, then you should reduce the amount of searching in that database you do by caching results. If you absolutely must always search the database, okay: now maybe the type of data structure will come into play.

As for "how do I get the data I want into a form I can use?" the answer is a bit simple: you have the base of it. You have to store those values in a format that you, the programmer, find useful. You could simplify things, such as writing yourself a script that allows you to pass all the variables on a single line:
Code:
add_new_potion( "Mana Potion", "You're not a wizard, Harry, the potions make you one.", 10, 50, 2 );
But really, if you need the data, want the data, and must have the data, you have to store it somewhere and access it somehow. You can always further simplify things for yourself, and abstract these concepts out further and further. Often you can trade memory for performance, or vice versa. In my case, I wrote a database loader that imports the data from external files, and can handle templates, static values and overrides. These are features I found desirable; however, just as I described above, it's just a way for me to store values in a format that I find useful.

You are correct, your database is extremely wasteful for any object that doesn't use a value. But at the same time, any object can have that value. So there's some flexibility there. This is one hell of a rabbit hole, so it's a bit hard to give you a definitive answer on the topic, but hopefully this post contains something you'll find useful.
 

Wardog

Member
Thank you both for the replies, the additional perspective definitely helps with progress.

It sounds like if I have even 25-50 parameters in each item won't bog down the game, since the game will only read those lines when called to do so.

As such, it actually benefits me to code a few unused parameter lines into each item and the player stat object, in case I add additional features later.
 

TheouAegis

Member
Depending on your game, you really don't even need every attribute for every item in your database. Most items will only have 1, 2, or 3 attributes.
 

Wardog

Member
Depending on your game, you really don't even need every attribute for every item in your database. Most items will only have 1, 2, or 3 attributes.
Actually just logged back in to comment on that after testing it out. I currently have the player_stats object reading/checking for 50 hypothetical variables on item consumption, and for items that don't have all of those values defined, it doesn't cause any issues.

Example:

// Item ID #1 - Health Potion
ds_items_info[# 0, 1] = "Health Potion";
ds_items_info[# 1, 1] = "Restores HP";
ds_items_info[# 24, 1] = 10; // HP Restore
ds_items_info[# 37, 1] = 2; // HP Regen

obj_player_stats.currenthp += real(inv_info[# 3, item]);
obj_player_stats.hpregen += real(inv_info[# 4, item]);
obj_player_stats.currentmp += real(inv_info[# 5, item]);
.....all the way to.....
obj_player_stats.undecided += real(inv_info[# 50, item]);

In short, I can make the item database as short as it needs to be for each item, while the player object can read as many hypothetical variables as exist in the game.
 
Last edited:
Top