Episode 9: +++ Progress Update (The End is Nigh) +++
Updates on work in progress …
Spending the final hours busily. By now, there are guided rocket missiles and missiles for the saucers. The AI is also fairly complete by now — and fully working. Hit detection and scoring are also done. All the building blocks for effects (spinning rocket and reverse video effect for a player's missile hitting a saucer, see previous episodes) are already in place. However, I'm still lacking the wrappers and control logic for them to make this a complete game. — Please check this site for updates.
Meanwhile: Hit detection pretty much done, a bit too tired to do the effect routines — calling it a day. We have the basic game mechanics working, while still lacking any effects! Going to finish this later. Sorry. — However, we've achieved some, stay tuned for a wrap-up.
Currently, there's a tiny bug in the collision-detection which I'm currently not able to spot. The hit detection issue was really a simple one, some hours of sleep provided. With reset routines and scoring already in place, we could simply disable the rocket at time-wrap, if the players score doesn't exceed the scaucers' score. This way, we would have already a fully playable game, while still lacking bells, whistles, and polish. — Just so short from somehow reaching the finish line …
Overall, while I haven't finished and polish the game in time, it's a proof of concept for things like this being done on the PET. (Where's Asteroids? Where's Spacewar? It can be done!) I'm rather suprised by how well some of the motions work in isolation — while too much of them are prone to a more cluttery experience. Especially with a bit more of experience — did I mention that I haven't touched the 6502 for more than 30 years? — and by going for ROM 2 and ROM 4 exclusively (are there any real, existing ROM 1.0 machines?), hence dropping the bottleneck of updating the screen during V-BLANK only, some really aracady games, other than Space Invaders, can be done on the PET.
+++ MISSION UPDATE +++ missiles implemented for rocket ship and saucer +++ stop +++ guided missile logic for player's shots final +++ stop +++ +++ sub-character-mapping for missiles fully implemented (including overlap) +++ stop +++ saucer AI (targeting) complete +++ stop +++ hit detection, scoring and reset routines pretty much done +++ effect wrappers still in the making +++ stop +++ also to be done: a bit of polishing (e.g., 'press any key to start' message, etc.) +++ stop +++
Statistics: Lines of Code (LOC) .......... 2,229 Bytes assembled .............. 4,790
Note: There still seem to be minor quirks in the collision detection. :-/
▶ See the final state of affairs, as for RC2017/04, in in-browser emulation.
Note: Previously, this link didn't set the flag to disable the keyboard repeat in the emulator, rendering the game rather unresponsive. — Bummer.
▶ See this link for the game in the current state of ongoing development.
Code Listing
; Personal Computer Space Transactor 2001 (work in progress) ; by Norbert Landsteiner, 2017 ; (a project for RetroChallenge 2017/04) ; Original Computer Space arcade game (c) 1971 Nutting Associates, Inc. ; by Nolan Bushnell and Ted Dabney. !to "missiles.prg", cbm ;set output file and format ; symbols / constants screenCols = 40 ;number of screen columns: 40/80 (only 40 cols tested) ticksPerSecond = 60 ;60: time in game corresponds to NTSC timing charQueue = $027A ;start of cassette buffer, used as a drawing buffer resetQueue = charQueue+60 ;buffer for screen resets maxX = 45 ;x-coors max value maxY = 28 ;y-coors max value rocketFreq = 12 ;frames (update frequency, responsiveness) saucerFreq = 8 ;frames (update frequency, speed) saucerOffset = 14 ;screen lines y offset (maxY/2) rocketVMax = 40 ;max velocity fractional value missileLife = 100 ;frames saucerCooling = 80 ;frames ; zero-page ; BASIC input buffer at $23 .. $5A may be reused safely (cf, PET 2001 manual) gameState = $23 ;0: attract, 1: active fIRQ = $24 ;flag to synchronize irq operations fRepaint = $25 ;flag for video rendering/irq control ticks = $26 ;ticks counter videoMask = $27 ;0: normal, $80: reverse (xor-ed) IRQVector = $28 ;backup of original irq vector (2 bytes) newRom = $2A ;flag ROM 1.0 (0) / ROM 2.0+ (1) qPosX = $2B ;temp x coor for display purpose qPosY = $2C ;temp y coor for display purpose qScreenCode = $2D ;temp screen code for display purpose charQueuePtr = $2E ;pointer to top offset of charQueue resetQueuePtr = $2F ;pointer to top offset of charQueue scoreRepaint = $30 ;flag to request a repaint (buffer to fRepaint) frameCounter = $31 ;counter for animations ran = $32 ;random number (1 byte) fReset = $33 tmp = $34 PT1 = $50 ;versatile pointer (2 bytes) PT2 = $52 ;versatile pointer (2 bytes) IPT1 = $54 ;versatile pointer for interrupt tasks (2 bytes) IPT2 = $56 ;versatile pointer for interrupt tasks (2 bytes) ; intro ; insert a tiny BASIC program, calling our code at $044C (1100) ; ; 10 REM PERSONAL COMPUTER SPACE ; 20 REM TRANSACTOR 2001, V.0.2, 2017 ; 30 SYS 1103 * = $0401 !byte $1F, $04, $0A, $00, $8F, $20, $50, $45 ; $0401 !byte $52, $53, $4F, $4E, $41, $4C, $20, $43 ; $0409 !byte $4F, $4D, $50, $55, $54, $45, $52, $20 ; $0411 !byte $53, $50, $41, $43, $45, $00, $42, $04 ; $0419 !byte $14, $00, $8F, $20, $54, $52, $41, $4E ; $0421 !byte $53, $41, $43, $54, $4F, $52, $20, $32 ; $0429 !byte $30, $30, $31, $2C, $20, $56, $2E, $30 ; $0431 !byte $2E, $32, $2C, $20, $32, $30, $31, $37 ; $0439 !byte $00, $4D, $04, $1E, $00, $9E, $20, $31 ; $0441 !byte $31, $30, $33, $00, $00, $00 ; $0449 .. $044E ; main * = $044F ; reset / setup cld ;reset BCD flag lda #0 sta fRepaint setup ; setup irq vector sei lda $91 and #$F0 cmp #$E0 ;is it ROM 2.0 or higher? bne .rom1 ;no, it's ROM 1.0 .rom2 lda $90 sta IRQVector lda $91 sta IRQVector+1 lda #<irqRoutine sta $90 lda #>irqRoutine sta $91 lda #1 sta newRom jmp .setupDone .rom1 lda $219 sta IRQVector lda $21A sta IRQVector+1 lda #<irqRoutine sta $219 lda #>irqRoutine sta $21A lda #0 sta newRom .setupDone cli title jsr drawTitleScreen jsr readKbd ; reset the keyboard lda #1 sta fIRQ titleLoop lda fIRQ bne titleLoop jsr readKbd cmp #0 bne init lda #1 sta fIRQ jmp titleLoop init lda #0 sta gameState sta videoMask sta fRepaint jsr background lda #0 sta score1 sta score2 sta time1 sta time2 sta ticks sta frameCounter sta charQueuePtr sta saucerCnt sta saucerLegCnt sta rocketCnt lda #1 sta saucerState lda $E844 ; initialize random number from VIA timer 1 sta ran jsr readKbd ; reset the keyboard lda #10 sta saucerY lda #18 sta saucerX jsr displaySaucer jsr animateSaucer jsr displaySaucerCenter lda #3 sta rocketDir lda #10 sta rocketX lda #12 sta rocketY lda #1 sta fRepaint sta fIRQ ; main job loop loop lda fIRQ bne loop lda #0 ;reset top-of-queue pointers sta charQueuePtr sta resetQueuePtr sta fReset lda gameState bne .gameRunning .attractMode lda rocketCnt cmp #30 beq .amkbd jsr readKbd ;reset keyboard inc rocketCnt bpl .gameFrame .amkbd jsr readKbd cmp #0 beq .gameFrame lda #0 sta ticks sta rocketCnt inc gameState inc rocketState jsr displayRocket .gameRunning ;manage a frame lda #0 sta scoreRepaint lda ticks ;manage time sec sbc #ticksPerSecond ;has a second passed? bcc .gameFrame ;no sta ticks inc time1 lda time1 cmp #$0A bne .loopScoresFinal lda #0 sta time1 inc time2 lda time2 cmp #$0A bne .loopScoresFinal lda #0 sta time2 jsr revertVideo .loopScoresFinal lda #1 sta scoreRepaint .gameFrame jsr checkCollisions lda fReset bne .loopIter jsr rocketHandler jsr saucerHandler .loopIter sei lda scoreRepaint ora resetQueuePtr ora charQueuePtr sta fRepaint .loopEnd lda #1 sta fIRQ cli jmp loop ; irq handling irqRoutine pha ;save registers txa pha tya pha inc ticks ;manage time inc frameCounter .checkRepaint lda fRepaint beq .irqDone jsr drawResetQueue jsr drawScores jsr drawCharQueue .irqDone lda #0 sta fRepaint sta fIRQ pla ;restore register tay pla tax pla jmp (IRQVector) ; subroutines readKbd ;reads a character from keyboard, returns char in AC (0 = empty) lda newRom beq .rkbdRom1 .rkbdRom2 ldx $9E ;get # of chars in keyboard buffer beq .kbdEmpty lda $026E,x ;get char from buffer ldx #$FF ;reset keboard matrix stx $97 ; for key repeat ldx #0 ;reset index of keyboard buffer stx $9E ; to clear the queue rts .rkbdRom1 ldx $020D ;same as above for ROM 1.0 beq .kbdEmpty lda $020E,x ldx #$FF stx $0203 ldx #0 stx $020D rts .kbdEmpty lda #0 rts background ;fills the screen with stars ldx #24 .row lda screenLinesLo, x sta PT1 lda screenLinesHi, x sta PT1+1 ldy #39 .col jsr getStar sta (PT1), y dey bpl .col dex bpl .row rts getStar ;returns a background screen code (in AC) for row X, col Y lda starMaskY, x beq .blank and starMaskX, y beq .blank lda #$2E ; return a dot rts .blank lda #$20 ; return a blank rts ; score and time display ; screen locations of score and time numerals screenAddressScore1 = $8000 + 4*screenCols + 36 screenAddressScore2 = $8000 + 10*screenCols + 36 screenAddressTime1 = $8000 + 16*screenCols + 36 screenAddressTime2 = $8000 + 16*screenCols + 33 drawScores ;draws scores and time display ldy score1 lda #<screenAddressScore1 sta IPT1 lda #>screenAddressScore1 sta IPT1+1 jsr drawDigit ldy score2 lda #<screenAddressScore2 sta IPT1 lda #>screenAddressScore2 sta IPT1+1 jsr drawDigit ldy time1 lda #<screenAddressTime1 sta IPT1 lda #>screenAddressTime1 sta IPT1+1 jsr drawDigit ldy time2 lda #<screenAddressTime2 sta IPT1 lda #>screenAddressTime2 sta IPT1+1 jsr drawDigit rts drawDigit ;draws a digit (screen address in IPT1, digit in Y) ldx digitOffsets, y ldy #0 lda #4 sta IPT2 .dgRow lda digits, x eor videoMask ;adjust for normal/reverse video sta (IPT1), y inx iny lda digits, x eor videoMask sta (IPT1), y dec IPT2 beq .dgDone inx dey ;reset y to zero and increment IPT1 by a screen line clc lda IPT1 adc #screenCols sta IPT1 bcc .dgRow inc IPT1+1 jmp .dgRow .dgDone rts revertVideo ;reverts the screen video lda videoMask eor #$80 sta videoMask ldx #24 .rvRow lda screenLinesLo, x sta PT1 lda screenLinesHi, x sta PT1+1 ldy #39 .rvCol lda (PT1), y eor #$80 sta (PT1), y dey bpl .rvCol dex bpl .rvRow rts ; draws chars in charQueue of (screenCode, addrLo, addrHi)* ; self-modifying (sets address at .dcqScreen, sta xxxx) drawCharQueue ldx charQueuePtr ;get top-of-queue pointer beq .dcqDone ;exit, if empty dex .dcqLoop lda charQueue, x ;get screen address hi-byte sta .dcqScreen+2 ;fix-up dex lda charQueue, x ;get screen address lo-byte sta .dcqScreen+1 ;fix-up dex lda charQueue, x ;get screen code eor videoMask ;adjust for normal/reverse video .dcqScreen sta $ffff ;store it (dummy address) dex bpl .dcqLoop .dcqDone rts ; same as above, but for resetQueue drawResetQueue ldx resetQueuePtr beq .drqDone dex .drqLoop lda resetQueue, x sta .drqScreen+2 dex lda resetQueue, x sta .drqScreen+1 dex lda resetQueue, x eor videoMask .drqScreen sta $ffff dex bpl .drqLoop .drqDone rts ; a single character 'sprite routine' ; pushes a screen code and address onto the charQueue, if on-screen pushScreenCode lda qPosY bmi .pcqDone ;negative cmp #25 ;gte 25 (off-screen to the bottom)? bcs .pcqDone lda qPosX bmi .pcqDone ;negative cmp #40 ;gte 40 (off-screen to the right)? bcs .pcqDone ldx charQueuePtr lda qScreenCode sta charQueue, x inx ldy qPosY lda qPosX clc adc screenLinesLo, y sta charQueue, x inx lda #0 adc screenLinesHi, y sta charQueue, x inx stx charQueuePtr .pcqDone rts ; same as above,but for resetQueue pushScreenReset lda qPosY bmi .psrDone ;negative cmp #25 ;gte 25 (off-screen to the bottom)? bcs .psrDone lda qPosX bmi .psrDone ;negative cmp #40 ;gte 40 (off-screen to the right)? bcs .psrDone ldx resetQueuePtr lda qScreenCode sta resetQueue, x inx ldy qPosY lda qPosX clc adc screenLinesLo, y sta resetQueue, x inx lda #0 adc screenLinesHi, y sta resetQueue, x inx stx resetQueuePtr .psrDone rts random ; a simple random number generator lda ran ror lda ran ror eor %11011001 sta ran rts ; collisions checkCollisions lda rocketState ora saucerState bne .ccRS rts .ccRS lda rocketX sta PT1 lda rocketY sta PT1+1 lda saucerX sta PT2 lda saucerY sta PT2+1 ldx #2 ldy #2 jsr checkObjectCollison bcs .ccRocketMissiles jsr resetRocket jsr resetSaucer jsr resetMissiles jsr incScore1 jsr incScore2 rts .ccRocketMissiles lda rocketMissileCnt beq .ccSaucerMissile lda rocketMissileX sta PT1 lda rocketMissileY sta PT1+1 lda saucerX sta PT2 lda saucerY sta PT2+1 ldx #3 ldy #2 jsr checkObjectCollison bcs .ccSaucerMissile jsr resetSaucer jsr resetMissiles jsr incScore1 rts .ccSaucerMissile lda saucerMissileCnt beq .ccDone lda rocketX sta PT1 lda rocketY sta PT1+1 lda saucerMissileX sta PT2 lda saucerMissileY sta PT2+1 ldx #2 ldy #2 jsr checkObjectCollison bcs .ccDone jsr resetRocket jsr resetMissiles jsr incScore2 .ccDone rts incScore1 lda score1 clc adc #1 cmp #10 bne .incS1End lda #0 .incS1End sta score1 inc scoreRepaint rts incScore2 lda score2 clc adc #1 cmp #10 bne .incS2End lda #0 .incS2End sta score2 inc scoreRepaint rts ;PT1: x1, PT1+1: y1 ;PT2: x2, PT2+1: y2 ;X: epsilon-x, Y: epsilon-y ;returns abs x1-x2 < eX and abs y1-y2 < eY in carry checkObjectCollison stx tmp sec lda PT1 sbc PT2 bpl .cocXCmp eor #$FF clc adc #1 .cocXCmp cmp tmp bcs .cocDone sty tmp sec lda PT1+1 sbc PT2+1 bpl .cocYCmp eor #$FF clc adc #1 .cocYCmp cmp tmp .cocDone rts ; object resets resetRocket lda #1 sta fReset lda rocketState beq .rstr0 jsr clearRocket lda rocketThrusting beq .rstr0 jsr clearThrust .rstr0 lda #1 sta rocketState lda #0 sta rocketXLo sta rocketYLo sta rocketDx sta rocketDy sta rocketDxLo sta rocketDyLo sta rocketThrust jsr displayRocket rts resetSaucer lda #1 sta fReset lda saucerState beq .rsts0 jsr clearSaucer jsr clearSaucerCenter jsr flipSaucer jsr clearSaucer jsr clearSaucerCenter .rsts0 jsr random clc and #31 adc #16 clc adc rocketX cmp #maxX bcc .rstsX sec sbc #maxX .rstsX sta saucerX jsr random and #31 cmp #maxY bcc .rstsY sec sbc #saucerOffset .rstsY sta saucerY lda #1 sta saucerState lda #0 sta saucerDx sta saucerDy sta saucerPhase sta saucerPhaseDir sta saucerPhaseMask sta saucerCnt sta saucerLegCnt .rstsDone jsr displaySaucer jsr displaySaucerCenter jsr flipSaucer jsr displaySaucer jsr displaySaucerCenter jsr flipSaucer rts resetMissiles lda rocketMissileCnt beq .rstmScr jsr clearRocketMissile lda #0 sta rocketMissileCnt .rstmScr lda #saucerCooling sta saucerMissileCooling lda saucerMissileCnt beq .rstmDone jsr clearSaucerMissile lda #0 sta saucerMissileCnt .rstmDone rts ; saucer(s) saucerHandler lda saucerState bne .shInit rts .shInit dec saucerCnt bmi .shUpdate lda scoreRepaint ;do we have a score/time update? bne .shRedraw ;yes, redraw the saucers jmp .shAnimate ;just check the animation state .shRedraw jmp .shDisplay .shUpdate lda #saucerFreq sta saucerCnt jsr clearSaucer jsr flipSaucer jsr clearSaucer jsr flipSaucer dec saucerLegCnt bpl .shMoveY jsr random and #15 clc adc #7 sta saucerLegCnt lda ran and #1 sta saucerPhaseDir ldx #3 lda ran bpl .shAnimSpeed ldx #7 .shAnimSpeed stx saucerPhaseMask jsr random and #$3F beq .shStop and #3 cmp #3 bne .shSaveDx lda #0 .shSaveDx sta saucerDx jsr random and #3 cmp #3 bne .shSaveDy lda #0 .shSaveDy sta saucerDy .shMoveY ldx saucerY lda saucerDy beq .shMoveX cmp #1 beq .shMoveY1 inx cpx #maxY bcc .shSaveY ldx #0 jmp .shSaveY .shMoveY1 dex bpl .shSaveY ldx #maxY-1 .shSaveY stx saucerY .shMoveX ldx saucerX lda saucerDx beq .shDisplay cmp #1 beq .shMoveX1 inx cpx #maxX bcc .shSaveX ldx #0 jmp .shSaveX .shMoveX1 dex bpl .shSaveX ldx #maxX-1 .shSaveX stx saucerX .shDisplay jsr displaySaucer jsr flipSaucer jsr displaySaucer jsr flipSaucer .shAnimate lda frameCounter and saucerPhaseMask bne .shDone jsr animateSaucer jsr displaySaucerCenter .shDone lda saucerMissileCnt bne .shmissle jmp saucerAI .shmissle jsr saucerMissileHandler rts .shStop lda #0 sta saucerDx sta saucerDy jmp .shMoveY flipSaucer ;flips saucerY by saucerOffset lda saucerY clc adc #saucerOffset cmp #maxY bcc .fpSave sec sbc #maxY .fpSave sta saucerY rts saucerAI ;targeting and missile fire lda saucerMissileCooling beq .sai0 dec saucerMissileCooling rts .sai0 lda rocketState cmp #1 beq .sai1 rts .sai1 jsr random and #3 sec sbc #1 sta tmp lda rocketDxLo asl sta PT1 lda rocketDx rol sta PT1+1 lda PT1 asl sta PT1 lda PT1+1 rol sta PT1+1 lda PT1 asl sta PT1 lda PT1+1 rol clc adc rocketX adc tmp bmi .sai1X1 cmp #maxX bcc .sai1X2 sec sbc maxX jmp .sai1X2 .sai1X1 clc adc maxX ;lda rocketX .sai1X2 sec sbc saucerX sta PT1 bmi .saiXAbs sta PT1+1 jmp .sai1Y .saiXAbs eor #$FF ;absolute value sta PT1+1 inc PT1+1 .sai1Y lda rocketDyLo asl sta PT2 lda rocketDy rol sta PT2+1 lda PT2 asl sta PT2 lda PT2+1 rol sta PT2+1 lda PT2 asl sta PT2 lda PT2+1 rol clc adc rocketY adc tmp bmi .sai1Y1 cmp #maxY bcc .sai1Y2 sec sbc maxY jmp .sai1Y2 .sai1Y1 clc adc maxY ;lda rocketY .sai1Y2 sec sbc saucerY sta PT2 bmi .saiYAbs sta PT2+1 jmp .saiVert .saiYAbs eor #$FF ;absolute value sta PT2+1 inc PT2+1 .saiVert jsr random and #3 tay cmp PT1+1 bcc .saiHor ldx #0 lda PT1 bpl .saiFire ldx #1 jmp .saiFire .saiHor tya cmp PT2+1 bcc .saiDiag ldx #2 lda PT2 bpl .saiFire ldx #3 jmp .saiFire .saiDiag sec lda PT1+1 sbc PT2+1 bpl .saiDiag1 eor #$FF clc adc #1 .saiDiag1 sta tmp tya cmp tmp bcc .saiDone ldx #4 lda PT1 bmi .saiDiag2 inx .saiDiag2 lda PT2 bmi .saiFire inx inx jmp.saiFire .saiDone rts .saiFire lda saucerMissileDirDxLo, x sta saucerMissileDxLo lda saucerMissileDirDx, x sta saucerMissileDx lda saucerMissileDirDyLo, x sta saucerMissileDyLo lda saucerMissileDirDy, x sta saucerMissileDy clc lda saucerMissileOffsetX, x adc saucerX sta saucerMissileX clc lda saucerMissileOffsetY, x adc saucerY sta saucerMissileY lda saucerMissileInitialX, x sta saucerMissileXLo lda saucerMissileInitialY, x sta saucerMissileYLo lda #missileLife sta saucerMissileCnt jsr displaySaucerMissile rts ; rocket rocketHandler lda rocketState bne .rhInit rts .rhInit lda #0 sta rocketRedraw lda rocketX sta rocketXN lda rocketY sta rocketYN lda rocketDir sta rocketDirN lda #0 sta rocketThrustingN lda rocketMissileCnt beq .rhScan jsr rocketMissileHandler .rhScan jsr readKbd cmp #$4B ;K beq .rhLeft cmp #$4A ;J (for big hands) beq .rhLeft cmp #$4C ;L beq .rhRight cmp #$41 ;A beq .rhThrust cmp #$53 ;S beq .rhFire cmp #$44 ;D (for big hands) beq .rhFire jmp .rhMove .rhLeft lda #$FF sta rocketTurn jmp .rhMove .rhRight lda #$01 sta rocketTurn jmp .rhMove .rhFire lda rocketMissileCnt bne .rhfDone jsr rocketMissileInit .rhfDone jmp .rhMove .rhThrust inc rocketThrustingN ldx rocketDirN ;direction index in X clc ;inc dx lda rocketDxLo adc rocketDirDx, x bmi .rhThrustXM ;process negative value cmp #rocketVMax ;check max velocity (positive) bcc .rhThrustX1 lda #rocketVMax-1 .rhThrustX1 sta rocketDxLo lda #0 ;set HI-byte / sign jmp .rhThrustX3 .rhThrustXM cmp #-rocketVMax ;check max velocity (negative) bcs .rhThrustX2 lda #-rocketVMax+1 .rhThrustX2 sta rocketDxLo lda #$FF ;set HI-byte / sign .rhThrustX3 sta rocketDx .rhThrustY clc ;inc dy lda rocketDyLo adc rocketDirDy, x bmi .rhThrustYM ;process negative value cmp #rocketVMax ;check max velocity (positive) bcc .rhThrustY1 lda #rocketVMax-1 .rhThrustY1 sta rocketDyLo lda #0 ;set HI-byte / sign jmp .rhThrustY3 .rhThrustYM cmp #-rocketVMax ;check max velocity (negative) bcs .rhThrustY2 lda #-rocketVMax+1 .rhThrustY2 sta rocketDyLo lda #$FF ;set HI-byte / sign .rhThrustY3 sta rocketDy ;jmp .rhMove .rhMove dec rocketCnt ;process Turn on rocketCnt underflow bpl .rhMoveX lda #rocketFreq sta rocketCnt lda rocketTurn beq .rhMoveX ;empty / no turn clc adc rocketDir and #7 sta rocketDirN inc rocketRedraw ;flag for redraw lda #0 ;reset turn sta rocketTurn lda rocketMissileCnt beq .rhMoveX jsr rocketMissileUpdate .rhMoveX ;move by dx lda rocketDxLo pha ;emulate 'asr' instruction rol pla ror clc ;sum it adc rocketXLo sta rocketXLo lda rocketX adc rocketDx bmi .rhMoveXM ;branch to warp to right on negativ cmp #maxX bcc .rhSaveX lda #0 ;wrap to left jmp .rhSaveX .rhMoveXM lda #maxX-1 .rhSaveX sta rocketXN ;save updated value cmp rocketX ;evaluate redraw beq .rhMoveY inc rocketRedraw .rhMoveY ;move by dy lda rocketDyLo pha ;emulate 'asr' instruction rol pla ror clc ;sum it adc rocketYLo sta rocketYLo lda rocketY adc rocketDy bmi .rhMoveYM ;branch to wrap to bottom on negative cmp #maxY bcc .rhSaveY lda #0 ;wrap to top jmp .rhSaveY .rhMoveYM lda #maxY-1 .rhSaveY sta rocketYN ;save updated value cmp rocketY ;evaluate redraw beq .rhRedraw inc rocketRedraw .rhRedraw lda rocketThrusting beq .rhRedraw2 cmp rocketThrustingN bne .rhRedraw1 lda rocketRedraw beq .rhRedraw3 .rhRedraw1 jsr clearThrust .rhRedraw2 lda rocketRedraw beq .rhRedraw3 jsr clearRocket lda rocketDirN sta rocketDir lda rocketXN sta rocketX lda rocketYN sta rocketY jsr displayRocket .rhRedraw3 lda rocketThrustingN sta rocketThrusting beq .rhDone jsr drawThrust .rhDone rts ; rocket missile rocketMissileInit ldx rocketDir lda rocketMissileDirDx, x sta rocketMissileDxLo bmi .rmiX1 lda #0 jmp .rmiX2 .rmiX1 lda #$FF .rmiX2 sta rocketMissileDx lda rocketMissileInitialX,x sta rocketMissileXLo lda rocketMissileDirDy, x sta rocketMissileDyLo bmi .rmiY1 lda #0 jmp .rmiY2 .rmiY1 lda #$FF .rmiY2 sta rocketMissileDy lda rocketMissileInitialY,x sta rocketMissileYLo clc lda rocketX adc rocketMissileOffsetX, x sta rocketMissileX clc lda rocketY adc rocketMissileOffsetY, x sta rocketMissileY lda #missileLife sta rocketMissileCnt jsr displayRocketMissile rts rocketMissileHandler jsr clearRocketMissile dec rocketMissileCnt beq .rmhDone clc lda rocketMissileDxLo adc rocketMissileXLo sta rocketMissileXLo lda rocketMissileDx adc rocketMissileX bmi .rmhXM cmp #maxX bcc .rmhSaveX lda #0 jmp .rmhSaveX .rmhXM lda #maxX-1 .rmhSaveX sta rocketMissileX clc lda rocketMissileDyLo adc rocketMissileYLo sta rocketMissileYLo lda rocketMissileDy adc rocketMissileY bmi .rmhYM cmp #maxY bcc .rmhSaveY lda #0 jmp .rmhSaveY .rmhYM lda #maxY-1 .rmhSaveY sta rocketMissileY jsr displayRocketMissile .rmhDone rts rocketMissileUpdate ;update missile motion vector on rocket turn ldx rocketDirN ;new direction lda rocketMissileDxLo ;average old dx, new dx pha ;emulate 'asr' (old dx/2) rol pla ror clc adc rocketMissileUpdateDx, x ;new dx/2 from table sta rocketMissileDxLo bmi .rmuXM ;arrange hi-bite for sign lda #0 jmp .rmuSaveX .rmuXM lda #$FF .rmuSaveX sta rocketMissileDx adc rocketMissileDyLo ;average old dy, new dy pha ;emulate 'asr' (old dy/2) rol pla ror clc adc rocketMissileUpdateDy, x ;new dy/2 from table sta rocketMissileDyLo bmi .rmuYM ;arrange hi-bite for sign lda #0 jmp .rmuSaveY .rmuYM lda #$FF .rmuSaveY sta rocketMissileDy rts ; saucer missile saucerMissileHandler jsr clearSaucerMissile dec saucerMissileCnt bne .smh1 lda #saucerCooling sta saucerMissileCooling rts .smh1 clc lda saucerMissileDxLo adc saucerMissileXLo sta saucerMissileXLo lda saucerMissileDx adc saucerMissileX bmi .smhXM cmp #maxX bcc .smhSaveX lda #0 jmp .smhSaveX .smhXM lda #maxX-1 .smhSaveX sta saucerMissileX clc lda saucerMissileDyLo adc saucerMissileYLo sta saucerMissileYLo lda saucerMissileDy adc saucerMissileY bmi .smhYM cmp #maxY bcc .smhSaveY lda #0 jmp .smhSaveY .smhYM lda #maxY-1 .smhSaveY sta saucerMissileY jsr displaySaucerMissile rts ; display routines (display and clear moving objects) displaySaucer ;pushes a saucer at saucerX /saucerY onto the charQueue ldx saucerY dex ;2 pos offset dex dex ;-1 for top row stx qPosY ldx saucerX dex ;2 pos offset dex stx qPosX lda #$64 sta qScreenCode jsr pushScreenCode ;$64 at x, y-1 ldx qPosY inx stx qPosY ldx qPosX dex stx qPosX lda #$73 sta qScreenCode jsr pushScreenCode ;$73 at x-1, y ldx qPosX inx stx qPosX ldx saucerPhase lda saucerPhases, x sta qScreenCode jsr pushScreenCode ;center code at x, y ldx qPosX inx stx qPosX lda #$6B sta qScreenCode jsr pushScreenCode ;$6B at x+1, y ldx qPosY inx stx qPosY ldx qPosX dex stx qPosX lda #$63 sta qScreenCode jsr pushScreenCode ; $63 at x, y+1 rts clearSaucer ;pushes a saucer at saucerX /saucerY onto the resetQueue ldx saucerY dex ;2 pos offset dex dex ;-1 for top row stx qPosY ldy saucerX dey ;2 pos offset dey sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset ldx qPosY inx stx qPosY ldy qPosX dey sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset ldx qPosY ldy qPosX iny sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset ldx qPosY ldy qPosX iny sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset ldx qPosY inx stx qPosY ldy qPosX dey sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset rts animateSaucer ;saucer center animation lda saucerPhaseDir beq .asLeft ldx saucerPhase inx cpx #10 bne .asNext ldx #0 beq .asNext .asLeft ldx saucerPhase dex bpl .asNext ldx #9 .asNext stx saucerPhase rts displaySaucerCenter lda saucerPhases, x sta qScreenCode ldx saucerX dex ;2 pos offset dex stx qPosX ldx saucerY dex ;2 pos offset dex stx qPosY jsr pushScreenCode rts clearSaucerCenter ldx saucerX dex ;2 pos offset dex stx qPosX ldx saucerY dex ;2 pos offset dex stx qPosY jsr getStar sta qScreenCode jsr pushScreenReset rts displayRocket ; pushes the rocket to the charQueue ldx rocketY dex ;2 pos offset dex stx qPosY ldy rocketX dey ;2 pos offset dey sty qPosX ldy rocketDir ;dispatch on value in rocketDir lda .drJumpTableHi,y sta .drJmp+2 lda .drJumpTableLo,y sta .drJmp+1 .drJmp jmp $ffff ;dummy address (fixed up) .dr0 lda #$1C sta qScreenCode jsr pushScreenCode ldx qPosX dex stx qPosX lda #$67 sta qScreenCode jsr pushScreenCode rts .dr1 lda #$2F sta qScreenCode jsr pushScreenCode ldx qPosX inx stx qPosX lda #$65 sta qScreenCode jsr pushScreenCode rts .dr2 lda #$2F sta qScreenCode jsr pushScreenCode ldx qPosY dex stx qPosY lda #$64 sta qScreenCode jsr pushScreenCode rts .dr3 lda #$1C sta qScreenCode jsr pushScreenCode ldx qPosY inx stx qPosY lda #$63 sta qScreenCode jsr pushScreenCode rts .dr4 lda #$1C sta qScreenCode jsr pushScreenCode ldx qPosX inx stx qPosX lda #$65 sta qScreenCode jsr pushScreenCode rts .dr5 lda #$2F sta qScreenCode jsr pushScreenCode ldx qPosX dex stx qPosX lda #$67 sta qScreenCode jsr pushScreenCode rts .dr6 lda #$2F sta qScreenCode jsr pushScreenCode ldx qPosY inx stx qPosY lda #$63 sta qScreenCode jsr pushScreenCode rts .dr7 lda #$1C sta qScreenCode jsr pushScreenCode ldx qPosY dex stx qPosY lda #$64 sta qScreenCode jsr pushScreenCode rts .drJumpTableLo !byte <.dr0 !byte <.dr1 !byte <.dr2 !byte <.dr3 !byte <.dr4 !byte <.dr5 !byte <.dr6 !byte <.dr7 .drJumpTableHi !byte >.dr0 !byte >.dr1 !byte >.dr2 !byte >.dr3 !byte >.dr4 !byte >.dr5 !byte >.dr6 !byte >.dr7 clearRocket ; pushes the rocket to the resetQueue ldx rocketY dex ;2 pos offset dex stx qPosY ldy rocketX dey ;2 pos offset dey sty qPosX ldy rocketDir ;dispatch on value in rocketDir lda .crJumpTableHi,y sta .crJmp+2 lda .crJumpTableLo,y sta .crJmp+1 .crJmp jmp $ffff ;dummy address (fixed up) .cr0 ldy qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset ldy qPosX dey sty qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset rts .cr1 ldy qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset ldy qPosX iny sty qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset rts .cr2 ldy qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset ldy qPosX ldx qPosY dex stx qPosY jsr getStar sta qScreenCode jsr pushScreenReset rts .cr3 ldy qPosX ldx qPosY jsr getStar sta qScreenCode jsr pushScreenReset ldy qPosX ldx qPosY inx stx qPosY jsr getStar sta qScreenCode jsr pushScreenReset rts .crJumpTableLo !byte <.cr0 !byte <.cr1 !byte <.cr2 !byte <.cr3 !byte <.cr1 !byte <.cr0 !byte <.cr3 !byte <.cr2 .crJumpTableHi !byte >.cr0 !byte >.cr1 !byte >.cr2 !byte >.cr3 !byte >.cr1 !byte >.cr0 !byte >.cr3 !byte >.cr2 drawThrust ;pushes the exhaust onto the charQueue ldx rocketDir clc lda rocketX adc thrustOffsetX, x sta qPosX clc lda rocketY adc thrustOffsetY, x sta qPosY lda #$2A sta qScreenCode jsr pushScreenCode rts clearThrust ;pushes background code for exhaust onto the resetQueue ldx rocketDir clc lda rocketX adc thrustOffsetX, x sta qPosX tay clc lda rocketY adc thrustOffsetY, x sta qPosY tax jsr getStar sta qScreenCode jsr pushScreenReset rts displayRocketMissile ldx #0 lda rocketMissileXLo and #$80 beq .drm1 inx .drm1 lda rocketMissileYLo and #$80 beq .drm2 inx inx .drm2 stx rocketMissileDisplayC lda missileCodes, x sta qScreenCode ldx rocketMissileX dex dex stx qPosX stx rocketMissileDisplayX ldx rocketMissileY dex dex stx qPosY stx rocketMissileDisplayY jsr pushScreenCode rts clearRocketMissile ldx rocketMissileDisplayY stx qPosY ldy rocketMissileDisplayX sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset rts displaySaucerMissile ldx saucerMissileX dex dex stx qPosX stx saucerMissileDisplayX ldx saucerMissileY dex dex stx qPosY stx saucerMissileDisplayY ldy #0 ;overlaps with rocket missile? lda rocketMissileCnt beq .dsm0 lda rocketMissileX cmp qPosX bne .dsm0 lda rocketMissileY cmp qPosY bne .dsm0 iny ;yes, set flag in Y .dsm0 ldx #0 lda saucerMissileXLo and #$80 beq .dsm1 inx .dsm1 lda saucerMissileYLo and #$80 beq .dsm2 inx inx .dsm2 cpy #1 ;flag for overlap set? bne .dsm3 stx PT1 ;resolve overlapping display codes lda rocketMissileDisplayC rol rol eor PT1 tax lda missileCodeCombinations, x jmp .dsm4 .dsm3 lda missileCodes, x ;single display code .dsm4 sta qScreenCode jsr pushScreenCode rts clearSaucerMissile ldx saucerMissileDisplayY stx qPosY ldy saucerMissileDisplayX sty qPosX jsr getStar sta qScreenCode jsr pushScreenReset rts drawTitleScreen ;draws the title screen (directly into screen memory) lda screenLinesLo sta PT1 lda screenLinesHi sta PT1+1 lda #<titleScreen sta PT2 lda #>titleScreen sta PT2+1 ldx #24 .dtsRow ldy #39 .dtsCol lda (PT2), y sta (PT1), y dey bpl .dtsCol dex bmi .dtsDone clc lda PT1 adc #screenCols sta PT1 lda #0 adc PT1+1 sta PT1+1 clc lda PT2 adc #screenCols sta PT2 lda #0 adc PT2+1 sta PT2+1 jmp .dtsRow .dtsDone rts ; variables score1 !byte 0 score2 !byte 0 time1 !byte 0 time2 !byte 0 saucerState !byte 0 saucerX !byte 0 saucerY !byte 0 saucerDx !byte 0 saucerDy !byte 0 saucerPhase !byte 0 saucerPhaseDir !byte 0 saucerPhaseMask !byte 0 saucerCnt !byte 0 saucerLegCnt !byte 0 rocketState !byte 0 rocketX !byte 0 rocketY !byte 0 rocketXLo !byte 0 rocketYLo !byte 0 rocketDx !byte 0 rocketDy !byte 0 rocketDxLo !byte 0 rocketDyLo !byte 0 rocketDir !byte 0 rocketThrust !byte 0 rocketCnt !byte 0 rocketXN !byte 0 rocketYN !byte 0 rocketDirN !byte 0 rocketRedraw !byte 0 rocketTurn !byte 0 rocketThrusting !byte 0 rocketThrustingN !byte 0 rocketMissileX !byte 0 rocketMissileY !byte 0 rocketMissileXLo !byte 0 rocketMissileYLo !byte 0 rocketMissileDx !byte 0 rocketMissileDy !byte 0 rocketMissileDxLo !byte 0 rocketMissileDyLo !byte 0 rocketMissileCnt !byte 0 rocketMissileDisplayX !byte 0 rocketMissileDisplayY !byte 0 rocketMissileDisplayC !byte 0 saucerMissileX !byte 0 saucerMissileY !byte 0 saucerMissileXLo !byte 0 saucerMissileYLo !byte 0 saucerMissileDx !byte 0 saucerMissileDy !byte 0 saucerMissileDxLo !byte 0 saucerMissileDyLo !byte 0 saucerMissileCnt !byte 0 saucerMissileDisplayX !byte 0 saucerMissileDisplayY !byte 0 saucerMissileCooling !byte 0 ; data saucerPhases !byte $20,$65,$54,$47,$42,$5D,$48,$59,$67,$20 rocketDirDx !byte -1, 1, 4, 4, 1, -1, -4, -4 rocketDirDy !byte -4, -4, -1, 1, 4, 4, 1, -1 thrustOffsetX !byte -2, -2, -3, -3, -2, -2, -1, -1 thrustOffsetY !byte -1, -1, -2, -2, -3, -3, -2, -2 rocketMissileDirDx !byte -16, 16, 64, 64, 16, -16, -64, -64 rocketMissileDirDy !byte -64, -64, -16, 16, 64, 64, 16, -16 rocketMissileUpdateDx !byte -8, 8, 32, 32, 8, -8, -32, -32 rocketMissileUpdateDy !byte -32, -32, -8, 8, 32, 32, 8, -8 rocketMissileInitialX !byte $E0, $20, $E0, $E0, $20, $E0, $E0, $E0 rocketMissileInitialY !byte $E0, $E0, $E0, $20, $20, $20, $20, $E0 rocketMissileOffsetX !byte -1, 1, 1, 1, 1, -1, -1, -1 rocketMissileOffsetY !byte -1, -1,-1, 1, 1, 1, 1, -1 saucerMissileOffsetX !byte 0, 0, 2, -2, -1, 1, -1, 1 saucerMissileOffsetY !byte 2, -2, 0, 0, -1, -1, 1, 1 saucerMissileDirDxLo !byte 0, 0, 72, -72, -48, 48, -48, 48 saucerMissileDirDyLo !byte 72, -72, 0, 0, -48, -48, 48, 48 saucerMissileDirDx !byte 0, 0, 0, $FF, $FF, 0, $FF, 0 saucerMissileDirDy !byte 0, $FF, 0, 0, $FF, $FF, 0, 0 saucerMissileInitialX !byte $20, $20, $20, $E0, $20, $E0, $20, $E0 saucerMissileInitialY !byte $E0, $20, $E0, $E0, $E0, $E0, $20, $20 missileCodes !byte $7E, $7C, $7B, $6C missileCodeCombinations !byte $7E, $E2, $61, $7F ;combinations with top left ($7E) !byte $E2, $7C, $FF, $E1 ;combinations with top right ($7C) !byte $61, $FF, $7B, $62 ;combinations with bottom left ($7B) !byte $7F, $E1, $62, $6C ;combinations with bottom right ($6C) starMaskX !byte $20, $00, $40, $0A, $08, $01, $82, $00 !byte $00, $00, $00, $00, $40, $00, $00, $02 !byte $00, $04, $20, $10, $88, $44, $00, $40 !byte $00, $01, $20, $00, $00, $42, $14, $00 !byte $48, $20, $00, $10, $18, $00, $00, $40 starMaskY !byte $40, $00, $01, $00, $00, $08, $00, $04 !byte $00, $40, $00, $02, $00, $00, $01, $00 !byte $04, $00, $10, $00, $20, $00, $01, $00 !byte $80 screenLinesHi !byte >($8000 + screenCols * 0) !byte >($8000 + screenCols * 1) !byte >($8000 + screenCols * 2) !byte >($8000 + screenCols * 3) !byte >($8000 + screenCols * 4) !byte >($8000 + screenCols * 5) !byte >($8000 + screenCols * 6) !byte >($8000 + screenCols * 7) !byte >($8000 + screenCols * 8) !byte >($8000 + screenCols * 9) !byte >($8000 + screenCols * 10) !byte >($8000 + screenCols * 11) !byte >($8000 + screenCols * 12) !byte >($8000 + screenCols * 13) !byte >($8000 + screenCols * 14) !byte >($8000 + screenCols * 15) !byte >($8000 + screenCols * 16) !byte >($8000 + screenCols * 17) !byte >($8000 + screenCols * 18) !byte >($8000 + screenCols * 19) !byte >($8000 + screenCols * 20) !byte >($8000 + screenCols * 21) !byte >($8000 + screenCols * 22) !byte >($8000 + screenCols * 23) !byte >($8000 + screenCols * 24) screenLinesLo !byte <($8000 + screenCols * 0) !byte <($8000 + screenCols * 1) !byte <($8000 + screenCols * 2) !byte <($8000 + screenCols * 3) !byte <($8000 + screenCols * 4) !byte <($8000 + screenCols * 5) !byte <($8000 + screenCols * 6) !byte <($8000 + screenCols * 7) !byte <($8000 + screenCols * 8) !byte <($8000 + screenCols * 9) !byte <($8000 + screenCols * 10) !byte <($8000 + screenCols * 11) !byte <($8000 + screenCols * 12) !byte <($8000 + screenCols * 13) !byte <($8000 + screenCols * 14) !byte <($8000 + screenCols * 15) !byte <($8000 + screenCols * 16) !byte <($8000 + screenCols * 17) !byte <($8000 + screenCols * 18) !byte <($8000 + screenCols * 19) !byte <($8000 + screenCols * 20) !byte <($8000 + screenCols * 21) !byte <($8000 + screenCols * 22) !byte <($8000 + screenCols * 23) !byte <($8000 + screenCols * 24) digits ;0 !byte $62,$62 !byte $61,$E1 !byte $61,$E1 !byte $FC,$FE ;1 !byte $20,$6C !byte $20,$E1 !byte $20,$E1 !byte $20,$E1 ;2 !byte $62,$62 !byte $20,$E1 !byte $EC,$E2 !byte $FC,$62 ;3 !byte $62,$62 !byte $20,$E1 !byte $7C,$FB !byte $62,$FE ;4 !byte $7B,$6C !byte $61,$E1 !byte $E2,$FB !byte $20,$E1 ;5 !byte $62,$62 !byte $61,$20 !byte $E2,$FB !byte $62,$FE ;6 !byte $7B,$20 !byte $61,$20 !byte $EC,$FB !byte $FC,$FE ;7 !byte $62,$62 !byte $20,$E1 !byte $20,$E1 !byte $20,$E1 ;8 !byte $62,$62 !byte $61,$E1 !byte $EC,$FB !byte $FC,$FE ;9 !byte $62,$62 !byte $61,$E1 !byte $E2,$FB !byte $20,$E1 digitOffsets !byte 0, 8, 16, 24, 32, 40, 48, 56, 64, 72 titleScreen !byte $20,$20,$20,$20,$20,$20,$20,$20 ;0 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$4F,$63,$A0,$20 ;1 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$6C,$61 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$65,$20,$77,$20 ;2 !byte $A0,$50,$67,$63,$A0,$63,$A0,$20 !byte $A0,$50,$20,$A0,$67,$20,$FB,$EC !byte $20,$4F,$A0,$20,$A0,$50,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$65,$20,$6F,$20 ;3 !byte $A0,$67,$67,$20,$A0,$20,$A0,$20 !byte $A0,$67,$20,$A0,$67,$20,$E1,$61 !byte $20,$4F,$63,$20,$A0,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$4C,$64,$A0,$20 ;4 !byte $A0,$7A,$67,$20,$A0,$20,$A0,$20 !byte $A0,$7A,$20,$A0,$7A,$20,$E1,$61 !byte $20,$4C,$A0,$20,$A0,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;5 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $A0,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$62,$20,$20,$20 ;6 !byte $20,$20,$20,$20,$A0,$63,$50,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$6C,$A0,$A0,$FB,$7B,$20 ;7 !byte $20,$20,$20,$20,$A0,$64,$64,$20 !byte $A0,$50,$20,$A0,$50,$20,$4F,$A0 !byte $20,$4F,$A0,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$A0,$FE,$FB,$A0,$A0,$20 ;8 !byte $20,$20,$20,$20,$20,$20,$A0,$20 !byte $A0,$67,$20,$64,$7A,$20,$65,$20 !byte $20,$4F,$63,$20,$20,$20,$20,$03 !byte $0F,$0E,$14,$12,$0F,$0C,$13,$20 !byte $20,$20,$A0,$FE,$A0,$FB,$A0,$20 ;9 !byte $20,$20,$20,$20,$4C,$64,$A0,$20 !byte $A0,$7A,$20,$4C,$A0,$20,$4C,$A0 !byte $20,$4C,$A0,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$7C,$A0,$A0,$A0,$7E,$20 ;10 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $A0,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$81 !byte $20,$14,$08,$12,$15,$13,$14,$20 !byte $20,$20,$20,$20,$E2,$20,$20,$20 ;11 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;12 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$93 !byte $20,$06,$09,$12,$05,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;13 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $4F,$A0,$20,$4F,$50,$20,$4F,$50 !byte $20,$7A,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;14 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $64,$A0,$20,$65,$67,$20,$65,$67 !byte $20,$67,$20,$20,$20,$20,$20,$8B !byte $20,$0C,$05,$06,$14,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;15 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $65,$20,$20,$A0,$67,$20,$A0,$67 !byte $20,$67,$62,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;16 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $4C,$A0,$20,$A0,$7A,$20,$A0,$7A !byte $20,$7A,$A0,$20,$20,$20,$20,$8C !byte $20,$12,$09,$07,$08,$14,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;17 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;18 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;19 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$22,$03,$0F,$0D,$10,$15,$14 ;20 !byte $05,$12,$20,$13,$10,$01,$03,$05 !byte $22,$20,$0F,$12,$09,$07,$09,$0E !byte $01,$0C,$20,$01,$12,$03,$01,$04 !byte $05,$20,$07,$01,$0D,$05,$20,$20 !byte $20,$28,$03,$29,$20,$31,$39,$37 ;21 !byte $31,$20,$0E,$15,$14,$14,$09,$0E !byte $07,$20,$01,$13,$13,$0F,$03,$09 !byte $01,$14,$05,$13,$2C,$20,$09,$0E !byte $03,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$02,$19,$20 ;22 !byte $0E,$0F,$0C,$01,$0E,$20,$02,$15 !byte $13,$08,$0E,$05,$0C,$0C,$20,$01 !byte $0E,$04,$20,$14,$05,$04,$20,$04 !byte $01,$02,$0E,$05,$19,$3B,$20,$20 !byte $20,$10,$05,$14,$20,$32,$30,$30 ;23 !byte $31,$20,$07,$01,$0D,$05,$20,$02 !byte $19,$20,$0E,$2E,$20,$0C,$01,$0E !byte $04,$13,$14,$05,$09,$0E,$05,$12 !byte $2C,$20,$32,$30,$31,$37,$2E,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 ;24 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20 !byte $20,$20,$20,$20,$20,$20,$20,$20
— Stay tuned! —
▶ Next: Episode 10: Not the End, Yet, Still Some of a Wrap-Up
◀ Previous:  Episode 8: Space Commander
▲ Back to the index.
April 2017, Vienna, Austria
www.masswerk.at – contact me.
— This series is part of Retrochallenge 2017/04. —