;=================================================================== ;BLASTOPIA (C) 2018 THE NEW DIMENSION ;PROGRAMMING, GRAPHICS, SFX AND MUSIC BY RICHARD BAYLISS ;http://tnd64.unikat.sk ;=================================================================== ;CheatMode = 1 ;Uncomment for infinite lives ;) !source "titlescreen.asm" GameStart ;Game code restarts here. lda #$12 ;Charset at $0800-$0fff sta $d018 lda #$18 ;Screen multicolour sta $d016 lda #$00 ;Black border/background sta $d020 sta $d021 lda #$0b ;Chosen multicolour 1 sta $d022 sta GAMEMULTICOLOUR1 lda #$03 ;Chosen multicolour 2 sta $d023 sta GAMEMULTICOLOUR2 lda #240 sta CAMELQUOTA lda #239 sta CAMELQUOTA+1 sta QUOTAPICKED sta QUOTAPICKED+1 ;NEW GAME ... Fill complete score, with ;amount 00000 of points, 3 lives, shield 99 ldx #$00 ZEROSCORE lda #239 ;Custom char representing 0 sta SCORE,x inx cpx #6 ;6 Digits max bne ZEROSCORE lda #242 ;Lives = 3 (Custom char) sta LIVES lda #240 ;Custom char representing 1 sta LEVEL NEWLEVEL jsr InitInterrupts ;Call disable interrupts lda #200 sta INVULNERABILITYTIME lda #244 ;Shield = 50 sta SHIELD lda #239 ;Shield = 50 sta SHIELD+1 lda #239 ;Camel quota = 10 sta QUOTAPICKED+1 sta QUOTAPICKED ldx #$00 ;Init the table stx FormationTablePointer ldy #$00 sty ALIENSELECTPOINTER fillformation lda f01x,x sta formationX,x lda f01y,x sta formationY,x inx bne fillformation ;Setup each level, the colour scheme, alien ;formation table (to chose from) and then ;decrunch the level. ldx LEVELPOINTER ;Grab level pointer lda MAPDECRUNCHLO,x ;Select low byte of end address of the crunched map sta DECRUNCHLO ;Store to the low-byte address of exomizer's decrunch source lda MAPDECRUNCHHI,x ;Select hi byte of end address of the crunched map sta DECRUNCHHI ;Store to the hi-byte address of exomizer lda LEVELMCOLTBL1,x ;Select colour from LEVELCOLOURTBL1 sta GAMEMULTICOLOUR1;Store to the game multicolour 1 pointer inside game raster split lda LEVELMCOLTBL2,x ;Select colour from LEVELCOLOURTBL2 sta GAMEMULTICOLOUR2;Store to the game multicolour 2 pointer inside game raster split lda LEVELMCOLTBL3,x ;Select colour from LEVELCOLOURTBL3 sta GAMECHARCOLOUR+1;Store to self-mode background char colour lda LEVELSELECTTABLELO,x ;Select lo-byte table for alien select table sta StoreAlienMode+1 ;Store to self-mod alien mode lowbyte address lda LEVELSELECTTABLEHI,x ;Select hi-byte table for alien select table sta StoreAlienMode+2 ;Store to self-mod alien mode hibyte address lda QUOTADIGITLEFT,x sta CAMELQUOTA lda QUOTADIGITRIGHT,x sta CAMELQUOTA+1 inx cpx #9 ;Game complete beq GameComplete ;Copy the select alien table and store it to ;the actual alien setup. Also reset the pointers that ;create the aliens. We don't want the wrong aliens ;spawned at a start of a new game, or level. ldx #$00 StoreAlienMode lda LEVEL1SELECTTABLE,x sta ALIENSELECTTABLE,x inx cpx #ALIENSELECTTABLEEND-ALIENSELECTTABLE ;Length of table (24) bne StoreAlienMode ;Clear SID Chip ldx #$00 SilenceSID lda #$00 sta $d400,x inx cpx #$18 bne SilenceSID ;Now decrunch game level map jmp DecrunchLevelMap ;The game is complete, so redisplay star field ;and display the game ending message. GameComplete ;Draw star field again ldx #$00 DrawStarFieldEnd lda STARTMAP,x sta SCRN,x lda STARTMAP+$100,x sta SCRN+$100,x lda STARTMAP+$200,x sta SCRN+$200,x lda STARTMAP+$2e8,x sta SCRN+$300,x lda #$09 sta COLR,x sta COLR+$100,x sta COLR+$200,x sta COLR+$2e8,x inx bne DrawStarFieldEnd ;Background colour dark blue ;and light blue lda #6 sta GAMEMULTICOLOUR1 lda #14 sta GAMEMULTICOLOUR2 ;Draw the game status panel ldx #$00 DrawPanelEnd lda STATUSPANEL,x sta SCRN+800,x lda #$0b sta COLR+800,x inx cpx #STATUSPANELEND-STATUSPANEL bne DrawPanelEnd ;Set Quota to 00/00 lda #239 sta CAMELQUOTA sta CAMELQUOTA+1 sta QUOTAPICKED sta QUOTAPICKED+1 ;Now copy the ending text in place ldx #$00 CopyEndText lda gcline1,x cmp #$20 ;Space detected? beq .IgnoreSpaceCharA ;ignore clc adc #191 ;Pick char where text chars lie and convert sta SCRN+120,x .IgnoreSpaceCharA lda gcline2,x cmp #$20 beq .IgnoreSpaceCharB clc adc #191 sta SCRN+280,x .IgnoreSpaceCharB lda gcline3,x cmp #$20 beq .IgnoreSpaceCharC clc adc #191 sta SCRN+360,x .IgnoreSpaceCharC lda gcline4,x cmp #$20 beq .IgnoreSpaceCharD clc adc #191 sta SCRN+520,x .IgnoreSpaceCharD lda gcline5,x cmp #$20 beq .IgnoreSpaceCharE clc adc #191 sta SCRN+640,x .IgnoreSpaceCharE inx cpx #$28 bne CopyEndText ;Quick high score check exclusively for the ;ending. Before done, check if the player ;has been cheating. lda LivesCheat ;Infinite lives cheat hit? cmp #$2c ; (BIT LIVES) bne NoCheatHiScore ;No cheat ;Zero high score properties to make last score:000000 ldx #$00 ZeroFinalScore lda #$30 sta FINALSCORE,x inx cpx #6 bne ZeroFinalScore ;Then disable the cheat lda #$ec sta LivesCheat jmp NoEndHiScore NoCheatHiScore ldx #$00 DoScoreConvert lda SCORE,x sec sbc #191 sta FINALSCORE,x inx cpx #6 bne DoScoreConvert lda FINALSCORE sec lda HISCORE+5 sbc FINALSCORE+5 lda HISCORE+4 sbc FINALSCORE+4 lda HISCORE+3 sbc FINALSCORE+3 lda HISCORE+2 sbc FINALSCORE+2 lda HISCORE+1 sbc FINALSCORE+1 lda HISCORE sbc FINALSCORE bpl NoEndHiScore ;Make new hi score ldx #$00 EndHiScore lda FINALSCORE,x sta HISCORE,x inx cpx #6 bne EndHiScore ;Set WELL DONE hi score text ldx #$00 FLHISC1 lda hiline4,x cmp #$20 beq skipEndHi1 clc adc #191 sta SCRN+440,x skipEndHi1 inx cpx #$28 bne FLHISC1 jmp SetupEndIRQ NoEndHiScore ;Then set FAIL hi score text ldx #$00 FLHISC2 lda hiline3,x cmp #$20 beq skipEndHi2 clc adc #191 sta SCRN+440,x skipEndHi2 inx cpx #$28 bne FLHISC2 SetupEndIRQ ldx #GAMEIRQ lda #$2e stx $0314 sty $0315 sta $d012 lda #$7f sta $dc0d sta $dd0d lda #$1b sta $d011 lda #$01 sta $d01a lda #ENDMUSIC jsr MUSICINIT cli lda #0 sta FIREBUTTON dec LEVEL jsr MaskPanel ;Wait for the fire button to be pressed, also ;keep the star field animation in place WaitEnding jsr SyncGameTimer jsr StarField lda $dc00 lsr lsr lsr lsr lsr bit FIREBUTTON ror FIREBUTTON bmi WaitEnding bvc WaitEnding ;Restore to no cheat lda #$ec sta LivesCheat ;(DEC LIVES) jmp TITLESCREEN DecrunchLevelMap jsr DECRUNCH ;Every time a new level starts. The map ;should initialise the position of the ;map. We place a low byte of the map position ;to a specific address which should be self-modified ;in order to have the map scroll position correctly ;set up. jsr InitMapPosition ;Initialise map position jsr InitAlienProperties ;Initialise alien properties ;Set default position for sprites ldx #$00 SetStartingPosition lda STARTPOSITION,x sta OBJPOS,x inx cpx #16 bne SetStartingPosition lda #$ff sta $d015 ;All sprites on sta $d01c ;and multicoloured lda #$09 ;Brown sta $d025 ;Sprite multicolour 1 lda #$01 ;White sta $d026 ;Sprite multicolour 2 lda #$07 sta $d028 ;Initialise pointers. The player should not ;be dead. The lazer should be enabled at the ;start of the game. lda #0 sta PLAYERDEAD sta LAZERTIME lda #1 sta LAZERON ;Setup game interrupts ldx #GAMEIRQ lda #$2e stx $0314 sty $0315 sta $d012 lda #$7f sta $dc0d sta $dd0d lda #$1b sta $d011 lda #$01 sta $d01a lda #$80 sta PLAYERALIVETYPE lda #INGAMEMUSIC ;Initialise in game music jsr MUSICINIT cli ;The main game loop, calling subroutines ;(Our main body of the game engine). MAINGAMESTART lda #0 sta PADENABLED ldx #$00 DrawGameScreen lda STARTMAP,x sta SCRN,x lda STARTMAP+$100,x sta SCRN+$100,x lda STARTMAP+$200,x sta SCRN+$200,x lda STARTMAP+$2e8,x sta SCRN+$2e8,x GAMECHARCOLOUR lda #$09 ;Chosen char colour for the map sta COLR,x sta COLR+$100,x sta COLR+$200,x sta COLR+$2e8,x inx bne DrawGameScreen ;Now draw the game status panel on to the screen ldx #$00 DrawPanel lda STATUSPANEL,x sta SCRN+800,x lda #$0b sta COLR+800,x inx cpx #STATUSPANELEND-STATUSPANEL ;Size of panel bne DrawPanel GAMELOOP jsr SyncGameTimer ;Synchronise game timer jsr ExpandMSB ;Expand sprite position area ;Check pause key (<-) lda $dc01 lsr lsr lsr bcs ContinueGame jmp GamePaused ContinueGame jsr ScrollMap ;Scroll the game map across the screen jsr StarField ;Animate the charset to make a starfield effect jsr TestLazer ;Animate the lazer (if on) otherwise it is off jsr AnimSprites ;Animate all the sprites jsr PlayerProperties ;Test player properties jsr TestAlienProperties ;Test alien properties jsr TestCamelProperties ;Test camel properties jsr SpriteToSprite ;Sprite to sprite collision jsr MaskPanel ;Mask the score panel jsr SpriteToBackground ;Sprite/Background collision (Player only) jsr AnimatePad ;Animate the lights of the launch pad (if enabled) jsr CheckMatchingQuotas jsr CheckZeroShield jsr AnimChar ;Animate the scrolling char 109 (Level 3 and Level 8 inside brick) jmp GAMELOOP ;The game has been paused, wait for the player ;to press FIRE on joystick port 2 to unpause the game GamePaused lda #0 sta FIREBUTTON WaitUnpause lda $dc00 lsr lsr lsr lsr lsr bit FIREBUTTON ror FIREBUTTON bmi WaitUnpause bvc WaitUnpause lda #0 sta FIREBUTTON jmp GAMELOOP ;The main IRQ raster interrupts. (Double split) ;One for the score panel, and the other for the ;scrolling game field. GAMEIRQ inc $d019 lda #$2e ;Set raster end position sta $d012 lda #$00 ;No sprites allowed in this raster area sta $d015 lda #$18 ;Screen still, multicolour on sta $d016 lda #$06 ;Blue set sta $d022 ;Multi colour #1 lda #$0e ;Light blue set sta $d023 ;Multi colour #2 lda #1 sta GAMESYNC ;Sync game timer again jsr MUSICPLAYER ;TEST PAL/NTSC to calculate music speed ldx #GAMEIRQ2 ;Fetch hibyte of second interrupt stx $0314 ;Store to IRQ low vector sty $0315 ;Store to IRQ hi vector jmp $ea7e ;IRQ looping GAMEIRQ2 inc $d019 lda #$da ;Set raster end position sta $d012 lda #$ff ;All sprites allowed in this raster area sta $d015 lda SCROLLX ora #$10 sta $d016 ;Set smooth scroller lda GAMEMULTICOLOUR1 ;Pick game multi colour 1 sta $d022 lda GAMEMULTICOLOUR2 ;Pick game multi colour 2 sta $d023 ldx #GAMEIRQ stx $0314 sty $0315 jmp $ea7e ;Synchronise game timer with interrupts SyncGameTimer lda #$00 sta GAMESYNC cmp GAMESYNC beq *-3 rts ;Expand game sprite position MSB and ;place to hardware sprite position ExpandMSB ldx #$00 ExpandLoop lda OBJPOS+1,x sta $d001,x lda OBJPOS,x asl ror $d010 sta $d000,x inx inx cpx #16 bne ExpandLoop rts ;The game map scrolling routine. ;Start by setting the scroll speed. ScrollExit rts ScrollMap lda SCROLLX sec sbc #MAPSCROLLSPEED and #$07 sta SCROLLX bcs ScrollExit ;Shift a byte from each character on screen ;then move it to the next character on screen. ;Split this into four different loops. (5 rows per ;loop) ldx #00 ;Grab last value of char - then add it MoveRow1 lda SCRN+1,x ;Grab one screen column higher sta SCRN,x ;pull it to the previous column lda SCRN+41,x sta SCRN+40,x lda SCRN+81,x sta SCRN+80,x lda SCRN+121,x sta SCRN+120,x lda SCRN+161,x sta SCRN+160,x inx cpx #$28 bne MoveRow1 ldx #00 ;Do the same thing for the next set of rows MoveRow2 lda SCRN+201,x sta SCRN+200,x lda SCRN+241,x sta SCRN+240,x lda SCRN+281,x sta SCRN+280,x lda SCRN+321,x sta SCRN+320,x lda SCRN+361,x sta SCRN+360,x inx cpx #$28 bne MoveRow2 ldx #00 ;Once again do the same for the next set of rows MoveRow3 lda SCRN+401,x sta SCRN+400,x lda SCRN+441,x sta SCRN+440,x lda SCRN+481,x sta SCRN+480,x lda SCRN+521,x sta SCRN+520,x lda SCRN+561,x sta SCRN+560,x inx cpx #$28 bne MoveRow3 ldx #00 ;Finally for the last 5 rows MoveRow4 lda SCRN+601,x sta SCRN+600,x lda SCRN+641,x sta SCRN+640,x lda SCRN+681,x sta SCRN+680,x lda SCRN+721,x sta SCRN+720,x lda SCRN+761,x sta SCRN+760,x inx cpx #$28 bne MoveRow4 ;Now place the self-mod stored character on to the ;last byte of each row. mapSM1 lda MAPROW1 sta SCRN+39 mapSM2 lda MAPROW2 sta SCRN+79 mapSM3 lda MAPROW3 sta SCRN+119 mapSM4 lda MAPROW4 sta SCRN+159 mapSM5 lda MAPROW5 sta SCRN+199 mapSM6 lda MAPROW6 sta SCRN+239 mapSM7 lda MAPROW7 sta SCRN+279 mapSM8 lda MAPROW8 sta SCRN+319 mapSM9 lda MAPROW9 sta SCRN+359 mapSM10 lda MAPROW10 sta SCRN+399 mapSM11 lda MAPROW11 sta SCRN+439 mapSM12 lda MAPROW12 sta SCRN+479 mapSM13 lda MAPROW13 sta SCRN+519 mapSM14 lda MAPROW14 sta SCRN+559 mapSM15 lda MAPROW15 sta SCRN+599 mapSM16 lda MAPROW16 sta SCRN+639 mapSM17 lda MAPROW17 sta SCRN+679 mapSM18 lda MAPROW18 sta SCRN+719 mapSM19 lda MAPROW19 sta SCRN+759 mapSM20 lda MAPROW20 sta SCRN+799 ;Now to get a new character fetched from the map, increment ;the lo/byte of the self-modifying addresses in order to ;allow all 256 bytes to update the last character that was ;used after every frame scrolled. inc mapSM1+1 inc mapSM2+1 inc mapSM3+1 inc mapSM4+1 inc mapSM5+1 inc mapSM6+1 inc mapSM7+1 inc mapSM8+1 inc mapSM9+1 inc mapSM10+1 inc mapSM11+1 inc mapSM12+1 inc mapSM13+1 inc mapSM14+1 inc mapSM15+1 inc mapSM16+1 inc mapSM17+1 inc mapSM18+1 inc mapSM19+1 inc mapSM20+1 lda mapSM1+1 beq RESETMAP rts RESETMAP jsr InitMapPosition rts ;Character based wrap-around animation. Produce ;a starfield, by rolling the bytes of the ;selected layers to be animated at different speeds StarField jsr AnimPixel1 jsr AnimPixel2 jsr AnimPixel2 jsr AnimPixel3 jsr AnimPixel3 jsr AnimPixel3 jsr AnimPixel4 jsr AnimPixel4 jsr AnimPixel4 jsr AnimPixel4 rts ;Animate the first chosen pixel on the ;current charset - Scroll it to the left. AnimPixel1 lda CHARSET+1 asl rol CHARSET+1+24 rol CHARSET+1+16 rol CHARSET+1+8 rol CHARSET+1 rts AnimPixel2 lda CHARSET+3 asl rol CHARSET+3+24 rol CHARSET+3+16 rol CHARSET+3+8 rol CHARSET+3 rts AnimPixel3 lda CHARSET+5 asl rol CHARSET+5+24 rol CHARSET+5+16 rol CHARSET+5+8 rol CHARSET+5 rts AnimPixel4 lda CHARSET+7 asl rol CHARSET+7+24 rol CHARSET+7+16 rol CHARSET+7+8 rol CHARSET+7 rts ;Animate the scrolling char (109) so that it ;rolls to the RIGHT while the scroller is scrolling ;to the right. AnimChar ldx #$00 AnimCharRolling lda CHARSET+109*8,x lsr ror CHARSET+109*8,x lsr ror CHARSET+109*8,x inx cpx #8 bne AnimCharRolling rts ;Test lazer animation. If lazer is switched on, ;the lazer should animate. If not, then it shouldn't. TestLazer jsr AnimLazer lda LAZERTIME cmp #$40 beq CheckLazer inc LAZERTIME rts CheckLazer lda #0 sta LAZERTIME lda LAZERON cmp #1 beq SwitchOff cmp #0 beq SwitchOn rts ;Lazer should be switched off, so fill ;charset with 0 bytes to make blank char SwitchOff ldx #$00 MakeBlankChar lda #$00 sta CHARSET+42*8,x inx cpx #8 bne MakeBlankChar lda #0 sta LAZERON rts ;Lazer should be switched on, so copy ;the backup char and restore it to the ;current charset position SwitchOn ldx #$00 RestoreBackupChar lda LazerBackup,x sta CHARSET+42*8,x inx cpx #8 bne RestoreBackupChar lda #1 sta LAZERON rts ;Animate the lazer CHARSET AnimLazer lda CHARSET+42*8+7 sta $02 ;Backup char to zeropage ldx #$07 MoveChar lda CHARSET+42*8-1,x sta CHARSET+42*8,x dex bpl MoveChar lda $02 sta CHARSET+42*8 rts ;Animate all of the sprites AnimSprites lda ALIENTYPE1 sta ALIENANIMSTORE ColourSprites lda ENEMY1COLOUR sta ALIENCOLOURSTORE lda ANIMDELAY cmp #$04 beq SprAnimOK inc ANIMDELAY rts SprAnimOK lda #0 sta ANIMDELAY ldx ANIMPOINTER lda PLAYERFRAME,x sta PLAYERALIVETYPE lda BULLETFRAME sta BULLETTYPE lda ENEMY1FRAME,x sta ALIENTYPE1 lda ENEMY2FRAME,x sta ALIENTYPE2 lda ENEMY3FRAME,x sta ALIENTYPE3 lda ENEMY4FRAME,x sta ALIENTYPE4 lda ENEMY5FRAME,x sta ALIENTYPE5 lda ENEMY6FRAME,x sta ALIENTYPE6 lda ENEMY7FRAME,x sta ALIENTYPE7 lda ENEMY8FRAME,x sta ALIENTYPE8 lda ENEMY9FRAME,x sta ALIENTYPE9 lda ENEMY10FRAME,x sta ALIENTYPE10 lda ENEMY11FRAME,x sta ALIENTYPE11 lda ENEMY12FRAME,x sta ALIENTYPE12 lda ENEMY13FRAME,x sta ALIENTYPE13 lda ENEMY14FRAME,x sta ALIENTYPE14 lda ENEMY15FRAME,x sta ALIENTYPE15 lda ENEMY16FRAME,x sta ALIENTYPE16 lda ENEMY17FRAME,x sta ALIENTYPE17 lda ENEMY18FRAME,x sta ALIENTYPE18 lda ENEMY19FRAME,x sta ALIENTYPE19 lda ENEMY20FRAME,x sta ALIENTYPE20 lda ENEMY21FRAME,x sta ALIENTYPE21 lda ENEMY22FRAME,x sta ALIENTYPE22 lda ENEMY23FRAME,x sta ALIENTYPE23 lda ENEMY24FRAME,x sta ALIENTYPE24 lda CAMELFRAME,x sta CAMELTYPE inx cpx #4 beq ResetAnim inc ANIMPOINTER rts ResetAnim ldx #$00 stx ANIMPOINTER rts ;Player Properties and control. Check whether or not ;the player is alive or dead. Pick out the correct ;sprite animation pointers. Test player movement and ;also collision. PlayerProperties jsr MoveBullet ;Player bullet firing ;Test player's invulnerability time lda INVULNERABILITYTIME cmp #0 beq NOTINVULNERABLE dec INVULNERABILITYTIME jsr FlashRoutine NOTINVULNERABLE lda PLAYERDEAD cmp #1 bne PlayerIsAlive jmp DestroyPlayer PlayerIsAlive lda PLAYERALIVETYPE ;Grab animation of player alive sta $07f8 ;and stick it to the sprite anim lda INVULNERABILITYTIME cmp #0 beq FIXEDCOLOUR lda INVULNERABLECOLOUR sta $d027 jmp .PMain FIXEDCOLOUR lda #$0f ;Grab the colour of the ship and sta $d027 ;then store to sprite HW colour .PMain ;Read joystick port 2 and control player lda #1 ;Check / Detect UP bit $dc00 bne NotUp ;Up not found. lda OBJPOS+1;Otherwise move the player ship sec ;up until reached stop position sbc #4 cmp #$31 bcs ForceUp lda #$31 ForceUp sta OBJPOS+1 NotUp lda #2 ;Check / Detect down bit $dc00 bne NotDown ;Down not found lda OBJPOS+1;otherwise move the player ship down clc ;until reached stop position adc #4 cmp #$bd bcc ForceDown lda #$bd ForceDown sta OBJPOS+1 NotDown lda #4 ;Check / Detect left bit $dc00 bne NotLeft ;Left not found lda OBJPOS ;Othewrise move the player ship left sec ;until reached stop position sbc #2 cmp #$10 bcs ForceLeft lda #$10 ForceLeft sta OBJPOS NotLeft lda #8 ;Check / detect right bit $dc00 ;Right not found bne NotRight;Othewise move the player ship right lda OBJPOS ;until reached stop position clc adc #2 cmp #$98 bcc ForceRight lda #$98 ForceRight sta OBJPOS NotRight ;Now check firebutton, but must not be held lda $dc00 lsr lsr lsr lsr lsr bit FIREBUTTON ror FIREBUTTON bmi NoFire bvc NoFire lda #0 sta FIREBUTTON ;Check if the bullet is offset, otherwise allow the ;player to fire it. lda OBJPOS+3 cmp #$f0 ;Outside screen bcc NoFire lda OBJPOS sta OBJPOS+2 lda OBJPOS+1 sta OBJPOS+3 ;Creat shoot SFX lda #SHOOTSFXTABLE ldx #14 jsr SFXINIT NoFire lda BULLETTYPE sta $07f9 lda #$0f sta $d028 rts ;The player is dead so animate it exploding DestroyPlayer lda PLAYEREXPLODEANIMDELAY cmp #4 beq PerformPlayerExplosion inc PLAYEREXPLODEANIMDELAY rts PerformPlayerExplosion lda #0 sta PLAYEREXPLODEANIMDELAY ldx PLAYEREXPLODEPOINTER lda EXPLODEFRAME,x sta $07f8 lda #7 sta $d027 inx cpx #8 beq FinishedKillingPlayer inc PLAYEREXPLODEPOINTER rts ;Player invulnerable flash routine FlashRoutine ldx PLAYERFLASHPOINTER lda FLASHCOLOURTABLE,x sta INVULNERABLECOLOUR inx cpx #FLASHCOLOURTABLEEND-FLASHCOLOURTABLE beq ResetFlashRoutine inc PLAYERFLASHPOINTER rts ResetFlashRoutine ldx #$00 stx PLAYERFLASHPOINTER rts FinishedKillingPlayer !ifdef CheatMode { } else { LivesCheat dec LIVES } lda LIVES cmp #239 ;0 digit from custom char beq GAMEOVER lda #244 ;Shield = 50 sta SHIELD lda #239 ;Shield = 50 sta SHIELD+1 lda #200 sta INVULNERABILITYTIME ;Respawn the player at the starting position lda STARTPOSITION sta OBJPOS lda STARTPOSITION+1 sta OBJPOS+1 lda #0 sta PLAYERDEAD rts GAMEOVER lda #239 ;Zero on custom char jsr MaskPanel ;Play GAME OVER sound lda #GAMEOVERSFXTABLE ldx #14 jsr SFXINIT ;Remove all of the game sprites ;offscreen ldx #0 ClearSpritesGameOver lda #0 sta OBJPOS,x sta $d000,x inx cpx #$10 bne ClearSpritesGameOver ;Display game over text ldx #$00 ShowGameOverText lda goline1,x cmp #$20 beq GOskipBlackSpace clc adc #191 sta SCRN+360,x GOskipBlackSpace inx cpx #$28 bne ShowGameOverText lda #0 sta FIREBUTTON jsr CheckHiScore WAITBUTTON jsr SyncGameTimer ;Sync timer again on game over jsr TestLazer ;Keep animation in tact jsr AnimatePad ;Animate the pad if enabled jsr StarField ;Carry on with the starfield lda $dc00 lsr lsr lsr lsr lsr bit FIREBUTTON ror FIREBUTTON bmi WAITBUTTON bvc WAITBUTTON lda #0 sta FIREBUTTON ;Game has finished. Restart! jmp TITLESCREEN ;Move the player's bullet object across ;the screen until it has reached its limited ;position. MoveBullet lda OBJPOS+2 clc adc #12 cmp #$a2 bcc NotExpired lda #$f0 sta OBJPOS+3 NotExpired sta OBJPOS+2 rts SCROLLX !byte 0 GAMESYNC !byte 0 ;Alien properties - This is all macroed together ;in order to have a same routine but different ;results for each alien. TestAlienProperties jsr TestAlien1 ;These are the subroutines that jsr TestAlien2 ;are linked to the macros to jsr TestAlien3 ;test alien properties. jsr TestAlien4 jsr TestAlien5 jsr TestRespawn ;Then test respawin of aliens rts ;Testing of alien properties. Test whether ;or not an alien is dead. If it is then ;create the alien death animation sequence ;otherwise call other check codes. !macro TestAlien ALIENDEAD,ALIENEXPLODEDELAY,ALIENEXPLODEPOINTER,SPRITEFRAME,SPRITECOLOUR,SPRITEX,SPRITEY,ALIENOFFSET,ALIENSPAWNED,ALIENWAITTIME,ALIENSPAWNLIMIT { lda ALIENDEAD cmp #$01 beq .DoAlienDeathScene jmp .AlienIsAlive ;The alien is dead. So destroy it by setting ;up the alien death sequence animation. .DoAlienDeathScene lda ALIENEXPLODEDELAY cmp #$02 ;Speed of explosion beq .SwitchToNextFrame inc ALIENEXPLODEDELAY rts ;Alien can now explode. Now call for ;the main animation subroutine .SwitchToNextFrame lda #$00 sta ALIENEXPLODEDELAY ;Reset delay ldx ALIENEXPLODEPOINTER ;Call pointer to display lda EXPLODEFRAME,x ;to display explosion frame sta SPRITEFRAME ;alien HW sprite frame lda #$07 ;colour yellow sta SPRITECOLOUR inx cpx #8 ;8 frames for explosion beq .FinishAlienExplosion inc ALIENEXPLODEPOINTER rts ;Finish explosion, switch sprite position off ;and then offset the alien object, so ;that it is not allowed to move on screen .FinishAlienExplosion ldx #$00 stx ALIENEXPLODEPOINTER lda #0 sta SPRITEX ;Zero position X sta SPRITEY ;and Y for sprites lda #1 sta ALIENOFFSET lda #0 sta ALIENSPAWNED sta ALIENDEAD rts ;The alien is alive, so perform a check ;to see whether or not the alien is ;offset, or ready. If not then the ;alien must not be seen or move. .AlienIsAlive lda ALIENOFFSET cmp #$01 bne .AlienNotOffset lda #0 ;Keep alien offset sta SPRITEX sta SPRITEY rts ;Now check if alien is ready to ;appear on screen (spawned) .AlienNotOffset lda ALIENSPAWNED ;Is the alien spawned cmp #$01 bne .AlienNotActive ;No. Not quite. jmp .AlienIsActivated ;Else the alien is active ;The alien is not active so call subroutine ;which holds the alien for a certain ;period of time. .AlienNotActive jsr .HoldAlien ;Call subroutine to hold the alien ;until it can spawn rts ;The alien is active, so allow it ;to move around the screen and ;animate accordingly .AlienIsActivated .alienframe lda ALIENANIMSTORE ;Define sprite frame for alien sta SPRITEFRAME ;HW alien sprite frame .aliencolour lda ALIENCOLOURSTORE ;Define sprite colour sta SPRITECOLOUR;HW alien sprite colour ;Read formation table, and set X, Y ;position to the aliens, to indicate their ;own paths. .alienmovex lda formationX ;Read address of formationX table table sta SPRITEX ;store it to the alien X position .alienmovey lda formationY ;Read address of formationY table sta SPRITEY ;store it to the alien Y position ;Increment the lowbyte address ;of the self-modified table read code, so ;that the next byte on the table is read inc .alienmovex+1 inc .alienmovey+1 ;Check if we have reached after the LAST byte ;of the formation table. If so, end the formation lda .alienmovex+1 ;Lo-byte addr = $00? beq .EndFormation ;Yes. Finished formation rts ;The formation has finished, so force the ;chosen alien to become offset. .EndFormation lda #$01 ;Set ALIENOFFSET to ON sta ALIENOFFSET lda #$00 ;Set ALIENSPAWNED to OFF sta ALIENSPAWNED rts ;The alien is not ready to be released so keep it offset until ;the alien has waited for long enough to respawn. .HoldAlien ;Initialise the formation table position ;for a new spawn. lda #formationX sta .alienmovex+2 lda #formationY sta .alienmovey+2 ;Zero X/Y position ofselected alien lda #0 sta SPRITEX sta SPRITEY ;Check if the alien time limit for waiting ;has reached a set value, so that the alien ;is allowed to spawn. lda ALIENWAITTIME ;Check timer cmp #ALIENSPAWNLIMIT ;time to wait expired? beq .SpawnNewAlien ;Yes, spawn a new alien. inc ALIENWAITTIME ;No, increment one byte to the counter rts ;Time out - Alien is ready to be ;released. .SpawnNewAlien lda #0 ;Reset alien waiting time sta ALIENWAITTIME lda #0 ;Switch ALIENOFFSET off. We do want sta ALIENOFFSET ;the alien enabled to move lda #1 ;Switch ALIENSPAWNED on. The alien sta ALIENSPAWNED ;should be enabled to move rts } ;End of macro code ;Test for alien respawn. Test to see whether or not all of the aliens ;are offset. If they are, then do a respawn. A loop ;is called to detect whether or not ALIENXOFFSET = 1, ;where X is the pointer that indicate which alien is ;offset. TestRespawn ldx #$00 CheckIfOffset lda ALIEN1OFFSET,x ;Read bytes from table cmp #$01 ;Is alien offset? bne .NotAllAliensOffset ;No, cannot respawn inx ;Move to next byte from table cpx #$05 ;until all 5 bytes have been read bne CheckIfOffset ;loop CheckIfOffset until 5 bytes read ;Loop has ended, generate a new formation ;and alien animation, colour, scoring table jsr .GenerateNewAliens ;Reset alien hit counter to 0 lda #0 sta ALIENHITCOUNT jmp .RespawnAliens ;Then launch them. .NotAllAliensOffset rts ;Generate a new set of aliens, colours, formation and ;scoring. .GenerateNewAliens ldy ALIENSELECTPOINTER ;Value of alien selection pointer lda ALIENSELECTTABLE,y ;select the value of the alien to spawn sta FormationTablePointer ;store it to the FormationAlien type pointer iny cpy #24 ;24 sets of formation beq ResetAlienSelect ;Reset to first selection inc ALIENSELECTPOINTER ;else increment the pointer by one step jmp MAKEALIEN ;Then call alien production code ResetAlienSelect ldy #$00 sty ALIENSELECTPOINTER ;This code produces the alien. MAKEALIEN ldx FormationTablePointer ;Read table pointer lda FORMXLO,x ;Read lo-byte table of X-Formation sta .formX+1 ;Store to lo-byte of self-modifying code .formX lda FORMXHI,x ;Read hi-byte table of X-Formation sta .formX+2 ;Store to hi-byte self-modifying code .formX lda FORMYLO,x ;Read lo-byte table of Y-Formation sta .formY+1 ;Store to lo-byte of self-modifying code .formY lda FORMYHI,x ;Read hi-byte taable of Y-Formation sta .formY+2 ;Store to hi-byte of self-modifting code .formY lda ANIMTYPELO,x ;Read lo-byte table of alien animation select table sta AnimSprites+1 ;Store to lo-byte of self-modifying code AnimSprites lda ANIMTYPEHI,x ;Read hi-byte table of alien animation select table sta AnimSprites+2 ;Store to hi-byte of self-modifying code AnimSprites lda ANIMCOLLO,x ;Read lo-byte of alien colour table sta ColourSprites+1 ;Store to lo-byte of self modying code ColourSprites lda ANIMCOLHI,x ;Read hi-byte of alien colour table sta ColourSprites+2 ;Store to hi-byte of self modifying code ColourSprites lda ALIENSCORETABLE,x ;Read picked score zone sta ALIENSCORE ;according to table jsr .SetNewFormation ;Then set the new alien settings. rts ;Reset the alien table pointer .ResetFormTable ldx #$00 stx FormationTablePointer ;Set the new read table, for alien sprite type, ;colour, formation, etc. .SetNewFormation ldx #$00 .GenLoop .formX lda f01x,x sta formationX,x .formY lda f01y,x sta formationY,x inx bne .GenLoop rts ;Respawn the aliens, by zeroing the ;pointers, and waiting times .RespawnAliens lda #0 sta ALIEN1OFFSET sta ALIEN2OFFSET sta ALIEN3OFFSET sta ALIEN4OFFSET sta ALIEN5OFFSET sta ALIEN1SPAWNED sta ALIEN2SPAWNED sta ALIEN3SPAWNED sta ALIEN4SPAWNED sta ALIEN5SPAWNED sta ALIEN1WAITTIME sta ALIEN2WAITTIME sta ALIEN3WAITTIME sta ALIEN4WAITTIME sta ALIEN5WAITTIME rts ;Alien spawning and movement properties have been set ;by macros. In order to avoid re-typing in the same ;code for each different alien. Each alien property ;is called through a different subroutine. TestAlien1 +TestAlien ALIEN1DEAD,ALIEN1EXPLODEDELAY,ALIEN1EXPLODEPOINTER,$07FA,$D029,OBJPOS+4,OBJPOS+5,ALIEN1OFFSET,ALIEN1SPAWNED,ALIEN1WAITTIME,ALIEN1SPAWNLIMIT TestAlien2 +TestAlien ALIEN2DEAD,ALIEN2EXPLODEDELAY,ALIEN2EXPLODEPOINTER,$07FB,$D02A,OBJPOS+6,OBJPOS+7,ALIEN2OFFSET,ALIEN2SPAWNED,ALIEN2WAITTIME,ALIEN2SPAWNLIMIT TestAlien3 +TestAlien ALIEN3DEAD,ALIEN3EXPLODEDELAY,ALIEN3EXPLODEPOINTER,$07FC,$D02B,OBJPOS+8,OBJPOS+9,ALIEN3OFFSET,ALIEN3SPAWNED,ALIEN3WAITTIME,ALIEN3SPAWNLIMIT TestAlien4 +TestAlien ALIEN4DEAD,ALIEN4EXPLODEDELAY,ALIEN4EXPLODEPOINTER,$07FD,$D02C,OBJPOS+10,OBJPOS+11,ALIEN4OFFSET,ALIEN4SPAWNED,ALIEN4WAITTIME,ALIEN4SPAWNLIMIT TestAlien5 +TestAlien ALIEN5DEAD,ALIEN5EXPLODEDELAY,ALIEN5EXPLODEPOINTER,$07FE,$D02D,OBJPOS+12,OBJPOS+13,ALIEN5OFFSET,ALIEN5SPAWNED,ALIEN5WAITTIME,ALIEN5SPAWNLIMIT ;Initialise all row positions of the game map ;so that it restarts after the 255th byte read ;in the map.Or whenever a new level/game starts InitMapPosition lda #PLAYERDIESFXTABLE ldx #14 JSR SFXINIT lda #1 sta PLAYERDEAD rts ;Now test the bullet to aliens. If the ;alien is already dead, it should not ;be destroyed. Otherwise, destroy the alien TestAliensToBullet jsr TestAlien1ToBullet jsr TestAlien2ToBullet jsr TestAlien3ToBullet jsr TestAlien4ToBullet jsr TestAlien5ToBullet rts ;Macro called !macro TestBulletToAliens ALIENDEAD, ALIENOFFSET, SPRITEX, SPRITEY, ALIENEXPLODEDELAY, ALIENEXPLODEPOINTER { lda ALIENDEAD ;Check if alien is already dead cmp #1 ;YES. beq .SkipAlienCollision ;Ignore all collision lda ALIENOFFSET ;Check if alien is offset cmp #1 ;YES beq .SkipAlienCollision ;Ignore al collision lda SPRITEX ;Read alien position X cmp BULLETCOLLISION ;Has sprite reached left most range of bullet? bcc .SkipAlienCollision ;NO, no collision cmp BULLETCOLLISION+1 ;Has sprite reached right most range of bullet? bcs .SkipAlienCollision ;No, no collision lda SPRITEY ;Read alien position Y cmp BULLETCOLLISION+2 ;Has the sprite reached the top most range of bullet? bcc .SkipAlienCollision ;No, no collision cmp BULLETCOLLISION+3 ;Has the sprite reached the bottom most range of bullet? bcs .SkipAlienCollision ;No, no collision lda SPRITEX ;Record last X position of alien sta LASTALIENPOSX ;Store it to last alien X position X lda SPRITEY ;Record last Y position of alien sta LASTALIENPOSY ;Store it to last alien Y position jsr AddScore lda #0 ;Get rid of the player's bullet sta OBJPOS+3 sta ALIENEXPLODEDELAY ;Reset animation pointer and sta ALIENEXPLODEPOINTER ;delay for sprite explosion inc ALIENHITCOUNT lda #1 ;Declare the alien to be dead sta ALIENDEAD lda #ALIENEXPLODESFXTABLE ldx #14 jsr SFXINIT .SkipAlienCollision rts } ;Linked to the macro code above: TestAlien1ToBullet +TestBulletToAliens ALIEN1DEAD, ALIEN1OFFSET, OBJPOS+4,OBJPOS+5,ALIEN1EXPLODEDELAY, ALIEN1EXPLODEPOINTER TestAlien2ToBullet +TestBulletToAliens ALIEN2DEAD, ALIEN2OFFSET, OBJPOS+6,OBJPOS+7,ALIEN2EXPLODEDELAY, ALIEN2EXPLODEPOINTER TestAlien3ToBullet +TestBulletToAliens ALIEN3DEAD, ALIEN3OFFSET, OBJPOS+8,OBJPOS+9,ALIEN3EXPLODEDELAY, ALIEN3EXPLODEPOINTER TestAlien4ToBullet +TestBulletToAliens ALIEN4DEAD, ALIEN4OFFSET, OBJPOS+10,OBJPOS+11,ALIEN4EXPLODEDELAY, ALIEN4EXPLODEPOINTER TestAlien5ToBullet +TestBulletToAliens ALIEN5DEAD, ALIEN5OFFSET, OBJPOS+12,OBJPOS+13,ALIEN5EXPLODEDELAY, ALIEN5EXPLODEPOINTER rts ;Test camel to ship TestCamelToShip lda OBJPOS+14 cmp SHIPCOLLISION bcc NoCamelCollected cmp SHIPCOLLISION+1 bcs NoCamelCollected lda OBJPOS+15 cmp SHIPCOLLISION+2 bcc NoCamelCollected cmp SHIPCOLLISION+3 bcs NoCamelCollected lda #0 sta OBJPOS+14 sta OBJPOS+15 ldx #14 lda #CAMELPICKEDSFXTABLE jsr SFXINIT lda #$00 ldy #$00 scoreCamel jsr ScoreMain iny cpy #50 bne scoreCamel lda PADENABLED cmp #1 beq SKIPQUOTA inc QUOTAPICKED+1 lda QUOTAPICKED+1 cmp #249 bne SKIPQUOTA lda #239 sta QUOTAPICKED+1 inc QUOTAPICKED NoCamelCollected SKIPQUOTA rts CheckMatchingQuotas lda PADENABLED cmp #1 beq SKIPQUOTAMANAGEMENT lda QUOTAPICKED cmp CAMELQUOTA beq CheckNextQuota rts CheckNextQuota lda QUOTAPICKED+1 cmp CAMELQUOTA+1 beq EnableLaunchPad rts EnableLaunchPad ldx #$00 ShowLandText lda LANDTEXT,x clc adc #191 sta $078a,x inx cpx #LANDTEXTEND-LANDTEXT bne ShowLandText lda #LANDSFXTABLE ldx #14 jsr SFXINIT lda #1 sta PADENABLED SKIPQUOTAMANAGEMENT rts ;Every time an alien is hit, or a camel has been ;collected. Points should be scored. However the ;value of the amount of points scored should be ;based on the alien shot. So the score calling loop ;is self-modified. AddScore ldy #0 MakeScore jsr ScoreMain iny cpy ALIENSCORE bne MakeScore rts ;Main scoring code. Scores are added in 100's ScoreMain inc SCORE+3 ldx #$03 ScoreLoop lda SCORE,x cmp #249 ;Character 249 in custom GFX is past digits bne ScoreOkay lda #239 ;Reset to custom character 0 sta SCORE,x inc SCORE-1,x ScoreOkay dex bne ScoreLoop rts ;Mask the score panel, so all digits are placed ;on to the actual score panel. Every time a ;scoring, shield or lives event occurs, the ;panel is updated. MaskPanel ldx #$00 MaskScore lda SCORE,x ;Get active score and sta $079a,x ;put to screen position inx cpx #6 ;6 digits max bne MaskScore lda LIVES ;Grab lives value sta $07a5 ldx #$00 CopyShield lda SHIELD,x sta $07ac,x lda QUOTAPICKED,x sta $07b2,x lda CAMELQUOTA,x sta $07b5,x lda LEVEL sta $07bb inx cpx #2 bne CopyShield rts ;Sprite to background collision routine ;first check if the player is already dead ;if it is. Then skip all collision. To avoid ;repeating typing in. Generate another macro ;Collision area is only the middle of the ;player ship. SpriteToBackground lda PLAYERDEAD cmp #1 beq SkipCollision lda $d000 ;Read hardware position of player sec xcoord sbc #$10 ;X-Co-ordinates sta ZP lda $d010 ;Sprite MSB sbc #$00 ;sta $fa lsr lda ZP ror lsr lsr sta ZP+3 lda $d001 ;Read hardware Y position of player sec ycoord sbc #$2a ;Y-Co ordinates set lsr lsr lsr sta ZP+4 lda #SCRN sta ZP+2 ldx ZP+4 beq CheckChars BGCLOOP lda ZP+1 clc adc #$28 sta ZP+1 lda ZP+2 adc #$00 sta ZP+2 dex bne BGCLOOP CheckChars ldy ZP+3 lda (ZP+1),y cmp #STAR1 beq SafeChar cmp #STAR2 beq SafeChar cmp #STAR3 beq SafeChar cmp #STAR4 beq SafeChar jmp CheckLandingPad SafeChar SkipCollision rts CheckLandingPad cmp #LANDINGPAD1 beq CheckSafeToLand cmp #LANDINGPAD2 beq CheckSafeToLand cmp #LANDINGPAD3 beq CheckSafeToLand cmp #LANDINGPAD4 beq CheckSafeToLand cmp #LANDINGPAD5 beq CheckSafeToLand jmp CheckLazerBeam CheckSafeToLand lda PADENABLED cmp #1 beq LevelComplete jmp PlayerIsHit CheckLazerBeam cmp #LAZERBEAM beq CheckBeamOn jmp PlayerIsHit CheckBeamOn lda LAZERON cmp #1 bne SafeChar jmp PlayerIsHit LevelComplete ;Level is complete, so clear the sprites. ;Flash the screen (To make it look as if the ;alien planet is destroyed). ;then display the level complete message ldx #$00 ClearSprites lda #$00 sta $d000,x sta OBJPOS,x inx cpx #$10 bne ClearSprites lda #BONUSSFXTABLE ldx #14 jsr SFXINIT ;Destroy Screen Mode ldx #0 stx EXPLODECOLOURPOINTER ;Main loop for the colour explosion effect DestroyPlanetLoop jsr SyncGameTimer jsr StarField jsr AnimPad jsr TestLazer ;Colour explosion routine ldx EXPLODECOLOURPOINTER lda EXPLODECOLOURTABLE,x sta $d020 sta $d021 inx cpx #EXPLODECOLOURTABLEEND-EXPLODECOLOURTABLE beq PlanetDestroyFinished inc EXPLODECOLOURPOINTER jmp DestroyPlanetLoop PlanetDestroyFinished ;Re-Display the starfied ldx #$00 RedisplayStarfield lda STARTMAP,x sta SCRN,x lda STARTMAP+$100,x sta SCRN+$100,x lda STARTMAP+$200,x sta SCRN+$200,x lda STARTMAP+$2e8,x sta SCRN+$2e8,x inx bne RedisplayStarfield ;Then restore the statuspanel ldx #$00 RestoreStatusPanel lda STATUSPANEL,x sta SCRN+800,x inx cpx #STATUSPANELEND-STATUSPANEL bne RestoreStatusPanel jsr MaskPanel ;Display the well done text, the ;same way as we did the title text ldx #$00 DisplayWellDone lda wdline1,x cmp #$20 beq .skipSpaceChar1 clc adc #191 ;Convert to custom letter chars sta SCRN+360,x .skipSpaceChar1 lda wdline2,x cmp #$20 beq .skipSpaceChar2 clc adc #191 sta SCRN+440,x .skipSpaceChar2 inx cpx #$28 bne DisplayWellDone ;Now do the bonus phase - based on ;shield count BONUSPHASE jsr SyncGameTimer jsr StarField jsr AddScore jsr DoBonusShield jmp BONUSPHASE ;Count down the shield, like before ;with the drained shield routine. DoBonusShield dec SHIELD+1 lda SHIELD+1 cmp #238 ;Is shield LOWER than custom digit 0 bne BONUSSHIELDOK lda #249 sta SHIELD+1 dec SHIELD lda SHIELD cmp #238 beq BONUSFINISHED BONUSSHIELDOK jsr MaskPanel rts BONUSFINISHED ;Now give the player an extra life lda #EXTRALIFESFXTABLE ldx #14 jsr SFXINIT lda LIVES cmp #248 ;Over digit 9? bcs WAITLEAVEBONUS ;Play extra lives SFX inc LIVES WAITLEAVEBONUS ;Wait for the player to press FIRE jsr SyncGameTimer jsr StarField jsr TestLazer jsr AnimatePad jsr MaskPanel lda #239 sta SHIELD sta SHIELD+1 lda $dc00 lsr lsr lsr lsr lsr bit FIREBUTTON ror FIREBUTTON bmi WAITLEAVEBONUS bvc WAITLEAVEBONUS inc LEVELPOINTER ;Setup the next level pointer inc LEVEL ;Move on to the next level jmp NEWLEVEL ;Animate the landing pad lights - so that they ;indicate that it is safe for the player to land ;and move on to the next level AnimatePad lda PADENABLED cmp #1 bne IgnorePad jmp AnimPad IgnorePad ldx #$00 RestorePad lda 223*8+$0800,x sta 33*8+$0800,x sta 38*8+$0800,x inx cpx #8 bne RestorePad rts AnimPad lda PADANIMDELAY cmp #8 beq DoPadAnimation inc PADANIMDELAY rts DoPadAnimation lda #0 sta PADANIMDELAY lda PADANIMPOINTER cmp #0 beq COPYCHAR220 cmp #1 beq COPYCHAR222 rts COPYCHAR220 ldx #$00 copyloop01 lda 223*8+$0800,x sta 33*8+$0800,x lda 220*8+$0800,x sta 38*8+$0800,x inx cpx #8 bne copyloop01 lda #1 sta PADANIMPOINTER rts COPYCHAR222 ldx #$00 copyloop02 lda 223*8+$0800,x sta 38*8+$0800,x lda 220*8+$0800,x sta 33*8+$0800,x inx cpx #8 bne copyloop02 lda #0 sta PADANIMPOINTER rts ;Scoring - Either the game has been complete ;or the game is lost. A subroutine is called ;here to convert the player's score into ;default number char codes, and then ;check compare the value of the player's ;score to the high score table. If new ;high score. A message near to the bottom ;should display a new high score. CheckHiScore ldx #$00 ConvertCharsToNumbers ;Convert the score's digit chars ;into default numbers, as FINALSCORE lda SCORE,x sec sbc #191 ;Charset to NUMBERS sta FINALSCORE,x inx cpx #$06 ;6 chars max bne ConvertCharsToNumbers ;Now check if the final score is ;higher than the hi score achieved lda FINALSCORE sec lda HISCORE+5 sbc FINALSCORE+5 lda HISCORE+4 sbc FINALSCORE+4 lda HISCORE+3 sbc FINALSCORE+3 lda HISCORE+2 sbc FINALSCORE+2 lda HISCORE+1 sbc FINALSCORE+1 lda HISCORE sbc FINALSCORE bpl NoHiScore ;Then display the well done text, underneath ;the GAME OVER text. ldx #$00 PutHiScoreText lda hiline2,x cmp #$20 beq skipSPHi2 clc adc #191 sta SCRN+440,x skipSPHi2 inx cpx #$28 bne PutHiScoreText ;A hi score hass been achieved. Make old score ;the new high score. ldx #$00 MakeNewHiScore lda FINALSCORE,x sta HISCORE,x inx cpx #$06 bne MakeNewHiScore rts ;No high score achieved. So display the ;message SORRY, NOT A HIGH SCORE! under GAME ;OVER NoHiScore ldx #$00 putNoHiText lda hiline1,x cmp #$20 beq skipSPCNoHi clc adc #191 sta SCRN+440,x skipSPCNoHi inx cpx #$28 bne putNoHiText rts ;Initialise interrupts, switch off all ;IRQ requests that are still playing in ;the background. InitInterrupts sei lda #$36 ;Allow use $0400-$bfff memory, with sta $01 ;KERNAL enabled. lda #$00 ;Switch of IRQs sta $d019 sta $d01a lda #$81 ;Disable CIA interrupt mode sta $dc0d sta $dd0d ldx #$31 ;Destroy low/hibyte of interrupt ldy #$ea ;and restore machine to its state stx $0314 sty $0315 ;Clear the screen with black and zero bytes ldx #$00 ClearScreen lda #$00 sta $0400,x sta $0500,x sta $0600,x sta $06e8,x lda #$00 sta $d800,x sta $d900,x sta $da00,x sta $dae8,x inx bne ClearScreen ;Zero all sprite positions ldx #$00 ZSPR lda #$00 sta $d000,x sta OBJPOS,x inx cpx #16 bne ZSPR rts ;PAL/NTSC music player MUSICPLAYER lda SYSTEM ;Check system type cmp #1 beq PAL inc NTSCTIMER lda NTSCTIMER cmp #6 beq ResetNTSCTimer PAL jsr MUSICPLAY rts ResetNTSCTimer lda #0 sta NTSCTIMER rts !source "pointers.asm"