The Level Names
- THE BOUNCING HEDGEHOGS
- THE WILY WALLABIES
- THE KILLER BEES
- ALL THAT BOUNCES
- THE SWARM
- SPRING AND STING
- NIGHTMARE PARK
- ABANDON ALL HOPE!
The Routine
Keep in mind hexadecimal is used here
(Skoolkit
syntax is e.g. $4000
which is equivalent to address 16384
).
Data
The data structure is rigid; each level contains one attribute byte and three lines containing nine characters.
; Messaging: Level Names
;
; Level 1.
@label=Messaging_Level1
t$BBA0 DEFB $42 ; Attribute INK: RED, PAPER: BLACK (BRIGHT).
$BBA1 DEFM " THE " ; {#UDGTABLE(default,centre)
$BBAA DEFM "BOUNCING " ; { #FONT:( THE )$3D00,attr=$42(level-01-01) }
$BBB3 DEFM "HEDGEHOGS" ; { #FONT:(BOUNCING )$3D00,attr=$42(level-01-02) }
; { #FONT:(HEDGEHOGS)$3D00,attr=$42(level-01-03) }
; UDGTABLE#}
; Level 2.
@label=Messaging_Level2
$BBBC DEFB $45 ; Attribute INK: CYAN, PAPER: BLACK (BRIGHT).
$BBBD DEFM " THE " ; {#UDGTABLE(default,centre)
$BBC6 DEFM " WILY " ; { #FONT:( THE )$3D00,attr=$45(level-02-01) }
$BBCF DEFM "WALLABIES" ; { #FONT:( WILY )$3D00,attr=$45(level-02-02) }
; { #FONT:(WALLABIES)$3D00,attr=$45(level-02-03) }
; UDGTABLE#}
; Level 3.
@label=Messaging_Level3
$BBD8 DEFB $46 ; Attribute INK: YELLOW, PAPER: BLACK (BRIGHT).
$BBD9 DEFM " THE " ; {#UDGTABLE(default,centre)
$BBE2 DEFM " KILLER " ; { #FONT:( THE )$3D00,attr=$46(level-03-01) }
$BBEB DEFM " BEES " ; { #FONT:( KILLER )$3D00,attr=$46(level-03-02) }
; { #FONT:( BEES )$3D00,attr=$46(level-03-03) }
; UDGTABLE#}
; Level 4.
@label=Messaging_Level4
$BBF4 DEFB $50 ; Attribute INK: BLACK, PAPER: RED (BRIGHT).
$BBF5 DEFM " ALL " ; {#UDGTABLE(default,centre)
$BBFE DEFM " THAT " ; { #FONT:( ALL )$3D00,attr=$50(level-04-01) }
$BC07 DEFM " BOUNCES " ; { #FONT:( THAT )$3D00,attr=$50(level-04-02) }
; { #FONT:( BOUNCES )$3D00,attr=$50(level-04-03) }
; UDGTABLE#}
; Level 5.
@label=Messaging_Level5
$BC10 DEFB $70 ; Attribute INK: BLACK, PAPER: YELLOW (BRIGHT).
$BC11 DEFM " THE " ; {#UDGTABLE(default,centre)
$BC1A DEFM " SWARM " ; { #FONT:( THE )$3D00,attr=$70(level-05-01) }
$BC23 DEFM " " ; { #FONT:( SWARM )$3D00,attr=$70(level-05-02) }
; { #FONT:( )$3D00,attr=$70(level-05-03) }
; UDGTABLE#}
; Level 6.
@label=Messaging_Level6
$BC2C DEFB $56 ; Attribute INK: YELLOW, PAPER: RED (BRIGHT).
$BC2D DEFM " SPRING " ; {#UDGTABLE(default,centre)
$BC36 DEFM " AND " ; { #FONT:( SPRING )$3D00,attr=$56(level-06-01) }
$BC3F DEFM " STING " ; { #FONT:( AND )$3D00,attr=$56(level-06-02) }
; { #FONT:( STING )$3D00,attr=$56(level-06-03) }
; UDGTABLE#}
; Level 7.
@label=Messaging_Level7
$BC48 DEFB $44 ; Attribute INK: GREEN, PAPER: BLACK (BRIGHT).
$BC49 DEFM "NIGHTMARE" ; {#UDGTABLE(default,centre)
$BC52 DEFM " PARK " ; { #FONT:(NIGHTMARE)$3D00,attr=$44(level-07-01) }
$BC5B DEFM " " ; { #FONT:( PARK )$3D00,attr=$44(level-07-02) }
; { #FONT:( )$3D00,attr=$44(level-07-03) }
; UDGTABLE#}
; Level 8.
@label=Messaging_Level8
$BC64 DEFB $D6 ; Attribute INK: YELLOW, PAPER: RED (BRIGHT) FLASH: ON.
$BC65 DEFM " ABANDON " ; {#UDGTABLE(default,centre)
$BC6E DEFM " ALL " ; { #FONT:( ABANDON )$3D00,attr=$D6(level-08-01) }
$BC77 DEFM " HOPE! " ; { #FONT:( ALL )$3D00,attr=$D6(level-08-02) }
; { #FONT:( HOPE! )$3D00,attr=$D6(level-08-03) }
; UDGTABLE#}
Fetching The Current Level Name
The routine finds the level data using this formula:
\( LevelData = 48032 + (CurrentLevelNumber * 28) \)
Obviously given this is z80 assembly, which does not have multiplication built-in, the code has to do this manually with addition.
; Print Level Name
;
; #UDGTABLE(default,centre)
; { #PUSHS #SIM(start=$75AA,stop=$7638)#SIM(start=$74DC,stop=$7518)
; #SCR$02(game) #POPS }
; UDGTABLE#
;
; This looks confusing, but it's basically #REGhl=#N$BBA0+(level*#N$1C).
;
; --------------------------------------------------------
; | Level | Address | Attribute | Level Name |
; |-------|---------|-----------|------------------------|
; | $00 | $BBA0 | $42 | THE BOUNCING HEDGEHOGS |
; | $01 | $BBBC | $45 | THE WILY WALLABIES |
; | $02 | $BBD8 | $46 | THE KILLER BEES |
; | $03 | $BBF4 | $50 | ALL THAT BOUNCES |
; | $04 | $BC10 | $70 | THE SWARM |
; | $05 | $BC2C | $56 | SPRING AND STING |
; | $06 | $BC48 | $44 | NIGHTMARE PARK |
; | $07 | $BC64 | $D6 | ABANDON ALL HOPE! |
; --------------------------------------------------------
@label=PrintLevelName
c$74DC LD A,($7820) ; Fetch the current level and store it in #REGa.
$74DF ADD A,A ; {Multiply it by 4 and store the result in #REGl (level*04).
$74E0 ADD A,A ;
$74E1 LD L,A ; }
$74E2 ADD A,A ; Multiply it again by 2 and store this in #REGh (level*08).
$74E3 LD H,A ; }
$74E4 ADD A,A ; {Multiply it again by 2 (level*16), add this together
$74E5 ADD A,H ; with #REGh, #REGl and 160 and the store the result in
$74E6 ADD A,L ; #REGl.
$74E7 ADD A,$A0 ;
$74E9 LD L,A ; }
$74EA LD A,$00 ; {#REGh=187+carry.
$74EC ADC A,$BB ;
$74EE LD H,A ; }
All level names are printed in the same place.
$74EF LD DE,$5A57 ; #REGde=#N$5A57 (attribute buffer location).
$74F2 LD C,$03 ; #REGc=#N$03 (line counter; all levels are three lines).
@label=LevelName_AttributeLineLoop
*$74F4 LD A,(HL) ; Fetch the attribute byte and store it in #REGa.
$74F5 LD B,$09 ; #REGb=#N$09 (character counter; all lines contain nine characters).
@label=LevelName_AttributeLoop
*$74F7 LD (DE),A ; Write the attribute byte to the attribute buffer.
$74F8 INC E ; Move one character block right.
$74F9 DJNZ $74F7 ; Decrease the character counter by one and loop back to
; LevelName_AttributeLoop until the counter is zero.
; Move down one line and reset the position; 9 + 23 = 32 (i.e. one full line).
$74FB LD A,E ; {#REGe+=23.
$74FC ADD A,$17 ;
$74FE LD E,A ; }
$74FF DEC C ; Decrease the line counter by one.
$7500 JR NZ,$74F4 ; Jump to LevelName_AttributeLineLoop until the line counter is zero.
--- title: "Subroutine: Set Attributes For Colouring The Level Name" --- flowchart TD; DE["DE=23127 (in the attribute buffer)"]-->C["C=03 (line counter)"]; C-->A[A=Attribute byte from HL]; A-->B["B=09 (number of characters in each line)"]; B-->Write["Write the attribute byte to DE (attribute buffer pointer)"]; Write-->E E["DE+=1 (move the attribute buffer pointer right)"]-->Loop_B Loop_B[Decrease the character counter by one until it is zero]-->Write Loop_B-->|All character blocks have been processed for this line|Loop_C Loop_C[Decrease the line counter by one until it is zero]-->A Loop_C-->|All lines have processed|End
Then similarly, print the characters to the screen buffer.
$7502 INC L ; Move #REGhl to the start of the level string data.
$7503 EXX ; Switch to the shadow registers.
$7504 LD DE,$5057 ; #REGde'=#N$5057 (screen buffer location).
$7507 EXX ; Switch back to the normal registers.
$7508 LD C,$03 ; #REGc=#N$03 (line counter; all levels are three lines).
@label=PrintLevelName_Loop
*$750A LD B,$09 ; #REGb=#N$09 (character counter; all lines contain nine characters).
$750C CALL $74D3 ; Call Print_Loop.
; Move down one line (and reset the position - #N$09+#N$17=#N$20).
$750F EXX ; Switch to the shadow registers.
$7510 LD A,E ; {#REGe'+=23.
$7511 ADD A,$17 ;
$7513 LD E,A ; }
$7514 EXX ; Switch back to the normal registers.
; Have we printed all three lines of the level name yet?
$7515 DEC C ; Decrease the line counter by one.
$7516 JR NZ,$750A ; Jump to PrintLevelName_Loop until #REGc is zero.
$7518 RET ; Return.
--- title: "Subroutine: Printing The Level Name To The Screen Buffer" --- flowchart TD; L[HL=Start of the level string data]-->|Shadow Registers|DE DE["DE'=20567 (in the screen buffer)"]-->|Normal Registers|C["C=03 (line counter)"]; C-->Print_Loop; Print_Loop["Call Print_Loop subroutine (uses B=09)"]-->|Shadow Registers|E E["DE'+=23 (Move down one line in the screen buffer)"]-->|Normal Registers|Loop_C Loop_C[Decrease the line counter by one until it is zero]-->Print_Loop Loop_C-->|All level data has been printed to the screen|Ret[Return]