Inventory System, psudocode?

Blitz3D Forums/Blitz3D Programming/Inventory System, psudocode?

i am looking for pseudocode or code example.

i cant figure out how to create an inventory system for an RPG Style test. My intention is to get some ideas to make it work.

what i wanto to achieve is the following:

1. the character clicks on an it that is on the ground (gold, charm, weapon, etc, any)

2. the items goes to the "Inventory System" (a backpack or a )

3. the item dimension is 1 space, the inventory (the backpack) has 32 spaces

how to display the items in the inventory sorted inside the backpack? maybe this is the more difficult situation for the Inventory System.

thanks for any idea.

It's something that surely lurks in the codearchives, but since there's no search...Here i repost mordy's inventory system:

; MORDYSLOTS
; Baldur's Gate style inventory lib for Blitz Basic
; written by morduun / morduun@... / 10.19.2003
; use freely; credit'd be nice but I'll settle for a copy of yer game :D
;

; ITEM TYPES
;-------------------------------------------------------------------------------
; I use these as ITEM\VARIANT and SLOT\FLAGS
; and check that an AND match between the two returns true
; this allows you to have inventory slots for only certain items
Const ITEM_HEAD =  %0000000001		; generally caps & helms
Const ITEM_NECK =  %0000000010		; generally amulets/necklaces
Const ITEM_BACK =  %0000000100		; generally cloaks
Const ITEM_QUVR =  %0000001000
Const ITEM_LHAND = %0000010000		; generally shields
Const ITEM_RHAND = %0000100000		; generally weapons
Const ITEM_BHAND = %0001000000		; generally gauntlets & gloves
Const ITEM_FING  = %0010000000		; for rings
Const ITEM_BODY  = %0100000000		; armor/ clothes
Const ITEM_FEET  = %1000000000		; boots!
Const ITEM_PACK  = %1111111111		; general inventory -- anything goes here


; simple type def for location of sprites onscreen
Type coord
	Field x
	Field y
End Type

; type def for items as they exist in data.  separate from visual definition (chit),
; tho it links to its current chit template.
Type item
	Field variant			; what kind of object?  weapon, armor, etc.
	Field ID$				; name of object
	Field active			; currently wielded or worn
	Field loc.coord			; where it is
	Field stackable			; is it stackable?
	Field quantity			; allows stacking
	Field inner.inventory	; allows an object to have an inventory
	Field current.inventory	; what inventory is this object part of now?
	Field display.chit		; what we look like in inventory
	Field tpl.ChitTemplate	; our current display type instance (if any)
	Field curslot$			; slot ID of this item for display
End Type

; type def for inventories as they exist in data.  separate from visual representation (slot)
; links to a 'slotmap' that allows the program to create an inventory visually.
Type inventory
	Field max				; how many max inventory items in this container
	Field parent.item		; if this inventory lies inside an item, which one? (allows sacks)
	Field myPack			; reference to the bank that holds all inventory instances
	Field SlotMap			; bank of references to slot handles (same order as myPack)
End Type

; type def for an individual slot for an item in an inventory.  both data and visual representation.
; links to parent inventory and any currently held chit.
Type Slot
	Field ID$				; for storage/retrieval
	Field image				; what image to use
	Field frame				; what image frame to use
	Field loc.coord			; x/y location
	Field holds.chit		; what chit it's holding
	Field parent.inventory	; this way we can delete em!
	Field visible			; show it or not -- it's a cheat but I like it >:)
	Field flags				; these AND the item type must be true
End Type

; type def for an item as it exists on the screen only.  connects to its parent item description
; (which in turn links to its template) as well as its current "home" inventory slot (if any)
Type Chit
	Field loc.coord			; what its current coord set is
	Field home.slot	; where it belongs, currently (if anywhere)
	Field linked.item		; what the actual item is
End Type

; type def for an object display item.  These are not actually displayed as they exist, but linked to
; from chit object instances in order to display those instances properly.
Type ChitTemplate
	Field ID$				; english name of template type
	Field image				; what image to reference
	Field frame				; what frame of that image
End Type

; necessary under this methodology, unfortunately.  Tells the code what chit, if any, is currently
; being carted around by the mouse.
Global ChitActive.chit

; ---------------------------------------------------------
; CODE SPECIFIC TO THIS DEMO STARTS HERE
; ---------------------------------------------------------

; generic initialization crap
Graphics 640, 480, 0
SetBuffer BackBuffer()
SeedRnd MilliSecs()

; load in the slot graphic
mySlot = LoadImage("slot.png")
MaskImage mySlot, 255, 0, 255

; load in the object graphic
Global myItems = LoadAnimImage("inv.png", 32, 32, 0, 90)
MaskImage myItems, 255, 0, 255

; load in the mouse graphic
Global mouse = LoadImage("mouse.png")
MaskImage mouse, 255, 255, 255

; create two inventories; one represents the ground, one represents the PC's pack
myPC.inventory = CreateInventory(10, Null)			; gives the PC a pack with 10 slots
theGround.inventory = CreateInventory(10, Null)		; gives the ground 10 item slots

; Create 10 slots for each of those inventories.  
; this demo doesn't take advantage of the cool slot flags or item variants
; but you could easily tinker with this routine to do so.
For i = 1 To 10
	myContainer.slot = CreateSlot("pack", mySlot, i*40, 10, myPC, ITEM_PACK)
	myContainer.slot= CreateSlot("ground", mySlot, i*40, 150, theGround, ITEM_PACK)
Next

; Create three chit templates: the sword, bow and arrows.
myTpl1.ChitTemplate = CreateChitTemplate("Hero Sword", myItems, 49)
myTpl2.ChitTemplate = CreateChitTemplate("Hero Bow", myItems, 79)
myTpl3.ChitTemplate = CreateChitTemplate("Arrows", myItems, 17)

; Create three actual items using those templates.
mySword.item = CreateItem(ITEM_RHAND, "Hero Sword", 0, 0)
myBow.item = CreateItem(ITEM_RHAND, "Hero Bow", 0, 0)
treasure.item = CreateItem(ITEM_QUVR, "Arrows", 5, 5, True, 50)

; add those items to their respective inventories
AddItemToInv(mySword, myPC, "pack", False, True)
AddItemToInv(myBow, myPC, "pack", False, True)

AddItemToInv(treasure, theGround, "ground", False, True)

; annnnnd show the inventories to the player (inventories start off hidden)
ShowInventory(theGround)
ShowInventory(myPC)

; generic game loop here
; Calls to DrawSlots and DoChits are required in your main loop
; Also, if you want to draw your mouse pointer properly (ie, with attached inventory)
; you'll need to do the ChitActive check as well
; DispInv is only the text version I hacked for debugging, so you can safely remove it
; ------------------------------------------------------------------------------------
While Not KeyDown(1)

	Cls

; do checks on inventory item grabs
; this works for this demo, but the important thing is that the DrawSlots routine
; must know whether a mouse hit has occured lately, and the value you pass that routine
; is true or false depending on that event.
	If MouseHit(1)
		CheckFlag = True
	Else
		CheckFlag = False
	EndIf

; draw slots & do checks
	CheckFlag = DrawSlots(checkflag)
	
; draw chits & do checks
	DoChits(checkflag)
	
; draw the mouse, if necessary
	If ChitActive = Null
		DrawImage mouse, MouseX(), MouseY()
	EndIf
	
; display the text version of each inventory
; unnecessary for the pure-graphic version, but this is a nice confirmation
; that the data internally is lining up with the visuals externally
	DispInv(myPC, 0, 300)
	DispInv(theGround, 320, 300)
	
; add a random bunch of arrows to the ground
	If KeyHit(2)
		aTreasure.item = CreateItem(ITEM_QUVR, "Arrows", 5, 5, True, Rand(1, 100))
		checkme.chit = AddItemToInv(aTreasure, theGround, "ground", False, True)
	EndIf
	
	If KeyHit(57)	; spacebar toggles player inventory
		ToggleInventory(myPC)
	EndIf

	Text 0, 465, "[1] to add arrows to lower inventory; [SPACE] to hide upper inventory"
	
	Flip True
	Delay 10

Wend
End

; ---------------------------------------------------------
; CODE SPECIFIC TO THIS DEMO STARTS HERE
; ---------------------------------------------------------


; displays text version of the inventory (for debugging)
Function DispInv(inv.inventory, x, y)

	For i = 0 To inv\max - 1
		pointer = i * 4
		myHandle = PeekInt(inv\myPack, pointer)
		If myHandle <> 0
			myItem.item = Object.item(myHandle)
			myName$ = myItem\ID$
			If myItem\stackable = True
				myName$ = myName$ + "(" + myItem\quantity + ")"
			EndIf
		Else
			myName$ = ""

		EndIf

		Text x, y + (i * 12), (i + " - " + myName$)

	Next
End Function

; simple routine, just swaps an inventory from visible to hidden or vice versa
; depending on its current state
Function ToggleInventory(my.inventory)

	For this.slot = Each slot
		If this\parent = my
			this\visible = Not this\visible
		EndIf
	Next

End Function

; shows all slot and chit instances for a specified inventory
Function ShowInventory(my.inventory)

	For this.slot = Each slot
		If this\parent = my
			this\visible = True
		EndIf
	Next

End Function

; hides all slots and chit instances for a specified inventory
Function HideInventory(my.inventory)

	For this.slot = Each slot
		If this\parent = my
			this\visible = False
		EndIf
	Next

End Function

; creates an inventory type object with a set number of slots
; including two banks; one for holding item references, one for
; holding references to slots that represent the inventory
Function CreateInventory.inventory(howMany, parent.item)
	RVAL.inventory = New inventory
	RVAL\max = howMany
	RVAL\parent = parent
	
	RVAL\myPack = CreatePack(howMany)
	RVAL\SlotMap = CreateSlotMap(howMany)
	
	Return RVAL
End Function

; destroys an inventory and the slots associated with it, not the objects inside!
; it DOES release items to an inventory above the current one, if it exists
; otherwise items get released to nullspace
Function DestroyInventory(where.inventory, safe=True)

	; is this inventory located inside another one?  if so, record it
	If where\parent <> Null
		If where\parent\inner <> Null
			myNewLocation.inventory = where\parent\inner
		EndIf
	EndIf

	; are there items inside this inventory?  if so, let em out.
	; use this same loop (conveniently) to destroy all of our slot instances too
	For i = 0 To where\max - 1
		; both routines can use this pointer
		pointer = i * 4
		
		; first, let's grab the item that's here, if any
		myHandle = PeekInt(where\myPack, pointer)
		If myHandle <> 0
			myItem.item = Object.item(myHandle)
			myItem\current = myNewLocation		; explodable bags!
		EndIf
		
		; now, let's grab the slot that's here
		myHandle = PeekInt(where\myPack, slotMap)
		If myHandle <> 0
			mySlot.slot = Object.slot(myHandle)
			DestroySlot(mySlot)
		EndIf
		
	Next
	
	FreeBank where\myPack
	Delete where
	Return True
	
End Function

; creates a bank to hold handle info for items held within an inventory
Function CreatePack(packitems)
	RVAL = CreateBank(packitems * 4)
	Return RVAL
End Function

; creates a bank to hold handle info for slots within an inventory
Function CreateSlotMap(Slots)
	RVAL = CreateBank(Slots * 4)
	Return RVAL
End Function

; Creates a specific inventory slot for an inventory.
; FLAGS here represent the item type flags, and allow you to restrict putting
; certain types of items within certain slots.
Function CreateSlot.slot(ID$, image, x, y, parent.inventory, flags=0)

	RVAL.slot = New slot
	RVAL\ID = ID
	RVAL\image = image
	RVAL\loc.coord = New coord
	RVAL\loc\x = x
	RVAL\loc\y = y
	RVAL\parent = parent
	RVAL\flags = flags
	
	AddSlotToInv(RVAL, parent)
	
	Return RVAL
	
End Function

; Destroys a slot.  Simple enough.  
; Best not done manually -- let DestroyInventory do this for you
Function DestroySlot(mySlot.slot)
	
	Delete mySlot\loc
	Delete mySlot

End Function

; Adds a slot to inventory
; Best not done manually -- let CreateSlot do this for you.
Function AddSlotToInv(what.slot, where.inventory)

	myHandle = Handle(what)
	
	For i = 0 To where\max - 1
		If PeekInt(where\slotmap, i*4) = 0
			PokeInt where\slotmap, i*4, myHandle
			Return True
		EndIf
	Next
	
	DebugLog "Unable to add slot to slotmap!"
	Return False	

End Function

; Given an index number, return the slot instance of an inventory at that index
; I don't recall exactly why I did this and I don't use it for this lib,
; but who knows, it might be useful.
Function GetSlotByIndex.Slot(index)

	RVAL.slot = First slot

	For i = 1 To index
		RVAL = After RVAL
		If RVAL = Null Then Return Null
	Next
		
	Return RVAL

End Function


; Given a slot, return its index number within the inventory
; I =do= use this one.  Must have thought I'd need the other one.
Function GetSlotIndex(this.slot)

	For i = 0 To this\parent\max-1
		offset = i * 4
		CheckVal = PeekInt(this\parent\slotmap, offset)
		If CheckVal = Handle(this) 
			Return i

		EndIf
	Next
	
	Return -1

End Function

; given the index number and an inventory, return the item type that sits there.
; Another one i don't specifically use in the lib but it should be fairly apparent why this is useful
Function GetInvByIndex.item(where.inventory, index)

	If index => where\max Then Return Null

	pointer = index * 4
	myHandle = PeekInt(where\myPack, pointer)
	
	RVAL.item = Object.item(myHandle)
	Return RVAL

End Function

; Creates an item and its corresponding chit instance.
; variant describes the type of item, and is useful for limiting inventory objects to only certain slots
; stackable means that you can stack a number of these objects together.
; quantity is only really useful for stackable objects
; if I remember correctly, slots was meant to be how many this item took up, but I said heck with that :D
Function CreateItem.item(variant, ID$, x, y, stackable=False, quantity=1, slots=0)

	RVAL.item = New item
	RVAL\variant = variant
	RVAL\ID$ = ID$
	RVAL\loc = CreateCoord(x, y)
	RVAL\stackable = stackable
	RVAL\quantity = quantity

	If variant = ITEM_CONTAINER
		RVAL\inner = CreateInventory(slots, RVAL)
	EndIf
	
	RVAL\tpl = GetChitTemplate(RVAL\ID$)
	RVAL\display = CreateChit(RVAL)
	
	Return RVAL

End Function

; Destroys an item and its corresponding child objects (coordinates and chit)
Function DestroyItem(which.item)

; this can only be true if this item has been set up as an inventory object
	If which\inner <> Null
		; ultimately we want the 'exploding bag' thing here ;)
		If CountItemsInInv(which\inner) > 0 
			DebugLog "Cannot destroy full container"
			Return False
		EndIf
		DestroyInventory(which\inner, False)
	EndIf

	If which\current <> Null
		RemoveItemFromInv(which)
	EndIf
	
	DestroyChit(which\display)
	DestroyCoord(which\loc)
	Delete which

	Return True
	
End Function

; adds an item to an inventory indiscriminately -- sort of like a flood fill, objects will just
; go wherever they fit.  Good for initializing inventories.
Function AddItemToInv.Chit(which.item, where.inventory, slot$, stack=False, overflow=False)

	For i = 0 To where\max - 1	; iterating through each slot
	
		mySlot.Slot = Object.Slot(PeekInt(where\slotmap, i*4))

		If mySlot\ID$ = slot$		; right kind of slot
			myPack = PeekInt(where\myPack, i*4)

			If (overflow = True And myPack = 0) Or (overflow = False)	; check to see if we're initializing inv
				Return AddItemToSlot(which, mySlot, stack)			

			EndIf				
		EndIf
	Next
				
	Return Null
	
End Function

; Removes a specific item from its current inventory
; items carry a link to their current inventories at all time, so all you need
; is to pass the item to this routine
Function RemoveItemFromInv.chit(which.item)		; which\current knows where

	If which\current = Null 
		Return Null
	EndIf

	myBank = which\current\myPack
	myHandle = Handle(which)
	
	For i = 0 To which\current\max - 1
		pointer = i * 4
		myInt = PeekInt(myBank, Pointer)
		If myInt = myHandle
			PokeInt myBank, pointer, 0
			RVAL.chit = which\display

			RVAL\home\holds = Null
			RVAL\home = Null

			which\current = Null
			Return RVAL
			
		EndIf
	Next
	
	DebugLog "Tried to remove an item from an inventory that's not its current inventory"
	Return Null
			
End Function

; simple.  just counts how many items are currently in an inventory.
Function CountItemsInInv%(where.inventory)

	For i = 0 To where\max - 1
		pointer = i * 4
		If PeekInt(where\myPack, pointer) <> 0
			count = count + 1
		EndIf
	Next
		
	Return count

End Function

; Adds a SPECIFIC item to a SPECIFIC slot in an inventory, 
; unlike AddItemToInventory, which just dumps stuff anywhere.
; STACK parameter tells an inventory whether to check if items are identical and stack if they are
Function AddItemToSlot.chit(which.item, mySlot.slot, stack=False)

	If Not (which\variant And mySlot\flags) ; wrong kinda slot -- buhbye!
		Return which\display
	EndIf

	myIndex = GetSlotIndex(mySlot)
	If myIndex = -1 
		DebugLog "GetSlotIndex failed miserably."
		Return Null			; erm, wtf?

	EndIf
	
	where.inventory = mySlot\parent
	
	myPack = PeekInt(mySlot\parent\myPack, myIndex)
	
	If which\current <> Null		; means this object is in another inventory
		RemoveItemFromInv(which)
	EndIf


	; if the slot contains the same stackable item, we actually destroy the
	; initiating item and add its value to the item lying there.
	If stack = True		; true for the player pack - we stack things there always
		myItem.item = CheckStack(which, mySlot)	; so what about THIS item?
		If myItem <> Null	; means we can stack on myItem
			myItem\quantity = which\quantity + myItem\quantity
			DestroyItem(which)
			Return Null
		EndIf
	EndIf
	
	; if the slot holds nothing, drop the item in place
	If mySlot\holds = Null			; if nothing in this slot
		mySlot\holds = which\display		; adds this chit to the slot
		PokeInt where\myPack, myIndex*4, Handle(which); adds this item to inventory
		which\current = where				; tell the item where it lives
		which\display\home = mySlot			; give a home to the obj
		Return Null							; nothing left on the cursor
	
	; otherwise, swap out the currently slotted object with the one we dropped
	
	Else								; if something IS in this slot
		tmp.chit = mySlot\holds				; record the chit
		mySlot\holds = which\display		; add the new chit to the slot
		PokeInt where\myPack, myIndex*4, Handle(which); overwrite existing item in pack
		which\current = where				; tell the item where it lives
		which\display\home = mySlot			; give a home to the display obj
		tmp\home = Null						; remove the home for the displaced obj
		Return tmp							; return the displaced object
	
	EndIf

End Function

; Creates and returns a new coord instance
Function CreateCoord.coord(x, y)

	RVAL.coord = New coord
	RVAL\x = x
	RVAL\y = y
	Return RVAL

End Function

; destroys a coord instance
Function DestroyCoord(where.coord)

	Delete where
	Return True

End Function


; checks to see if a given object and any potential items on a given slot
; are stackable -- returns the item that can be stacked on if true
Function CheckStack.item(which.item, mySlot.slot)

	If which\stackable = False Then Return Null
	If mySlot\holds = Null Then Return Null
	
	RVAL.item = mySlot\holds\linked

	If RVAL <> Null
		If RVAL\variant = which\variant
			If RVAL\ID$ = which\ID$
				Return RVAL
			EndIf
		EndIf
	EndIf
	
	Return Null

End Function


; Creates a chit template and returns the instance.
Function CreateChitTemplate.ChitTemplate(ID$, image, frame)

	RVAL.ChitTemplate = New ChitTemplate
	
	RVAL\ID$ = ID$
	RVAL\image = image
	RVAL\frame = frame
	
	Return RVAL

End Function

; get a chit template by its ID
Function GetChitTemplate.ChitTemplate(ID$)

	; consider speeding this up with an array of 26 insertion points (A-Z)
	
	For this.ChitTemplate = Each ChitTemplate
		If this\ID$ = ID$
			Return this

		EndIf
	Next
	
	Return Null

End Function

; Creates a chit instance, given an item instance.
Function CreateChit.Chit(link.item, x=0, y=0)

	RVAL.chit = New chit
	RVAL\linked = link
	RVAL\loc.coord = New coord
	RVAL\loc\x = x
	RVAL\loc\y = y
	
	Return RVAL
End Function

; Correctly destroys a chit
Function DestroyChit(this.chit)

	Delete this\loc
	Delete this

End Function

; Draws slots and does collisions for them with any active chit the player may be holding.
; this routine MUST be told whether a MouseDown event has occured.
Function DrawSlots(checkflag)

	For this.slot = Each slot
		If checkflag = True
			If this\visible = True
				If ImagesCollide(mouse, MouseX(), MouseY(), 0, this\image, this\loc\x, this\loc\y, 0)
					If ChitActive = Null
						If this\holds <> Null
							ChitActive = RemoveItemFromInv(this\holds\linked)
						EndIf
					Else
						ChitActive = AddItemToSlot(ChitActive\linked, this, True)
					EndIf
					
					CheckFlag = False

				EndIf
			EndIf
				
		EndIf

		If this\visible = True Then DrawImage this\image, this\loc\x, this\loc\y
	Next
	
	Return checkflag

End Function

; draws item chits currently visible.
; the commented code here is for using randomly scattered objects in a 2d playfield
; but since I've decided not to go this way I've pretty much ignored it and it's not guaranteed to work
; right.  If you DO intend to let objects scatter around, this routine will need to know whether
; a mousedown has recently occured too.
Function DoChits(checkflag)

	If ChitActive <> Null
		ChitActive\loc\x = MouseX()
		ChitActive\loc\y = MouseY()
		Insert ChitActive After Last chit
	EndIf

	For this.chit = Each chit

;		If CheckFlag = True
;	
;			If ChitActive = Null
;				If ImagesCollide(this\linked\tpl\image, this\loc\x, this\loc\y, this\linked\tpl\frame, mouse, MouseX(), MouseY(), 0)
;					ChitActive = this
;					checkflag = False
;				EndIf
;			Else
;				ChitActive = Null
;				checkflag = False
;			EndIf
;		EndIf
			
;		If this\home = null
		If this = ChitActive
			DrawImage this\linked\tpl\image, this\loc\x, this\loc\y, this\linked\tpl\frame
		Else
			If this\home <> Null
				If this\home\visible = True
					DrawImage this\linked\tpl\image, this\home\loc\x, this\home\loc\y, this\linked\tpl\frame
				EndIf
;			Else
;				DrawImage this\linked\tpl\image, this\loc\x, this\loc\y, this\linked\tpl\frame
			EndIf
		EndIf
	Next
	

End Function


wow! this is excellent!

i am going to check this code, it seams to be exactly as what i needed!

thanks a lot!

i am sorry...

would you please tell me if there is somewhere i can get the media? i am a programmer trying to get somebody in the team, right now i dont handle graphic stuff :(

please.

many thanks.

p.s. i sent an email to the author (congratulationsm thanks and requesting media if available) but the mailbox is not available :(

>would you please tell me if there is somewhere i can get
>the media? i am a programmer trying to get somebody in the
>team, right now i dont handle graphic stuff :(

Well, there is no time like the present to start doing graphics. Nothing fancy, just placeholders until you find that graphics artist.


Andy

Okay, here's the zip:

http://files.to/get/40121/861/mordy_inventory.zip


Good luck !