ID:2063388
 
(See the best response by Ter13.)
Code:
proc/addItem(var/mob/receiver, var/itemType, var/itemName, var/amountToGive = 1)
if(!receiver || !itemName || !itemType) return 0
var/path = "/obj/Item/"
path += "[itemType]/" //currently only necessary because of subclasses
path += itemName
path = text2path(path)
if(path in typesof(/obj/Item))
for(var/i = 0; i<amountToGive; i++)
if(length(receiver.inventory))//This is for grouping. Rather than creating a whole new obj, just increment the existing one
for(var/obj/Item/item in receiver.inventory)
if(istype(item,path))
item.amount ++
break
else
new path(receiver)
var/itemGetMsg = "Obtained [amountToGive] [itemName]"
if(amountToGive > 1) itemGetMsg += "s"
receiver << itemGetMsg + "!"
return 1
receiver << "Item '[itemName]' Not Found."
return 0


Problem description:

The above code WORKS, however the system doesn't work the way I actually want it to. Essentially I'm trying to be able to create item objects by name with that proc in a plug-and-play manner (i.e addItem(player, "Sword", 3)). What's getting in my way is that obj/Item has subclasses, and I'm not sure how I would be able to play around the type paths to accommodate that. A workaround would be to just make every item directly under obj/Item but that seems like a cheap bandaid to me, and I like what class hierarchy affords me in the way of exclusive variables, etc.
Hmmm that's not a bad idea. So then would the getItems() proc just return a list of every item and then I would just use Find() or something in my addItem proc?

EDIT: Oh didn't see the edit
For some reason nothing is being added to my world_items list. I even put a little piece of test code that would output the name of each item as it's added so I can see if they are and nothing is going into it
Best response
I've actually been working on this exact thing!

Alright, the trick here is going to be using initial() and datum initialization.

var
list/items
item_manager/item_manager = new/item_manager()

item_manager
New()
items = list() //initialize the items list
var/list/types = typesof(/obj/item) //get all subtypes of /obj/item
var/obj/item/i
var/id
for(var/v in types)
i = v //cast the prototype into the typecast variable
id = initial(i.id) //grab the prototype's default id
if(id)
items[id] = v //associate the id with the type

obj
item
var
id //a unique string per item subtype


Now let's set up item stacking.

obj
item
var
stack = 1
max_stack = 1
proc
Clone() //useful override for duplicating a type of item
var/obj/item/i = new type()
i.id = id
return i

isSame(obj/item/i) //useful override for checking if items are the same
return i.type==type&&i.id==id


The gist of a stacking algorithm:

Terminology:

CONTAINER: The list you are attempting to add ITEM to.
ITEM: The item you are attempting to add to CONTAINER.
NUMBER: The number of ITEMs you want to add to CONTAINER.

if(ITEM.max_stack>1)
var/chg
//attempt to stack on any existing items in the container that match
for(var/obj/item/foundstack in CONTAINER)
if(isSame(foundstack))
chg = min(NUMBER,foundstack.max_stack-foundstack.stack) //make sure we don't overstack
if(chg)
NUMBER -= chg
foundstack.stack += chg
if(!NUMBER)
return //early ejection
//handle any leftover stacks that have to be added to the container
var/stacks = ceil(NUMBER/ITEM.max_stack)
var/obj/item/newstack
for(var/count in 2 to stacks)
newstack = ITEM.Clone()
newstack.stack = ITEM.max_stack
CONTAINER += newstack
NUMBER -= ITEM.max_stack
ITEM.stack = NUMBER
CONTAINER += ITEM


Anyway, the point is that every unique breed of item should be associated to an ID. If you want to add an item to a container:

proc
AddItem(list/container,obj/item/i,stack)
if(!i)
return 0
if(istype(i)) //handle objects passed into the function
i = i //does nothing, but this is an early-eject case. Usually you shouldn't do this.
else if(ispath(i)) //handle paths passed into the function
i = new i()
else if(istext(i)) //handle id strings passed into the function
i = items[id]
i = new i()
else if(isnum(i)) //handle numbers passed into the function
i = items[items[id]]
i = new i()
stack = max(floor(stack),0)
if(!stack) stack = i.stack||1

var/added = 0
if(i.max_stack>1)
var/chg
for(var/obj/item/foundstack in container)
if(i.isSame(foundstack))
chg = min(stack,foundstack.max_stack-foundstack.stack)
if(chg)
stack -= chg
foundstack.stack += chg
added += chg
if(!stack)
return added //early ejection
var/stacks = ceil(stack/i.max_stack)
var/obj/item/newstack
for(var/count in 2 to stacks)
newstack = i.Clone()
newstack.stack = i.max_stack
CONTAINER += newstack
stack -= i.max_stack
i.stack = stack
container += i
return added //exit


And for setting up your items:

obj/item
sword
id = "sword"
shield
id = "shield"
category
item_in_category
id = "notcategory"


Just make sure every item's id is set to a unique string and you are golden. Any item that has a null id will not be added to the item database, so you can have subtype filters if you want without any problems.

If you change the values that can differentiate whether an item will stack with another, you should override Clone() and isSame().

obj
item
wand
var
charges = 0

isSame(obj/item/wand/w)
//fast approach
return w.type==type&&w.id==id&&w.charges==charges
/* polymorphic approach:
return ..()&&w.charges==charges*/


Clone()
//fast approach
var/obj/item/wand/w = new type()
w.id = id
w.charges = charges
return w
/* polymorphic approach:
var/obj/item/wand/w = ..()
w.charges = charges
return w */


Notice how I showed a fast/polymorphic approach? That's because invocation overhead makes the polymorphic approach much slower than the fast approach. The polymorphic approach is cleaner though, because you don't have to change as much code if you change the parent type's structure or behavior later on. You touch one function and all descendants are aware of the change. I included both approaches because there are tradeoffs to both and you should be aware of what I'm locking you to.

Anyway, just checked the thread, and Yut beat me to it. Sorry.
This... is a lot to digest lol. I more or less understand the code, I just need to dumb it down for my purposes. For starters, I don't need to be able to pass in anything other than simply item names and how many of that item to grant, and the stacking definitely doesn't need to be complex-- if that item is already in the inventory, increment its "amount" variable rather than wasting cpu creating a new obj. If they don't already have that item, make a new one.
Ok so after essentially re-writing Ter13's code from the ground up (with my own style to understand it better) I was able to get everything working as intended :) Decided to keep the stacking system with leftover stacks as well as I remembered I WILL need that for certain items. Thanks for the help guys!