variant constants

Blitz3D Forums/Blitz3D Beginners Area/variant constants

Const item0 = %0000000001
Const item1 = %0000000010
Const item2 = %0000000100
Const item3 = %0000001000
Const item4 = %0000010000
Const item5 = %0000100000
Const item6 = %0001000000
Const item7 = %0010000000
Const item8 = %0100000000
Const item9 = %1000000000

What comes next? I have many other items I need to add to the fray. %10000000001, %1000000010, etc doesn't seem to work.

Const item0 = %0000000001

Const item0 = 1

Strange way to write it :o) Why have you put the zero's in front? It looks like your trying to use bits here. But surely blitz would save 0000000001 as 1, as % is an interger variable is it not?

Trying to get my head around morduun's inventory code...

; MORDYSLOTS
; Baldur's Gate style inventory lib for Blitz Basic
; written by morduun / <a href="mailto:morduun@hotmail.com">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


Mordunns system is more like binary flags , so looks like this in int form.

Const ITEM_HEAD =  1		; generally caps & helms
Const ITEM_NECK =  2		; generally amulets/necklaces
Const ITEM_BACK =  4		; generally cloaks
Const ITEM_QUVR =  8
Const ITEM_LHAND = 16		; generally shields
Const ITEM_RHAND = 32		; generally weapons
Const ITEM_BHAND = 64		; generally gauntlets & 
const 
gloves
etc..


This flag is basically 2^( Item property ) so that you can store and access multiple properties for each object. You would assign this property to the item rather than item0 = 1, item 1 = 2 , item 2 = 4 etc.. I think you misunderstand it's usage.

So, for example if you have a sword which you can hold in your Left Hand and Right Hand you would set the item property flag to 96 ( 32 + 64 )

When checking which slots this item can be placed ...

Flag = 32+64

if Flag and ITEM_LHAND
  { this item can be held in the left hand }
endif

if Flag and ITEM_RHAND
  { this item can be held in the right hand }
endif


Both conditions will return true so the system knows it can be placed in either slot.

Another example, level ambience :

;level ambience
;time of day
Const LA_DAY = 1
Const LA_NIGHT = 2
;weather
Const LA_MILD = 4
Const LA_SUN = 8
Const LA_RAIN = 16
Const LA_FOG = 32
Const LA_WIND = 64
Const LA_THUNDER = 128


So to set a the ambience to night + raining + thunder ..

global LA_FLAG = LA_NIGHT + LA_RAIN + LA_THUNDER


To access the individual properties ..
If ( LA_FLAG and LA_NIGHT )
   ;turn the lights out
endif

if ( LA_FLAG and LA_RAIN )
   ;make it rain
endif


Not much of an explanation but hopefully it'll help slightly.

Stevie

Makes perfect sense, thanks a ton. I pretty much figured things out by the time I read this and it works great. Thank goodness for people that donate code (morduun).