Sega Genesis Programming Part 15: Inventory


Goals

This little article has significantly fewer pictures than the previous one, sorry if that disappoints/bores you. There are almost 500 lines of code in here if that does anything for you.

Today we'll be adding inventory management to the demo, this includes:

1) Adding & removing items from the player's inventory

2) Displaying a give/take dialog where the player can choose items

3) Responding to a selection from the previous step

Alright, let's get going...

Inventory management

First off is defining the maximum number of items the player can carry. This is small for two reasons: laziness. Well, mostly laziness. I was going to add an excuse that it makes the game more realistic if the player can't carry 99 potions but I assume most of you would see through that.


MAX_ITEMS=$04 ; maximum number of items the player can carry

Next is reserving some places in memory to store the item list:


;-----------------
; player inventory
;-----------------
MEM_PLAYER_ITEM_COUNT=$FFFF002C ; how many items the player is holding
MEM_PLAYER_ITEMS=$FFFF002E ; item list

Now we need the basic add & remove subroutines. Add is first for hopefully obvious reasons:


;---------------------------------------
; adds an item to the player's inventory 
; d7 = item to add
; d6 is modified by this subroutine
; a1 is modified by this subroutine
;---------------------------------------
AddItem:
 move.w (MEM_PLAYER_ITEM_COUNT),d6 ; copy current item count to d6
 cmpi.w #MAX_ITEMS,d6 ; check if inventory is full 
 bge.s ExitAddItem ; branch if already at the limit
 addq #$1,(MEM_PLAYER_ITEM_COUNT) ; increment item count
 mulu.w #WORD_SIZE,d6 ; find index of location to write the item
 lea MEM_PLAYER_ITEMS,a1 ; point to start of item list
 move.w d7,(a1,d6) ; copy the item 
ExitAddItem:
 rts

Before we can remove an item we need a subroutine to determine if the player is carrying it in the first place. "Remove by index" is an easy enough subroutine to add but not as useful. There are a dozen scenarios where removing an item by item ID makes sense. Anyway, this subroutine checks if the player has an item and if so returns the index. -1 (FFFF) is returned if the item is not found.


;---------------------------------------------------
; tests if the player has an item
; d7 = item to look for
; d6 will have index of item if found, otherwise FFFF
; d5 is modified by this subroutine
; a1 is modified by this subroutine
;-----------------------------------------------------
HasItem:
 move.w (MEM_PLAYER_ITEM_COUNT),d6 ; copy item count to d6
 tst.w d6 ; test if item count is zero
 beq.s HasItemNotFound ; item count is zero, return FFFF and exit
 subq #$1,d6 ; decrement for zero-based list
 move.w d6,d5 ; copy item count to d5
 mulu.w #WORD_SIZE,d5 ; multiply to get the index of the last item
 lea MEM_PLAYER_ITEMS,a1 ; point to start of item list
 adda.l d5,a1 ; move a1 to last item in the list
HasItemLoop:
 cmp.w (a1),d7 ; test if this is the item we're looking for
 beq.s ExitHasItem ; branch if it is
 suba.l #WORD_SIZE,a1 ; move to next item
 dbra d6,HasItemLoop ; loop to the end of the list
HasItemNotFound:
 move.w #$FFFF,d6 ; set FFFF as the return value
ExitHasItem:
 rts

Last is the subroutine to remove an item, which calls the previous subroutine:


;--------------------------------------------
; removes an item from the player's inventory
; d7 = item to remove
; d5 and d6 are modified by this subroutine
; a1 is modified by this subroutine
;--------------------------------------------
RemoveItem:
 bsr.w HasItem ; test if the item is in the inventory
 cmpi.w #$FFFF,d6 ; test if the item was found
 beq.s ExitRemoveItem ; exit if it was not
 subq #$1,(MEM_PLAYER_ITEM_COUNT) ; decrement item count
 move.w d6,d5 ; copy item index to d5
 mulu.w #WORD_SIZE,d5 ; multiply to get the index of the removed item
 lea MEM_PLAYER_ITEMS,a1 ; point to start of item list
 adda.l d5,a1 ; move a1 to the removed item
 move.w #$0000,(a1) ; clear removed item
 move.w (MEM_PLAYER_ITEM_COUNT),d5 ; copy item count to d5
 sub.w d6,d5 ; subtract item index from count to get loop control
 beq.s ExitRemoveItem ; exit if the only item in inventory was removed
RemoveItemLoop:
 move.w (WORD_SIZE,a1),(a1) ; copy item +1 to current item
 adda.l #WORD_SIZE,a1 ; move to next item
 move.w #$0000,(a1) ; clear item slot 
 dbra d5,RemoveItemLoop ; loop to next item
ExitRemoveItem:
 rts 

With the basic plumbing out of the way we can move on to the slightly more difficult part...

Item dialog

In previous articles we built dialogs with two and three selections. We now need a dialog that displays four selections. This magical number is based on the number of items in the player's inventory. Although it could page to fit more if needed. It will also be used when the player selects "Take" from the A button menu to present them with a list of items to choose. Also, I think it will be helpful at some point to have a dialog that gives the player four choices. Like in a battle it could show options like: Fight, Item, Defend, or Wet Pants.

Step one is adding some new dialog flags and renaming a couple others:


DIALOG_FLAG_STYLE_ITEM_MENU=$15 ; item menu dialog
DIALOG_FLAG_STYLE_MENU=$16 ; overworld menu style dialog
DIALOG_FLAG_STYLE_TEXT_4CHOICE=$17 ; dialog has text with selection at the end
DIALOG_FLAG_STYLE_TEXT_2CHOICE=$18 ; dialog has text with selection at the end 

DIALOG_FLAG_STYLE_TEXT_4CHOICE is used mostly when the selector sprite is moved. DIALOG_FLAG_STYLE_ITEM_MENU tells the ProcessDialog subroutine to draw a list of items. It also changes the values set when the dialog is closed.

For ProcessDialog to handle items we need three new variables. We need a pointer to a list of items, a counter of where we are in drawing that list, and also a place to store the item selected.


MEM_ACTIVE_ITEM=$FFFF001A ; item that is currently being used
[...]
MEM_DIALOG_ITEM_LIST=$FFFF0046 ; pointer to location of item list to display
MEM_DIALOG_ITEM_INDEX=$FFFF004A ; track which item in the list is being drawn 

The nice thing about MEM_DIALOG_ITEM_LIST is that it can either point to an address in the ROM or in memory so it can be used to display static items or what the player is currently carrying.

Now we need some items. Since the player starts off close to the magazine rack, and I'm incredibly lazy, the first items will be magazines. This requires creating some item IDs, names for the items, and a lookup table for the names:


;-----------------------------------
; items
;-----------------------------------
OBJ_ITEM_BASE=$3000
OBJ_ITEM_NOTHING=OBJ_ITEM_BASE
OBJ_ITEM_MAG_GAMEPRO=OBJ_ITEM_BASE+1
OBJ_ITEM_MAG_EGM=OBJ_ITEM_BASE+2
OBJ_ITEM_MAG_ANTIC=OBJ_ITEM_BASE+3
OBJ_ITEM_MAG_ANALOG=OBJ_ITEM_BASE+4
[...]
ItemNameNothing:
 dc.b "Nothing",ITEMNAMEEND

ItemNameMagGamePro:
 dc.b "GamePro",ITEMNAMEEND

ItemNameMagEGM:
 dc.b "EGM",ITEMNAMEEND

ItemNameMagAntic:
 dc.b "Antic",ITEMNAMEEND

ItemNameMagAnalog:
 dc.b "Analog",ITEMNAMEEND
[...]
ItemNameTable:
 ;OBJ_ITEM_NOTHING
 dc.l ItemNameNothing
 ;OBJ_ITEM_MAG_GAMEPRO
 dc.l ItemNameMagGamePro
 ;OBJ_ITEM_MAG_EGM
 dc.l ItemNameMagEGM
 ;OBJ_ITEM_MAG_ANTIC
 dc.l ItemNameMagAntic
 ;OBJ_ITEM_MAG_ANALOG
 dc.l ItemNameMagAnalog

We also need a list that will be referenced in ProcessDialog. I guess I should figure out how to store this in the scene definition or something. For now it's hard-coded in some random spot:


ItemListVBMagazine:
 dc.w OBJ_ITEM_MAG_GAMEPRO
 dc.w OBJ_ITEM_MAG_EGM
 dc.w OBJ_ITEM_MAG_ANTIC
 dc.w OBJ_ITEM_MAG_ANALOG

Here's some new text that will come up later. ITEMNAMESTART is a new constant that will be used to tell ProcessDialog to draw the next item in the list.


ItemMenu:
 dc.b "{",ITEMNAMESTART
;-------------------------
; take menus and messages
;-------------------------
TakeMenuFull:
 dc.b "You can't carry any",LF
 dc.b "more items.",ETX
TakeMenuMagazines:
 dc.b "Which magazine do you",LF
 dc.b "want to take?        ^",FF
 dc.b "{",ITEMNAMESTART
TakeMagazinesOption0:
 dc.b "You selected option 0.",ETX
TakeMagazinesOption1:
 dc.b "You selected option 1.",ETX
TakeMagazinesOption2:
 dc.b "You selected option 2.",ETX
TakeMagazinesOption3:
 dc.b "You selected option 3.",ETX 

ProcessDialog is doing the most complicated work, and it's not terribly complicated at all. When it encouters the ITEMNAMESTART character it looks up the name of the next item and sets it as the next text to draw. When it encounters the ITEMNAMEEND character it determines whether there are more items to draw. If so it resets the text back to ItemMenu, otherwise it moves to the next dialog state.


ProcessDialogTextDrawing:
[...]
TestItemNameStart:
 cmpi.b #ITEMNAMESTART,d6 ; start of an item name?
 bne.s TestItemNameEnd ; not the ITEMNAMESTART character, next test
 ;------------------------------------------
 ; build text for next item name in the list
 ;------------------------------------------
 ; lookup the object ID for the next item 
 move.l (MEM_DIALOG_ITEM_LIST),a6 ; copy address of item list to a6
 move.w (MEM_DIALOG_ITEM_INDEX),d6 ; copy current item index to d6
 mulu.w #WORD_SIZE,d6 ; multiply by WORD_SIZE to get the offset
 adda.l d6,a6 ; add offset
 move.w (a6),d6 ; copy item ID to d6
 andi.w #$0FFF,d6 ; clear the base value
 ; object ID is in d6 now, find the address for the text
 mulu.w #LWORD_SIZE,d6 ; multiply by LWORD_SIZE to get the offset
 lea ItemNameTable,a6 ; point a6 to item name table
 adda.l d6,a6 ; add offset
 move.l (a6),(MEM_DIALOG_TEXT) ; copy value at a6 to MEM_DIALOG_TEXT
 bra.w ExitProcessDialog ; exit
TestItemNameEnd:
 cmpi.b #ITEMNAMEEND,d6 ; end of an item name?
 bne.s TestLF ; not the ITEMNAMEEND character, next test
 ;---------------------------------------------
 ; determine if there are more items to display
 ;---------------------------------------------
 addq #$1,(MEM_DIALOG_ITEM_INDEX) ; increment item name
 cmpi.w #MAX_ITEMS,(MEM_DIALOG_ITEM_INDEX) ; at max items?
 bge.s ProcessDialogTextEnd ; branch if at max items
 ; test if the next item is OBJ_ITEM_NOTHING
 move.l (MEM_DIALOG_ITEM_LIST),a6 ; copy address of item list to a6
 move.w (MEM_DIALOG_ITEM_INDEX),d6 ; copy current item index to d6
 mulu.w #WORD_SIZE,d6 ; multiply by WORD_SIZE to get the offset
 adda.l d6,a6 ; add offset
 cmpi.w #OBJ_ITEM_NOTHING,(a6) ; test if value at a6 = OBJ_ITEM_NOTHING
 beq.s ProcessDialogTextEnd ; branch if next item is OBJ_ITEM_NOTHING
 cmpi.w #$0000,(a6) ; test if value at a6 = 0000
 beq.s ProcessDialogTextEnd ; branch if next item is OBJ_ITEM_NOTHING
 ;----------------------------
 ; setup to draw the next item
 ;----------------------------
 lea ItemMenu,a6 ; point a6 to the item menu text
 move.l a6,(MEM_DIALOG_TEXT) ; copy a6 to MEM_DIALOG_TEXT
 bsr.w SetItemMenuDrawLocation ; set the draw location of the next item
  bra.w ExitProcessDialog 
[...]

There's also some work to set where the next item name should be drawn in the dialog.


SetItemMenuDrawLocation:
 move.w (MEM_DIALOG_ITEM_INDEX),d6 ; copy index of current item to d6
 ;test for 0001
 cmpi.w #$0001,d6 ; is it one?
 bne.s .1 ; branch if not
 ; move down 2 rows
 move.l #(VDP_VRAM_WRITE_A+DIALOG_ROWCOL+$01020000),(MEM_DIALOG_VPD)
 bra.s ExitSetItemMenuDrawLocation ; exit
.1 ; test for 0002
 cmpi.w #$0002,d6 ; is it two?
 bne.s .2 ; branch if not
 ; move down 1 row
 move.l #(VDP_VRAM_WRITE_A+DIALOG_ROWCOL+$00980000),(MEM_DIALOG_VPD)
 bra.s ExitSetItemMenuDrawLocation ; exit
.2 ; test for 0003
 cmpi.w #$0003,d6 ; is it theee?
 bne.s ExitSetItemMenuDrawLocation ; exit if not
 ; move down 1 row and column
 move.l #(VDP_VRAM_WRITE_A+DIALOG_ROWCOL+$01180000),(MEM_DIALOG_VPD)
ExitSetItemMenuDrawLocation:
 rts

Moving the selector sprite needs to account for the new four choice style. It also needs to account for the possibility that there might only be 1-3 items in the list.


FourChoiceLeftRight:
 btst.l #DIALOG_FLAG_STYLE_ITEM_MENU,d7 ; test if this is an item menu
 beq.s .1 ; not an item menu, branch
 ; MEM_DIALOG_ITEM_INDEX has the total number of items in dialog +1
 cmpi.w #$0002,(MEM_DIALOG_ITEM_INDEX) ; are there 2 or fewer items?
 ble.s ExitFourChoiceLeftRight ; exit if 2 or fewer
 ; there are 3 or 4 items, 4 items is fine
 cmpi.w #$0004,(MEM_DIALOG_ITEM_INDEX) ; are there 4 items?
 bge.s .1 ; if so continue
 ; three items is the only possibility now
 cmpi.w #$0001,(MEM_MENU_SELECTION) ; is the 2nd item selected?
 beq.s ExitFourChoiceLeftRight ; if so exit
.1
 cmpi.w #$0002,(MEM_MENU_SELECTION) ; test if <2
 blt.s .2 ; MEM_MENU_SELECTION is > 2
 subq #$0002,(MEM_MENU_SELECTION) ; subtract 2 to rollover
 bra.s ExitFourChoiceLeftRight ; exit
.2
 addq #$0002,(MEM_MENU_SELECTION) ; add 2 to move right
ExitFourChoiceLeftRight:
 rts
FourChoiceUpDown:
 btst.l #DIALOG_FLAG_STYLE_ITEM_MENU,d7 ; test if this is an item menu
 beq.s .1 ; not an item menu, branch
 ; MEM_DIALOG_ITEM_INDEX has the total number of items in dialog +1
 cmpi.w #$0001,(MEM_DIALOG_ITEM_INDEX) ; is there only 1 item?
 beq.s ExitFourChoiceFourChoiceUpDown ; exit if only 1 item
 ; there are 3 or 4 items, 4 items is fine
 cmpi.w #$0004,(MEM_DIALOG_ITEM_INDEX) ; are there 4 items?
 bge.s .1 ; if so continue
 ; three items is the only possibility now
 cmpi.w #$0002,(MEM_MENU_SELECTION) ; is the 3rd item selected?
 beq.s ExitFourChoiceFourChoiceUpDown ; if so exit
.1
 cmpi.w #$0000,(MEM_MENU_SELECTION) ; test if 0
 beq.s FourChoiceUpDownAdd ; MEM_MENU_SELECTION is 0
 cmpi.w #$0002,(MEM_MENU_SELECTION) ; test if 2
 beq.s FourChoiceUpDownAdd ; MEM_MENU_SELECTION is 2
 subq #$0001,(MEM_MENU_SELECTION) ; subtract 1 to rollover
 bra.s ExitFourChoiceFourChoiceUpDown ; exit
FourChoiceUpDownAdd:
 addq #$0001,(MEM_MENU_SELECTION) ; add 2 to move down
ExitFourChoiceFourChoiceUpDown: 
 rts

When the player confirms a menu selection there's a little new work to determine if this is an item list and if so to store the selected item.



ConfirmMenuSelection:
[...]
ConfirmMenuSelection4Choice:
 move.w (MEM_MENU_SELECTION),(MEM_MENU_RESPONSE) ; selection->response
 btst.l #DIALOG_FLAG_STYLE_ITEM_MENU,d7 ; test if this is an item menu
 beq.s ExitConfirmMenuSelection ; not an item menu, branch
 ; store selected item in MEM_ACTIVE_ITEM 
 move.l (MEM_DIALOG_ITEM_LIST),a6 ; copy address of item list to a6
 move.w (MEM_MENU_SELECTION),d6 ; copy current item index to d6
 mulu.w #WORD_SIZE,d6 ; multiply by WORD_SIZE to get the offset
 adda.l d6,a6 ; add offset
 move.w (a6),(MEM_ACTIVE_ITEM) ; copy item ID to d6 
[...]

The end result is this little dialog showing a list of items:

Item menu

That was fun, OK not a lot of fun to debug but overall this wasn't too bad. Let's wrap this up by...

Responding to item selections

The ProcessAction subroutine was previously built to handle forwarding actions to the appropriate day/scene/action handler. One (of possibly many) flaws with this approach is there are some actions that don't change based on the day & scene. Giving an item is one of them, or at least the initial act of displaying the list of items to give. There needs to be a default handler for this, it needs to be smart enough to determine if the player is trying to open the Give menu or has just selected an item in it. That's pretty easy to sort out:



ProcessAction:
 bsr.w ResetDialog ; reset the dialog
 ; ----------------------------------------
 ; test if a default handler should be used
 ; ----------------------------------------
 cmpi.w #ACTION_TAKE_GIVE,(MEM_ACTION_ID) ; test if this is a give action
 bne.s ProcessActionBuildActionTableOffset ; not give action, branch
 move.w (MEM_ACTION_TARGET_OBJID),d7 ; copy action target to d7
 andi.w #OBJ_NPC_BASE,d7 ; and against base npc ID
 beq.s .1 ; target is not an NPC
 ; --------------------------------------------
 ; default handler for giving an item to an NPC
 ; --------------------------------------------
 cmpi.w #$0000,(MEM_ACTIVE_ITEM) ; test if there is an active item
 bne.s ProcessActionBuildActionTableOffset ; responding to a give menu
 bsr.w DefaultActionGive ; otherwise launch default action
 bra.s ExitProcessAction ; exit
.1 ; test if target is scenery
 move.w (MEM_ACTION_TARGET_OBJID),d7 ; copy action target to d7
 andi.w #OBJ_SCENE_BASE,d7 ; and against base npc ID
 beq.s ProcessActionBuildActionTableOffset ; target is not scenery
 cmpi.w #MAX_ITEMS,(MEM_PLAYER_ITEM_COUNT) ; carrying max items?
 bne.s ProcessActionBuildActionTableOffset ; branch if < max
 bsr.w DefaultActionInventoryFull ; launch default action
 bra.s ExitProcessAction ; exit
ProcessActionBuildActionTableOffset:
 bsr.w BuildActionTableOffset ; build action table offset
 lea ActionTable,a5 ; point to action table
 adda.w (MEM_ACTION_TABLE_OFFSET),a5 ; move to offset location
 move.l (a5),a6 ; a5 has the address of the subroutine to jump to
 jsr (a6) ; jump to location of code to process this event
ExitProcessAction:
 move.l (MEM_GAME_STATE),d7 ; copy current game state to d7
 bclr.l #STATE_FLAG_ACTION,d7 ; clear action flag
 move.l d7,(MEM_GAME_STATE) ; save it back
 rts 

The default Give action then displays the menu or a message saying the player doesn't have any items. As a bonus, there's also a message if a player tries to take an item when their inventory is full.


;--------------------------------------------------------------------
; builds the give menu or displays message if the player has no items
;--------------------------------------------------------------------
DefaultActionGive:
 cmpi.w #$0000,(MEM_PLAYER_ITEM_COUNT) ; is item count 0?
 beq.s DefaultActionGiveNoItems ; branch if 0
 lea ItemMenu,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
 lea MEM_PLAYER_ITEMS,a6 ; load item list
 move.l a6,MEM_DIALOG_ITEM_LIST ; copy address to MEM_DIALOG_ITEM_LIST
 move.l (MEM_DIALOG_FLAGS),d7 ; copy dialog flags to d7
 bset.l #DIALOG_FLAG_STYLE_TEXT_4CHOICE,d7 ; set text choice flag
 bset.l #DIALOG_FLAG_STYLE_ITEM_MENU,d7 ; set item menu flag
 move.l d7,(MEM_DIALOG_FLAGS) ; save updated dialog flags
 bra.s ExitDefaultActionGive ; exit
DefaultActionGiveNoItems:
 lea DialogTextNoItems,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
ExitDefaultActionGive:
 rts

;-------------------------------------------------------
; displays a message if the player can't hold more items
;-------------------------------------------------------
DefaultActionInventoryFull:
 lea TakeMenuFull,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
ExitDefaultActionInventoryFull:
 rts

In the action script there are two ways we can respond to a Give/Take action. We can look at the selected index in the dialog and display a message. This code example does that. Another option is responding based on the item ID that was selected. This is more useful in 99% of cases but I coded the other one first (and again am lazy). This also shows how to handle giving an item to an NPC.


Day00Scene00Action02: ; ACTION_TAKE_GIVE
 move.w (MEM_ACTION_TARGET_OBJID),d6 ; copy action target to d6
 andi.w #OBJ_SCENE_BASE,d6 ; and against base scene ID
 beq.w Day00Scene00Action02DefaultGive ; not scenery
 move.w (MEM_ACTION_TARGET_OBJID),d6 ; copy action target to d6
 cmpi.w #OBJ_SCENE_VB_MAGS,d6 ; is the magazine rack the target?
 bne.w Day00Scene00Action02DefaultTake ; not the magazine rack, branch
 ; check if we are coming back from a take menu or need to open one 
 cmpi.w #DIALOG_NO_RESPONSE,(MEM_MENU_RESPONSE) ; test response
 beq.s .5 ; branch if no response
 cmpi.w #$0000,(MEM_MENU_RESPONSE) ; test response
 bne.s .1
 lea TakeMagazinesOption0,a6 ; load dialog text
 bra.s .4
.1
 cmpi.w #$0001,(MEM_MENU_RESPONSE) ; test response
 bne.s .2
 lea TakeMagazinesOption1,a6 ; load dialog text
 bra.s .4
.2
 cmpi.w #$0002,(MEM_MENU_RESPONSE) ; test response
 bne.s .3
 lea TakeMagazinesOption2,a6 ; load dialog text
 bra.s .4
.3
 cmpi.w #$0003,(MEM_MENU_RESPONSE) ; test response
 bne.s .3
 lea TakeMagazinesOption3,a6 ; load dialog text
.4
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
 move.l (MEM_DIALOG_FLAGS),d7 ; copy dialog flags to d7
 bclr.l #DIALOG_FLAG_STYLE_TEXT_4CHOICE,d7 ; set text choice flag
 move.l d7,(MEM_DIALOG_FLAGS) ; save updated dialog flags
 bra.s ExitDay00Scene00Action02
.5 
 lea TakeMenuMagazines,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
 lea ItemListVBMagazine,a6 ; load item list
 move.l a6,MEM_DIALOG_ITEM_LIST ; copy address to MEM_DIALOG_ITEM_LIST
 move.l (MEM_DIALOG_FLAGS),d7 ; copy dialog flags to d7
 bset.l #DIALOG_FLAG_STYLE_TEXT_4CHOICE,d7 ; set text choice flag
 bset.l #DIALOG_FLAG_STYLE_ITEM_MENU,d7 ; set item menu flag
 move.l d7,(MEM_DIALOG_FLAGS) ; save updated dialog flags
 bra.s ExitDay00Scene00Action02
Day00Scene00Action02DefaultTake:
 lea DialogTextCantTake,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
 bra.s ExitDay00Scene00Action02
Day00Scene00Action02DefaultGive:
 lea DialogTextNothingHappens,a6 ; load dialog text
 move.l a6,MEM_DIALOG_TEXT ; copy address to MEM_DIALOG_TEXT
ExitDay00Scene00Action02:
 rts

And the end result is this exciting message:

Responding to a selection

With just a little work items can be added to all the shelves and racks. We can also have the NPCs respond to items you show them. This is all part of the overall game plan for a one-room demo. This seems like a good enough time as any to check in on that...

What's next?

Looking at the "plan" from three articles ago:

1) Dialog between characters - meaning an NPC says something to you and you respond. Maybe you respond with more dialog, maybe you give them an item. That leads to...

2) Inventory management - along with basic stuff like taking and giving items.

3) Game event tracking - we need a way to say "if [X] happened and you talk to character [Y] then do [Z]", I'll probably over-complicate this. I won't call this 100% complete but it's functional enough.

4) Scripted sprite movements - if the ultimate goal is to get a customer to leave a store then there needs to be an animation where they walk away.

5) Adding & removing NPCs from the current scene - the one NPC is hard-coded, there needs to be a way to move NPCs in and out of scenes. The removing part hasn't been needed yet but it's small and will be addressed with #4.

6) To make this look like a real demo I should really create a title screen and ending message.

7) Dozens of things I didn't think of that will all be painful to work out.

Next round will be scripted sprite movements, along with removing NPCs from the scene. Of course adding more items and NPC dialog needs to happen along the way too.

Download

Download the latest source code on GitHub




Related