; Stardodger By Stewart C. Russell
; Z80 Assembly Version
; Standard AMSDOS Equates
gra_initialise equ &bbba
gra_move_abs equ &bbc0
gra_move_rel equ &bbc3
gra_line_rel equ &bbf9
gra_set_pen equ &bbde
gra_test_rel equ &bbf3
gra_wr_char equ &bbfc
scr_initialise equ &bbff
scr_set_ink equ &bc32
scr_set_border equ &bc38
scr_set_mode equ &bc0e
km_initialise equ &bb00
km_read_key equ &bb1b
km_test_key equ &bb1e
txt_initialise equ &bb4e
txt_output equ &bb5a
txt_set_cursor equ &bb75
kl_time_set equ &bd10
kl_time_please equ &bd0d
org &5000
.start call su ; The game itself
call su ; Set up colours, etc.
.oloop call tiscr ; Print title screen
.loop1 call drawscr1 ; Draw screen box
call plot ; Plot stars
ld de,2
ld hl,200
call gra_move_abs ; Move to start position
.contscr call shift ; Test if SHIFT is pressed
ld a,3
call haudon ; 0.01 second delay
ld a,(dy) ; Get result of SHIFT test
cp 4 ; Should it go up?
jr nz,down ; Draw it down if it isn't
ld hl,4
ld de,4
call gra_line_rel ; Draw line upwards
.doline call test ; Have we hit anything?
ld a,(col) ; Get result of collision test
cp 1 ; Is it white?
jr z,lost ; If it is, end game
cp 3 ; Have we hit the gap?
jr z,next ; If so, go to next screen
jr contscr ; Continue the screen if neither
.lost call losscr ; Print 'You Goofed' etc...
ld a,1
ld (scr),a ; First screen number = 1
ld hl,5
ld (q),hl ; First no. of starts = 5
ld a,4
ld (dy),a ; Initial direction = up
jr oloop ; Go back to start of outer loop
.next call wonscr ; Print 'Well Done' etc...
jr loop1 ; Go to the next screen
.down ld hl,-4
ld de,4
call gra_line_rel ; Draw line downwards
jr doline
; Draws the lines for the playing screen
.drawscr1 ld a,1
call scr_set_mode ; MODE 1
ld a,1
call gra_set_pen ; GRAPHICS PEN 1
ld de,629
ld hl,0
call gra_line_rel ; DRAWR 629,0
ld de,0
ld hl,170
call gra_line_rel ; DRAWR 0,170
ld de,0
ld hl,60
call gra_move_rel ; MOVER 0,60
ld de,0
ld hl,169
call gra_line_rel ; DRAWR 0,169
ld de,-629
ld hl,0
call gra_line_rel ; DRAWR -629,0
ld de,0
ld hl,-399
call gra_line_rel ; DRAWR 0,-399
ld de,0
ld hl,2
call gra_move_rel ; MOVER 0,2
ld de,627
ld hl,0
call gra_line_rel ; DRAWR 627,0
ld de,0
ld hl,168
call gra_line_rel ; DRAWR 0,168
ld de,0
ld hl,60
call gra_move_rel ; MOVER 0,60
ld de,0
ld hl,167
call gra_line_rel ; DRAWR 0,167
ld de,-625
ld hl,0
call gra_line_rel ; DRAWR -625,0
ld de,0
ld hl,-399
call gra_line_rel ; DRAWR 0,-399
ld a,3
call gra_set_pen ; GRAPHICS PEN 3
ld de,637
ld hl,0
call gra_move_abs ; MOVE 637,0
ld de,0
ld hl,400
call gra_line_rel ; DRAWR 0,400
ld de,2
ld hl,0
call gra_move_rel ; MOVER 2,0
ld de,0
ld hl,-400
call gra_line_rel ; DRAWR 0,-400
ld a,1
call gra_set_pen ; GRAPHICS PEN 1
ret
; Returns A = 0 and NC if no key
; key no. and C if ok
.keyvalid or a ; Clear carry flag
call km_read_key
ret c ; Return if we have a key
xor a ; Clear accumulator to 0
ret
; Prints string addressed by DE at text position H,L
; String must end with zero byte
.prts push af
push hl
push de ; Save AF, HL & DE registers
call txt_set_cursor ; Set cursor to H,L
pop de ; Get string address
.pl ld a,(de) ; Get character
inc de ; Increment string pointer
or a ; Is character zero?
jr z,pret ; Go to pret if it is
call txt_output ; Print it
jr pl ; Loop to start of routine
.pret pop hl
pop af ; Restore HL & AF registers
ret
; Pauses until a key is pressed
.waitkey push af
.w call keyvalid ; Loop while key pressed
jr c,w ; to clear buffer
.u call keyvalid
jr nc,u ; Loop until key pressed
pop af
ret
; Pauses for A/300ths of a second
.haudon push de
push hl
push af
ld de,0
ld hl,0
call kl_time_set ; Reset clock
pop af ; Get pause length
.tl call kl_time_please ; Get time
cp l ; Is it equal to value in A?
jr nz,tl ; Loop while it isn't
pop hl
pop de
ret
; Get SHIFT state and return 4 or -4 in (dy)
.shift push af
push hl
push bc
ld a,21
call km_test_key ; Has SHIFT been pressed?
jr nz,yep ; If so, go to yep
ld a,-4
.nup ld (dy),a ; Store value of key test
pop bc
pop hl
pop af
ret
.yep ld a,4 ; Positive line increment
jr nup
; Prints 'Press any key to continue' at 8,25
.waitmess ld hl,&0819
ld de,paktc
call prts
ret
; Print the title screen
.tiscr ld a,1
call scr_set_mode ; MODE 1
ld hl,&1001
ld de,sdr
call prts ; Print title
ld hl,&0105
ld de,avoi
call prts ; Print instructions 1
ld hl,&0906
ld de,wond
call prts ; Print instructions 2
ld hl,&0c0d
ld de,uses
call prts ; Print key to use
call waitmess
call waitkey ; Wait for a keypress
; Prints A in HEX
.prta push af
push bc
ld b,2 ; Loop counter for two nibbles
ld c,a ; Store A
rra
rra
rra
rra
.gnyb and &f ; Get nibble
cp &a ; Is it > = 10?
jr nc,hex ; If so, go to hex
add a,&30 ; convert to ASCII char 0-9
.prn call txt_output ; Print it
ld a,c
djnz gnyb ; Act on lower nibble
pop bc
pop af
ret
.hex add a,&37 ; Convert to ASCII char A-F
jr prn
; Test point relative (2,dy/2) and returns in (col)
.test push bc
push de
push hl
ld a,(dy) ; Get player's line direction
cp 4 ; Is the line currently going up?
jr nz,n4 ; Go to n4 if it isn't
ld hl,2 ; Use relative co-ords (2,2) for
ld de,2 ; test if going up.
.ctest push hl
call gra_test_rel ; Test point relative to line end
ld (col),a ; Store INK result
pop hl
call nhl ; Negate HL value
ld de,-2 ; Move graphics cursor back
call gra_move_rel ; to original position.
pop hl
pop de
pop bc
ret
.n4 ld hl,-2
ld de,2 ; Use reletive co-ords (2,-2)
jr ctest ; for test if going up
; Negate HL value
.nhl push af
ld a,h
cpl
ld h,a ; Complement H
ld a,l
neg
ld l,a ; Negate L
pop af
ret
; Prints success screen
.wonscr ld a,1
call scr_set_mode ; MODE 1
ld hl,&1001
ld de,well
call prts ; PRINT "Well Done"
ld hl,&090d
ld de,stan
call prts ; Print next screen message
ld a,(scr) ; Get next screen number
call prta ; Print screen number in HEX
call waitmess
call waitkey ; Press any key to continue
ret
; Prints lose screen
.losscr ld a,1
call scr_set_mode ; MODE 1
ld hl,&1001
ld de,youg
call prts ; PRINT "You Goofed"
ld hl,&040d
ld de,numb
call prts ; Print number completed message
ld a,(scr) ; Get no. of next screen
dec a
dec a ; Reduce it to screens completed
call prta ; Print no. of screens completed
call waitmess
call waitkey ; Press any key to continue
ret
; Returns a psuedo-random integer in HL
.random push af
push bc
ld hl,(seed) ; Get seed
push hl ; Save it onto stack
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl ; HL = seed x 256
pop bc ; get original seed
add hl,bc ; Add seed to (seed x 256)
ld bc,41
add hl,bc ; Add 41 to result for fun of it!
ld a,r ; Get value of memory refresh
add l ; Add low byte of random result
ld l,a ; Return this value to HL
pop bc ; Restore BC
adc hl,bc ; Add BC to HL (fiddle factor)
ld (seed),hl ; Store result for later use
pop af ; Restore AF
ret
; Remainder routine, returns HL = HL mod DE
.rem or a ; Clear carry flag
sbc hl,de ; Is DE > HL?
add hl,de ; restore HL
ret c ; Return if DE > HL
sbc hl,de ; HL = HL - DE (-0 in carry flag)
jr rem ; Recurse to start
; Plots the relevant number of asterixs
; Keeps track of screen no. and no. of stars
; in scr (byte) and q (word) respectively.
.plot push af
push bc
push de
push hl
ld hl,(q) ; Get number of asterisks
.pltlp push hl ; Save loop counter
call random ; Get random number in HL
ld de,561
call rem ; HL = HL mod 561
ld de,50 ; Add 50 to it to allow for
add hl,de ; initial reaction time
push hl ; Save x co-ord
call random ; Get random number for y co-ord
ld de,361
call rem ; HL = HL mod 361
ld de,20
add hl,de ; Add 20 for tidyness
pop de
call gra_move_abs ; Move to the random position
ld a,'*'
call gra_wr_char ; Write a * at that position
pop hl ; Get loop counter
dec hl ; Decrement it
ld a,h
or l ; Is it zero?
jr nz,pltlp ; Loop if not
ld a,(scr) ; Get screen no.
inc a ; Increment screen no.
ld (scr),a ; Restore new screen no.
ld hl,(q) ; Get number of asterisks
inc hl
inc hl
inc hl
inc hl
inc hl
ld (q),hl ; Set no. of stars (scr x 5)
pop hl
pop de
pop bc
pop af
ret
; Set up MODE, colours, etc...
.su ld a,1
call scr_set_mode ; MODE 1
call txt_initialise
call km_initialise
call gra_initialise
call scr_initialise
xor a
ld b,a
ld c,a
call scr_set_ink ; INK 0,0,0
ld a,1
ld b,26
ld c,b
call scr_set_ink ; INK 1,26,26
ld a,3
ld b,0
ld c,b
call scr_set_ink ; INK 3,0,0
xor a
ld b,a
ld c,a
call scr_set_border ; BORDER 0,0
ret
; Static variables and strings
.dy defb 4
.col defb 0
.scr defb 1
.paktc defm 'Press any key to continue.',0
.sdr defm 'Stardodger',0
.avoi defm 'Avoid the killer Asterisqs, and seek the',0
.wond defm 'wondrous Nextscreen Gap.',0
.uses defm 'Use SHIFT to climb',0
.well defm 'Well Done!',0
.stan defm 'Stand by for screen ',0
.youg defm 'You Goofed',0
.numb defm 'Number of screens completed = ',0
.seed defw &abcd
.q defw 5
NOTICE TEXTE n° 2 (3.89 Ko)
Stardodger III - the assembler version
Author : Stewart Russell
Publisher : Amstrad Computer User November 1988
Stewart Russell shows you how to program the same game three times in three very
different languages
BCPL produced a game that would be fast enough for anyone, but was about 10K
long. This seemed quite excessive, so a non-singing, non-dancing compact game
in Z80 code was developed in assembly language.
Assembly language programming is quite a different kettle of fish from Basic or
BCPL, with absolutely no safety net provided for the unwary. Simple housekeeping
tasks such as printing a string have to be written by the author and these can
frequently prove to be the most difficult bits.
Again, the Basic Stardodger served as the template for this model, with slight
differences. The screen numbers in this version are printed in hexadecimal simply
because a hex routine is shorter to write than a decimal one.
Reasonable care has been taken that each routine does not corrupt registers
unnecessarily. This wastes space in the form of PUSHes and POPs, but the approach
is preferable to a possible system crash.
The random routine and the screen drawing routine could both be made shorter, but
they work, this being of the utmost importance. Results of tests were not generally
returned in registers but in memory locations, because it is all too easy to corrupt
a register by mistake.
The listing was produced using the Maxam rom, so the long label names may cause
problems for ADAM, Devpac, Zapp and Code Machine users, but are there to increase
readability. Check your manuals to see how label names should be entered into your
particular assembler.
Your reward for all of this effort? A paltry 937 bytes of code. This can be saved
by hopping into Basic and typing:
+----------------------------------+
| SAVE"STARDOJ",B,&5000,&3A9,&5000 |
+----------------------------------+
Some People may find this Assembler version a bit fast. Remedy this by changing part
of the START subroutine from LD A,3:CALL HAUDON to LD A,value:CALL HAUDON where value
can take any value from zero to 255 - 3 (default),4,5 or 6 (very slow) are the best
ones to use. HAUDON, incidentally, is Glaswegian for "hold on".
Conclusions
-----------
If there has to be a conclusive winner in the general niceness stakes, BCPL would take
it by a short head. It was as simple as the Basic version to write, yet ran as quickly
as the Assembly version. Its only drawback was the length of the object file produced.
Producing the Assembly version was certainly challenging, but the effort involved
doesn't really justify the result.
Although coming last in the race, Basic provided the slow, good-natured workhorse from
which the tetchy thoroughbreds were descended.
My current record on both the BCPL and the Assembly versions is Screen 11. I've made it
through Screen 19 on the Basic one. Can you get further? Go forth, and dodge them stars!
A comparison of the main routines
+-------------------------------------------------------------------+
| | Basic | BBPL | Assembly |
|---------------------------+---------+---------+-------------------|
| Routine | lines | procs | procs |
| initialisation | 20-70 | start | su |
| Print title screen | 90-170 | start | tiscr |
| Draw game screen | 180-450 | drawscr | drawscr1, plot |
| Main game logic | 470-530 | start | start |
| Print game over screen | 550-600 | start | losscr |
| Print success screen | 620-680 | start | wonscr |
| Wait for keypress routine | 700-760 | waitkey | waitmess, waitkey |
+-------------------------------------------------------------------+