Main loop is very similar to the one from Pursuing Tom Ram
;--- Main --------------------------
Game_Begin
; Init variables
; Before init for resuing some routines.
jsr Random_City
jsr Init
; show intructions of the game
jsr Instructions
LocLoop
; Reset stack
ldx #$ff
txs
jsr CLRS
jsr PrintStats
jsr PrintLOC
jsr Jump_LOC
MainLoop
jsr InputCommand ; get command
jsr EvalCommand
jmp MainLoop
Resetting stack is more important in Desert than in Pursuing tom Ram.
If you read the source code of Desert, you will find that, many times, I call subroutines with JSR but I do not go back with RTS. JSR stores the actual memory address in the stack, so, when the processor finds a RTS, it knows where to go back to continue the execution.
If I jump to a subroutine with JSR but I do not execute a RTS, for example, because I go to another subroutine with JMP, the memory address remains in stack. If you play long time, the stacks will, be full and the program crashes.
At the beginning of the LocLoop part there is not any JSR call waiting to return, so it is a good time to clear the stack. There is a specific register for the memory address of the stack, S register, so I load the original position of the stack in this register. All information remaining in the stack will be rewriting without any problem.
Input in Desert is easier than Pursuing Tom Ram due the game only understands a verb. I reused the same code, but dropping the parts dedicated to the name and fixing an inconsistency.
In Pursuing Tom Ram, a value of 0 means no valid verb, but first verb has an index of 0. So I had do remember to decrement verb (and name) indexes by one before used them.
I fixed it in this game. Desert uses a $ff value to indicate an invalid verb. Hope you think this solution is better.
TokenizeVerb
; Token has to be in $Token cvector
; This subroutine returns the index of the token in a
; First verb is index 0; a verb_index = $FF means not found
ldy #$FF ; This vaklue means no valid verb
sty verb_index
iny
@F_Loop
lda verb_tokens,y
beq @F_Exit ; N
cmp verb
bne @Next1
iny
lda verb_tokens,y
cmp verb+$1
bne @Next2
lda verb+$1
tya
lsr
sta verb_index
@F_Exit
; a = 0 not found means, other found
rts
@Next1
iny
@Next2
iny
jmp @F_Loop
You read about techniques for working with the half of a byte and even with individual bits in the guide about Pursuing Tom Ram. If you do not remember that part of the guide or you skipped it, here you will find some ideas.
Desert reuses the code for the flags from Pursing Tom Ram. In addition, it uses more flags. Desert uses a flag for each item, to know if player carries the object or not. There are no hidden objects in Desert, although there is one object that can be destroyed.
The code for handling the flags is the same as in the Pursuing tom Ram adventure. You can see that code below.
;---Flag subriotines --------------------
set_x_y
; Innter subroutine
ldx #$0
tya
and masks+$3
beq set_rts
inx
tya
sec
sbc #$8
tay
set_rts
rts
set_flag_y
jsr set_x_y
lda flags,x
ora masks,y
sta flags,x
rts ; Acumulador
clear_flag_y
jsr set_x_y
lda masks,y
eor #$FF ; Invierto la mask
and flags,x
sta flags,x
rts ; Acumulador
read_flag_y
; a - bit of the flag
; 0, not set
; no 0, set
jsr set_x_y
lda flags,x
and masks,y
rts ; Acumulador
In a previous section, I told you that I use 4 bits to indicate the context of a location. Something has to happen in a location: showing a text message, allow player to perform some actions (like drinking or taking an object), etc.
So I store a vector with the subroutines that executes the code for each location
v_locs WORD Loc_Empty, Loc_Birds, Loc_Oasis, Loc_Oasis_East, Loc_Ruk, Loc_Idol
WORD Loc_Vibrates, Loc_Flask, Loc_Scorpion, Loc_Compass, Loc_Found_Temple
WORD Loc_Ankh, Loc_Final, Loc_Enemy_North
I have to search in the map, the actual location and use this previous vector to execute the code of the current loc.
Subroutine PrintLOC prints nothing (bad name).- Instead it does this work. First, it checks if player is in temple (I will explain it in the future), then, calculate the index in the map from the X and Y of the player, uses the index to recover the content of the loc and stores it in current_loc_type.
;--------------------------
; Wrong name for a subroutine
; This one prints nothing
; instead, it calculate the content of the LOC
; and stores it current_loc_type
; It is very usefull
PrintLOC
; check if player is in the temple
lda player_x
cmp #$10 ; This number is not in map
bne @Not_in_Temple
jsr Loc_Temple
jmp MainLoop
@Not_in_Temple
; Calculate LOC number from x and y
jsr Return_LOC_in_X
; I use 4 bits for LOC content
; So I dicie LOC / 2
txa
tay
lsr
; Load LOC content
tax
lda row00,x
tax
; Load again LOC number to see
; if it is pair or odd
; To see whcih part of the byte use
tya
and #%00000001
bne @LOC_is_odd ; odd
; par
txa
lsr
lsr
lsr
lsr
jmp @Exit
@LOC_is_odd
txa
and #%00001111
@Exit
; Saves current LOC type
sta current_loc_type
rts
I calculate the index from the X and Y of the player in the subroutine Return_LOC_in_X
Remember one important thing you learnt in the guide about Pursuing Tom Ram. I am using half of a byte to store the content of the LOC, so a position from the vector (a byte) has two locs. If loc is odd I use the lower part of the byte but if it is no, I have to use the higher part.
The simplest location is Empry_Loc. There is nothing in this loc, so I print a message and nothing else. Here is the code.
Print_You_Are
lda #str_you_are
jsr PRTSTR
rts
;---------
Loc_Empty
jsr Print_You_Are
lda #str_lost_loc0
jsr PRTSTR
jsr CR
rts
Other locs that just print messages are: Loc_Birds, Loc_Oasis, Loc_Oasis_East