# GM:S 1.4 need inventory help

Discussion in 'Programming' started by woods, Jun 30, 2019.

1. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
so i am working on a little farming sim... and have ran into an area that i am completely unfamiliar with... inventory... i have a row of ten 32x32 "empty" slots drawn at the bottom of the screen for the hotbar (going to keybind 1-0)

and i have my backpack

ive also made a handful of tools to use.. pick,axe,shovel,hoe,watercan, etc... 32x32 icons

my question is how do i make them able to be placed in the backpack and activated on the hotbar to be used in the world?

i know i need to make use of arrays.. but this is a brand new area for me.. and some assistance would greatly be appreciated ;o)

File size:
1.1 KB
Views:
1
File size:
26.9 KB
Views:
3
2. ### the_dude_abidesMember

Joined:
Jun 23, 2016
Posts:
629
I haven't made an inventory (and am not all that with GMS...), so this most likely isn't the best way, but it's how I'd start.

Your situation sounds fairly specific - 10 items, 10 keys to bind to them. So you could have variables for whether the item has been picked up, and set them to false to begin with.

create event:
Code:
Has_pickaxe = false;
Has_shovel = false;
etc
In a collision event with the object (if picked up in the environment), or maybe bought from a shop etc, set the appropriate variable to true.

With the keys: (pseudo code)
Code:
if key is pressed (whatever)
{
if Has_whatever_object
{
can use whatever object
}
}
Draw event for the inventory :
Code:
if Has_pickaxe
{draw whatever}
etc
Or you could do it as an array, and so remove the need for variables, by doing this instead (if the numbers for the objects remain fixed):

Make an array (I call it "array" throughout this example) that is the same length in number as there are objects, and do each position as false.

Create event:
Code:
is_object = undefined;
Collision with object, or is purchased:
Code:
set its array position to true
object is dropped, or sold, or whatever:
Code:
set its array position to false
within a step event:

Code:
var is_key =  keyboard_check_released (vk_anykey); // check if any key was released
if is_key
{var key_result = keyboard_lastchar;
var result = string_length(string_digits(key_result)); // is key_result a number? by removing anything that is not a digit you should get a string length of either 1 or 0
if result != 0 // key_result (the last key pressed) was a number
{var real_num = real(key_result);
var position_value = array[ real_num]
if position_value == true
{
is_object =  real_num
}
}
else
{
// key pressed was not a number - do whatever here, if you have functions for letter keys being pressed (using key_result as the variable to find the value of)
}
}

if is_object != undefined
{switch (is_object)
{
case 0:
if array[is_object]
{
can use pickaxe
}
else
{
//has dropped it, or sold it, so:
is_object = undefined;
};
break;
case 1:
if array[is_object]
{
can use shovel
}
else
{
//has dropped it, or sold it, so:
is_object = undefined;
};
break;
etc
}
}
Draw event for the inventory :
Code:
// loop through array, and get value of position
if array value == true
{
switch (array position)
{
case 0: draw pickaxe in slot; break;
case 1: draw shovel in slot; break;
etc
}
}
I think that would work when used with fixed outcomes, such as each object being assigned to a particular number on the keyboard. But, if the keys can be rebound, then this isn't flexible at all.

Last edited: Jun 30, 2019
3. ### BentleyMember

Joined:
Jun 18, 2017
Posts:
802
A simple idea
Code:
width = 10;
height = 20;
backpack = ds_grid_create(width, height);

// Add item to first available spot
var found = false;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++)
{
if (backpack[# i, j] == -1)
{
backpack[# i, j] = "Potion";
found = true;
break;
}
}
if (found)
{
break;
}
}

Last edited: Jun 30, 2019
4. ### Kasra_nMember

Joined:
Jun 19, 2019
Posts:
26
Hi there
in this case we usually use coordinators, Something like idea bellow:

Imagine you choose your item and your item x and y is same as mouse x and mouse y. First you need to define your items for the machine, for example shovel is 1 pickaxe is 2 and etc ...
So
Code:
//Create Event
//we have an inventory 8×8
For(var i = 0; i < 8; i++)
{
// initializing adjacency matrice with free slots (zero means no item)
}
//step event
If mouse_check_button_released(mb_left)
{
var xoff, yoff;
xoff = rx_to_vx(mouse_x);
yoff = ry_to_vy(mouse_y);
inventory_adjacency[xoff, yoff] = pi;
\\pi is picket item id as we described
}
//rx to vx (real x to virtual x)
var module = 32; //inventory icon size
var rx = argument[0];
rx = rx / module;
rx = rx - frac(rx);

Return rx;
In draw event you can make a 8×8 nested loop and then define another coordinator to convert array x to real x and draw the properiate sprite depends to the array current home value(usually using sprite index)

5. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
thanks for the responses guys.. will deffinately set me on the right track ;o)

ran across this tutorial the other day...

i think i need some one on one help.... babysteps to understand what goes where...
i made it thru spoiler2 where he says to run the game and see some visual results..... and got a couple different errors.
im not 100% sure where to put some of this code to make it work.

when i click start in my first room to goto the actual game i get this error..

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_inventory_control_2:

global variable name 'inventory' index (100003) not set before reading it.
at gml_Object_obj_inventory_control_2_CreateEvent_1 (line 4) - while (slot < ds_grid_width(global.inventory))
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_inventory_control_2_CreateEvent_1 (line 4)

here is the code for that control object..
Code:
//Get values
var iid = global.inventory[# var_slot, 0];
var amount = global.inventory[# var_slot, 1];
var name = global.item_index[# iid, item_stat.name];
var description = global.item_index[# iid, item_stat.description];

//Draw stuff
if (iid != item.none)
{
draw_sprite(spr_item, iid, x+160, y+288); //Draw item sprite
draw_text(x+160, y+292, string(amount)); //Draw item quantity
}

even if i put my controller in the starting room, i still get the same error..

if someone feels upto walking me thru this a bit, i would really appreciate it ;o)

6. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
maybe ive bitten off more than i can chew... before trying to make an inventory i need to learn more about loops and such

i think ill put this on standby for a while

thanks for the assist ;o)

RefresherTowel likes this.
7. ### FabsevenMember

Joined:
Oct 7, 2016
Posts:
350
You better use loops and a 2d array or ds_map (i think ds map can be ordered in a more easier way but array are faster)

let's say you have a global variable bdd_items with the items existing in the game (all of them)
You can initialize this bdd with a json file or ini file or manually,

first create macro to make the code more readable :
OBJ_ID = 0
OBJ_NAME = 1
OBJ_FAMILLY = 2
OBJ_MAXSTORAGE = 3
OBJ_SPRITE = 4
OBJ_FEATURE = 5
OBJ_FEATURE_T1 = 6
OBJ_FEATURE_T2 = 7
OBJ_FEATURE_T3 = 8
OBJ_FEATURE_V1 = 9
OBJ_FEATURE_V2 = 10
OBJ_FEATURE_V3 = 11

script bdd_initialize_items
Code:

//Little red potion , giving 50hp when consumed , can have up to 99 in inventory
global.bdd_items[0,OBJ_ID] = 0
global.bdd_items[0,OBJ_NAME] = " Little red potion"
global.bdd_items[0,OBJ_FAMILLY] = "Healing"
global.bdd_items[0,OBJ_MAXSTORAGE] = 99
global.bdd_items[0,OBJ_SPRITE] = sprite_little_red_potion
global.bdd_items[0,OBJ_FEATURE] = "HEAL_SELF"
global.bdd_items[0,OBJ_FEATURE_T1] = "HEAL_SELF_HP"
global.bdd_items[0,OBJ_FEATURE_T2] = ""
global.bdd_items[0,OBJ_FEATURE_T3] = ""
global.bdd_items[0,OBJ_FEATURE_V1] = 50
global.bdd_items[0,OBJ_FEATURE_V2] = 0
global.bdd_items[0,OBJ_FEATURE_V3] = 0

//Silk armor, giving 10hp and 5def
global.bdd_items[0,OBJ_ID] = 100
global.bdd_items[0,OBJ_NAME] = "Silk Armor"
global.bdd_items[0,OBJ_FAMILLY] = "Armor"
global.bdd_items[0,OBJ_MAXSTORAGE] = 1
global.bdd_items[0,OBJ_SPRITE] = sprite_little_armor
global.bdd_items[0,OBJ_FEATURE] = "ARMOR"
global.bdd_items[0,OBJ_FEATURE_T1] = "STAT_HP"
global.bdd_items[0,OBJ_FEATURE_T2] = "STAT_DEF"
global.bdd_items[0,OBJ_FEATURE_T3] = ""
global.bdd_items[0,OBJ_FEATURE_V1] = 10
global.bdd_items[0,OBJ_FEATURE_V2] = 5
global.bdd_items[0,OBJ_FEATURE_V3] = 0


Once you have this database, initialize your inventory
have some additional macro

INV_BDD_ID = 0
INV_QTE = 1
INV_BDD_SLOT = 2

script initialize_inventory
Code:
for(i=0;i<30;i++)
{
global.inventory[i,INV_BDD_ID] = noone
global.inventory[i,INV_QTE] = 0
global.inventory[i,INV_BDD_SLOT] = noone
}


If you want to take and item
Code:
var item_id_to_add = argument0
var item_qte_to_add = argument1
var in_inventory = false
var slot_in_inv = noone
var first_empty_slot = noone

for(i=0;i<30;i++) //looking for the item, if already exist in inv, add qte if possible (in founded slot)
{
if( global.inventory[i,INV_BDD_ID] == item_id_to_add)
{
in_inventory = true
slot_in_inv = i
}
if(first_empty_slot == noone and  global.inventory[i,INV_BDD_ID] == noone)
{
first_empty_slot  = i //first empty slot in inventory
}

}

if( in_inventory)
{
var max_qte = global.bdd_items[ global.inventory[i,INV_BDD_SLOT]
if  global.inventory[slot_in_inv,INV_QTE]  > max_qte //ajust to max qte if >
{
global.inventory[slot_in_inv,INV_QTE]  = max_qte
}
}
else
{
global.inventory[ first_empty_slot ,INV_BDD_ID] = item_id_to_add
global.inventory[ first_empty_slot ,INV_QTE] = item_qte_to_add

}


in order to draw you have to loops and global.inventory and if [i,INV_BDD_ID] != noone draw the sprite + qte + name

It's not perfect but it might give you a good idea of how to make it with loops.
Didnot test it, just writed it in one shot, good luck x)

8. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
appreciate all the help..

going along @Fabseven system here.. ive ran into a couple snags..

i have 2 items in my inventory system so far.. a hoe and a watercan..
when i pick up the second item (doesnt matter which one i grab first) i get a fatal error..

Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of  Step Eventobj_player
for object obj_tool:

DoAdd :1: undefined value
at gml_Script_add_item_to_inventory (line 23) -    global.inventory[slot_in_inv,INV_QTE] += item_qte_to_add
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
called from - gml_Object_obj_tool_CollisionEvent_6_1 (line 1) - script_execute(add_item_to_inventory);


i understand the error.. undefined value but dont know how to fix it.

also can you give me a lilo more from your post above on how to draw.. im pretty dense sometimes ;o)

"in order to draw you have to loops and global.inventory and if [i,INV_BDD_ID] != noone draw the sprite + qte + name"

9. ### chamaeleonMember

Joined:
Jun 21, 2016
Posts:
976
Is the current error due to calling script_execute() with your script without providing parameters, hence leading to argument0 and argument1 not being defined (and therefore item_id_to_add and item_qte_to_add being undefined as well)?

Side note edit: Why use script_execute() when add_item_to_inventory(<parameters>) will do?

10. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
as you can tell, this is a bit out of my league ;o) im trying to dissect the code to see how it works.. i dont really understand the most of it.

......

ok i see how this works now..
in the collision event with object with player..
add_item_to_inventory(10,1) //10 being the obj_IDfor the hoe and 1 is QTY

and i wouod use the obj_ID 12 for the watercan

testrun and that fixed the error ;o)

still im not understanding teh how to draw the inventory items into my backpack when i pick them up

11. ### FabsevenMember

Joined:
Oct 7, 2016
Posts:
350
Hello again,
In order to draw the inventory you just have to loop in the inventory and draw, for optimize purpose you should first calcultate cells positions in a create event (in order to calcultate only one time)

in create event of obj_hero or obj_system :
Code:

//define main windows
gui_draw_inv_www = 500
gui_draw_inv_hhh = 500
gui_draw_x1 = display_get_gui_width()/2 - gui_draw_inv_www/2
gui_draw_y1 = display_get_gui_height()/2 - gui_draw_inv_hhh/2
gui_draw_x2 = gui_draw_x1 + gui_draw_inv_www
gui_draw_y2 = gui_draw_y1 + gui_draw_inv_hhh
gui_draw_bkcolor = c_white
gui_draw_bkalpha=0.5
gui_draw_ftcolor=c_black
gui_draw_ftalpha=1

startx = gui_draw_x1 +10
starty = gui_draw_y1 + 10
cell_www = 30
cell_hhh = 30
stepx = cell_www +5
stepy = cell_hhh + 5

maxinv = 30 //30 = size of global.inventory, you should use a fonction there, something like 1d_array_get_height() - cannot remember the exact function

for(i=0;i<maxinv;i++)
{
idraw[i,0] = startx //x1 of cell
idraw[i,1] = starty //y1
idraw[i,2] = startx + cell_www //x2 of cell
idraw[i,3] = starty + cell_hhh //y2
idraw[i,4] = startx + cell_www/2 //middlex of cell
idraw[i,5] = starty + cell_hhh/2 //middley of cell
idraw[i,6] = startx + cell_www //xlegend
idraw[i,7] = starty - 10 //ylegend
idraw[i,8] = choose(c_white,c_yellow,c_gray) //cell bkcolor random for fun

startx += stepx
if(startx >= gui_draw_x2) //if your x point is larger than windows then start a new line
{
startx = gui_draw_x1 +10
starty += stepy
}

}


in draw gui event of whatever obj you want
Code:
maxinv = 30

if( 1 == 1 ) //you can set a condition there if you want
{
//draw the windows
draw_set_color(gui_draw_bkcolor)
draw_set_alpha(gui_draw_bkalpha)
draw_rectangle(gui_draw_x1,gui_draw_y1,gui_draw_x2,gui_draw_y2,false) //read doc to know what does false, make it true if you want
draw_set_alpha(gui_draw_ftalpha)
draw_set_color(c_red) //title in red for fun
draw_text( gui_draw_x1 ,    gui_draw_y1,"Inventory")

//draw cells
for(i=0;i<maxinv;i++)
{

draw_set_color(idraw[i,8] )
draw_rectangle( idraw[i,0],idraw[i,1] ,idraw[i,2],idraw[i,3] , false)

}
}


with this you have a grid with rectangles x)
all you have to do know is to add some code to draw the actual sprite+name+qte when you are in the cell (in draw cells loop)
time is up for me i have to work but try this already

12. ### SabnockMember

Joined:
Jul 21, 2016
Posts:
311
i would have thought that this is what ds_list() / ds_grid() and their associated functions would be perfect for.

13. ### FabsevenMember

Joined:
Oct 7, 2016
Posts:
350
People says Ds grid and list are slow but i agree you can make an better inventory with a ds_grid.

14. ### SabnockMember

Joined:
Jul 21, 2016
Posts:
311
the speed difference between an array and ds_grid would be negligible compared to the benefits of the of the ds_ functions i would have thought.

15. ### RefresherTowelMember

Joined:
Jul 13, 2016
Posts:
1,212
"Premature optimization is the root of all evil (or at least most of it) in programming."

16. ### Simon GustMember

Joined:
Nov 15, 2016
Posts:
3,182
I personally think using ds grids as inventory is a waste. I don't see any real benefits of having a second dimension to an inventory.
It just makes it more complicated if anything.

My inventory system makes good use of gm objects (which are my items) and an 1D array as the inventory.
The hotbar in this case is just the unextened version of the inventory.

To get the grid-like ordering of inventory cells you can just use math.
Example of drawing inventory (pseudo code)
Code:
var size = array_length_1d(inventory);

for (var n = 0; n < size; n++)
{
var cell_x = base_x + (n mod inventory_width) * interval_x;
var cell_y = base_y + (n div inventory_width) * interval_y;

draw_sprite(spr_inventory_cell, 0, cell_x, cell_y);

var cell_entry = inventory[n];
with (cell_entry)
{
draw_sprite(sprite_index, image_index, cell_x, cell_y);
}
}

Now, in the OP's version, the inventory also holds the values for how many items there are in a cell and some other info.
I don't like this either, because it is susceptible to bugs, as you are forced to change values in multiple places as if you had the object as items variant, you wouldn't have to do anything.
The logic for the items and inventory are almost entirely seperated.

I assume your inventory is a mixture of everyones inputs at this point.
It's probably best to start over, think which tutorial you like the most or is easiest for you and serves it's purpose rather than glueing some random blocks of code together and hoping it works.

If your tutorial does not cover all functionallity, you have already lost, as you are forced to use and extend code you are unfamiliar with.
If you didn't use a tutorial, I didn't say anything.

woods and RefresherTowel like this.
17. ### SabnockMember

Joined:
Jul 21, 2016
Posts:
311
This is a valid comment and goes to show how wonderfully diverse coding can be

Joined:
Oct 7, 2016
Posts:
350
19. ### FabsevenMember

Joined:
Oct 7, 2016
Posts:
350
Corrected version of obj_system + you have to draw in the middle or resize font or you will not see number 2 digits

Code:
Information about object: obj_system
Sprite:
Solid: false
Visible: true
Depth: 0
Persistent: false
Parent:
Children:
No Physics Object
Create Event:
execute code:

bdd_initialize_items()
initialize_inventory()

show = false
//define main windows
gui_draw_inv_www = 500
gui_draw_inv_hhh = 500
gui_draw_x1 = display_get_gui_width()/2 - gui_draw_inv_www/2
gui_draw_y1 = display_get_gui_height()/2 - gui_draw_inv_hhh/2
gui_draw_x2 = gui_draw_x1 + gui_draw_inv_www
gui_draw_y2 = gui_draw_y1 + gui_draw_inv_hhh
gui_draw_bkcolor = c_white
gui_draw_bkalpha=0.5
gui_draw_ftcolor=c_black
gui_draw_ftalpha=1

startx = gui_draw_x1 +10
starty = gui_draw_y1 + 10
cell_www = 40
cell_hhh = 40
stepx = cell_www +5
stepy = cell_hhh + 5

maxinv = 30 //30 = size of global.inventory, you should use a fonction there, something like 1d_array_get_height() - cannot remember the exact function

//Define items
for(i=0;i<maxinv;i++)
{
idraw[i,0] = startx //x1 of cell
idraw[i,1] = starty //y1
idraw[i,2] = startx + cell_www //x2 of cell
idraw[i,3] = starty + cell_hhh //y2
idraw[i,4] = startx + cell_www/2 //middlex of cell
idraw[i,5] = starty + cell_hhh/2 //middley of cell
idraw[i,6] = startx + cell_www //xlegend
idraw[i,7] = starty - 10 //ylegend
idraw[i,8] = choose(c_white,c_yellow,c_gray) //cell bkcolor random for fun

startx += stepx
if(startx >= gui_draw_x2) //if your x point is larger than windows then start a new line
{
startx = gui_draw_x1 +10
starty += stepy
}

}

Draw GUI Event:
execute code:

///draw inv
//maxinv = 30

if( show == true ) //you can set a condition there if you want
{
//draw the windows
draw_set_color(gui_draw_bkcolor)
draw_set_alpha(gui_draw_bkalpha)
draw_rectangle(gui_draw_x1,gui_draw_y1,gui_draw_x2,gui_draw_y2,false) //read doc to know what does false, make it true if you want
draw_set_alpha(gui_draw_ftalpha)
draw_set_color(c_red) //title in red for fun
draw_text( gui_draw_x1 ,    gui_draw_y1,"Inventory")

//draw cells
for(i=0;i<maxinv;i++)
{
//cell
draw_set_color(idraw[i,8] )
draw_rectangle( idraw[i,0],idraw[i,1] ,idraw[i,2],idraw[i,3] , false)

//obj if exists
if( global.inventory[i,INV_BDD_ID] != noone)
{
obj_id     = global.inventory[i,INV_BDD_ID]
obj_slot   = obj_id_to_bdd_slot(obj_id)
//show_debug_message("obj_slot =" + string(obj_slot))
if(obj_slot != noone)
{
obj_sprite = global.bdd_items[obj_slot,OBJ_SPRITE]
obj_name   = "test" //global.bdd_items[obj_slot,OBJ_NAME]
obj_nbr    = global.inventory[i,INV_QTE]

draw_sprite( obj_sprite,0 ,idraw[i,4],idraw[i,5])
draw_set_color(c_black)
draw_text(idraw[i,0],idraw[i,5],"x" + string(obj_nbr))
}
}

}
}

execute code:

///text
draw_text(10,10,"CTRL to toggle inventory")
draw_text(10,20,"+ To add potions")

Key Press Event for <Ctrl> Key:
execute code:

show = !show

Key Press Event for Keypad + Key:
execute code:


press CTRL and you have this :

Press + multiple times and number of potion will increase

20. ### woodsMember

Joined:
Jun 21, 2016
Posts:
223
sorry for the late response.. been dealing with some RL stuffs for the past week or so.. regardless, thank you all for the input.. its gonna take me a bit to chew this up, and make it all fit into my head ;o) i dont like copy paste code.. we dont learn that way. i appreciate the explanations and details everyone here put into their responses.

"I assume your inventory is a mixture of everyones inputs at this point."

ive taken a hard look at everything ive been presented with, and have come to the conclusion that i have a long way to go to become proficient with anything other than super basic stuff.. at least i know i dont know and am not afraid to say it heheheh.

when i started this project, i was already headed in the direction that Bentley is going, but i realized things arent going to be moveable like i wanted.. so i think im going to go with @Fabseven's advice.. for some reason it seems to be sticking better for me.

again thanks for the help fellas ;o)