Desert

Game available in Itch.io.

Soruce code in Github.

Programming grid games in assembly for VIC-20.


Main loop

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.

Reading input

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.

Flags

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

  

Routing to locations

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.

Examples of location

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