ID:2376067
 
(See the best response by FKI.)
So I'm trying to get back into the swing of things after a long absence, and in a new little project I'm working on I am trying to create an inventory system where some equipment takes up more than one space. Much like Diablo II, Path of Exile, Adventures of Van Helsing and so on have done... But I am a bit stumped on the best approach.

I've done plenty of slotted inventories, but single slot consumption is a lot easier since its just a little looping and some lists then a few screen locs and you're set.

In this one I'm using 45 slots spread over a 9 by 5 32x32 slotted inventory. I've considered making each one a variable, and going over them but that seems messy. I'm also interested in drag and drop rearranging which further complicates it. I could try a list for each row or column but then they all interact too much in drag and drop.

Anyone got some ideas that might help me get started in the right direction?

Don't all you have to do is handle item stacking procedures upon item pickup -- e.g. if item A is not stackable, then immediately move it to the player's inventory list, otherwise add its quantity to any existing items of the same type if applicable -- then go through the player's inventory list and plot the items on the screen?
For item stacking, yes. But for what I am looking to do you would have cases like for example... A sword might take up three spaces vertically on screen, an armor might take up a 2x2 square (4 32x32 boxes), a potion only one space, and so on.
Best response
Ah.

I wrote a rough idea of what came to mind for this. Disclaimer: This is a personal first and written off-top. At best, I would use this to get an idea of how to approach it yourself, as there is much room for improvement.

mob
var/tmp/bag/bag

proc/grab_item(obj/item/i)
if(!bag) bag = new
bag.add(i)


obj/item
var/tmp/bag_x = 0
var/tmp/bag_y = 0
var/tmp/bag_req_width = 1
var/tmp/bag_req_height = 1

Click()
if(!on_can_grab(usr)) return
usr.grab_item(src)

proc/on_can_grab(mob/user)
return 1


#define INVENTORY_WIDTH 9
#define INVENTORY_HEIGHT 5

bag
var/tmp/inventory[]

New()
inventory = new/list(9, 5)

proc/get_space(start_x, start_y, width, height)
var/end_x = start_x + width
var/end_y = start_y + height
// flop if the box size extends past set boundaries.
if(end_x > INVENTORY_WIDTH || end_y > INVENTORY_HEIGHT) return
. = list()
for(var/y = start_y; y <= end_y; y++)
for(var/x = start_x; x <= end_x; x++)
. += "x=[x]&y=[y]"

proc/add(obj/item/item)
. = has_open_slot()
if(.)
. = params2list(.)
var/slot_x = .["x"]
var/slot_y = .["y"]

// check that we have enough space
var/req_width = item.bag_req_width
var/req_height = item.bag_req_height
if(!has_open_space(slot_x, slot_y, req_width, req_height)) return

// successful item grab... do stuff.
item.bag_x = slot_x
item.bag_y = slot_y
inventory[slot_x][slot_y] = item


. = (.) ? TRUE : FALSE

proc/has_open_space(start_x, start_y, width, height)
if(!has_open_slot(start_x, start_y)) return FALSE

var/x = 0
var/y = 0
var/s[] = get_space(start_x, start_y, width, height)
if(s?:len)
for(var/params in s)
var/l[] = params2list(params)
x = l["x"]
y = l["y"]
// flop if this tile/bag space is linked to an item already.
if(!inventory[x][y]) return FALSE

proc/has_open_slot(x, y)
if(x || y) return (!inventory[x][y]) ? TRUE : FALSE

for(var/xloc = 1; xloc <= INVENTORY_WIDTH; xloc++)
for(var/yloc = INVENTORY_HEIGHT; yloc > 0; yloc--)
if(!inventory[xloc][yloc])
return "x=[xloc]&y=[yloc]"

proc/get_slot(x, y)
ASSERT(x && y)
return inventory?:[x][y]


I didn't jump into any drag/drop stuff, but I imagine that part would be simple once you decide on your core.

It's been a minute so maybe you've found some clarity by now (do share if so). This seems to be mostly a question of approach though, so while one side of me would say there is no "right" answer, the other side would suggest the "right" answer is what works for you now and going forward.
Well it'll definitely take some trial and error. I'm working on fixing a bad index runtime error in has_open_slots and working out a display before diving into improvement and ironing it out. Solid start point though, which is what I needed; so thank you!

Once I get everything set up right I'll probably post up the final version to help anyone else that attempts this along the way.