; Quikman 8k ROM cartridge for Commodore VIC 20 ; written by Robert Hurst ; originally used Commodore VICMON (SYS 45056) ; ported using the CA65 assembler (cc65.org) ; updated version: 07-Sep-2009 ; ; see quikman-8k.bat for compile, link, and go instructions ; ; to run the binary using viceteam.org project: ; xvic -memory none -ntsc -sound -joydev1 2 -cartA quikman-8k.a0 ; to run the binary using mess.org project: ; mess -view "Pixel Aspect (25:31)" vic20 -cart1 quikman-8k.a0 ; ; pertinent VIC20 symbols JIFFYH = $A0 ; jiffy-clock hi byte value JIFFYM = $A1 ; jiffy-clock mid byte value JIFFYL = $A2 ; jiffy-clock low byte value CLRPAGE = $F4 ; color memory page (unexpanded = $97) CTRLCSHIFT = $028D ; keyboard flag: control/commodore/shift CASSBUFF = $033C ; cassette buffer ;RESET = $FD22 ; warm startup CHROUT = $FFD2 ; print character with cursor translation GETIN = $FFE4 ; get a character from keyboard queue ; ; my symbol / memory map PPILLTIMER = $10 ; powerpill effectiveness timer FRUITTIMER = $39 ; 0 - 250 FRUITFLAG = $3A ; zero or non-zero, if fruit has been activated PPILLFLAG = $3B ; just ate a powerpill this turn (0=no) CHOMP = $3C ; pointer into sound effect for fruit and fleeing monsters CHEWING = $3D ; flag whether quikman just ate a dot or not DIGIT = $3E ; award points at this digit place POINTS = $3F ; how many points scored OLDDIR = $40 ; direction sprite was last moving in NEWDIR = $41 ; direction sprite wants to take, if valid by MAZEMOVE JOYVAL = $42 ; last joystick read value QMANDIR = $43 ; quikman's current direction (0=right,1=down,2=left,3=up) FRAME = $44 ; frame number LIVES = $45 ; 0 - 3 FLASHPILL = $46 ; powerpill blink counter (0-30) EXTRAQMAN = $47 ; bonus quickman flag (0=unused) DEMOQMAN = $48 ; spirit of quickman index (0-3) FRUITLEVEL = $49 ; 0 - 12 DOTS = $4A ; 0 - 170 PENALTY = $4B ; $4B-$4E monsters are free-to-roam flag ; = $4F ; $4F-$52 monsters current direction (0=right,1=down,2=left,3=up) ; = $53 ; $53,$55,$57,$59 monster's knowledge of quikman's "X" coord was ; = $54 ; $54,$56,$58,$5A monster's knowledge of quikman's "Y" coord was MONMOVE = $61 ; $61-$64 monster array for its next best move ; = $69 ; temporary var FLEEINGSCORE= $70 ; fleeing monster score: 2, 4, 8, 16 ; ; other constants FRUITCELLX = 10 FRUITCELLY = 13 POOLSIZE = $40 ;********************************************************************* ; SOFT reset entry point ; LDA VIC+$0F CMP #$0E BEQ @cont JMP INTRO ; reset sound channels @cont: LDA #$00 TAY @snd: STA VIC+$0A,Y INY CPY #$04 BNE @snd LDA #$8F ; brown & highest STA VIC+$0E ; auxiliary color & volume ; my interrupt vector init SEI LDX #BACKGROUND STX $0314 STY $0315 CLI JSR RESTORE ; LDA #$03 STA COLORCODE LDX #$00 LDY PLAYROWS DEY JSR SSSPLOT @msg: LDA BANNERMSG,Y JSR SSSPRINT LDY CRSRCOL BNE @msg LDX #$0E LDY PLAYROWS DEY JSR SSSPLOT LDY CRSRCOL LDA (COLORLINE),Y AND #$E0 ORA #$09 STA (COLORLINE),Y INY STA (COLORLINE),Y ; DEMO: JSR INITVARS LDY #$00 STY LIVES JSR GAMEOVER LDY #$0A STY SSS @loop: LDA FRAME AND #$7F BNE @slow @skip: INC FRUITLEVEL LDX FRUITLEVEL CPX #$0D BCC @fruit STX PPILLFLAG ; demo powerpill LDX #$00 STX FRUITLEVEL @fruit: LDA FRUITCLR,X STA COLORCODE LDX #FRUITCELLX LDY #FRUITCELLY JSR SSSPLOT LDX FRUITLEVEL LDA FRUIT,X JSR SSSPOKE LDA #$50 STA FRUITTIMER STA FRUITFLAG @slow: JSR NPC ; demo mode LDY #$01 JSR SSSFLIP LDA SSS EOR #$1E STA SSS LDY #$01 JSR SSSFLIP @scan: JSR GETIN ; get keyboard CMP #$42 ; got B ? BNE @no JMP READY @no: CMP #$85 ; got F1 ? BEQ RESETGAME ; try again ... LDA #$FF STA $9122 LDA $9111 AND #$20 ; FIRE BNE @loop ; ;********************************************************************* RESETGAME: LDA #$03 ; start with 3-lives STA LIVES LDY #$FF ; -1 will become 0 at start of "next" level STY FRUITLEVEL JSR GAMEOVER ; clear status LDX #$00 ; reset score STX EXTRAQMAN ; reset bonus @loop1: LDA #$B0 ; each digit to "0" STA $1A06,X ; into savebuffer INX ; do next digit CPX #$06 ; all 6 of them BNE @loop1 ; STARTLVL: JSR RESTORE ; initialize new level ; RESETCHR: JSR INITVARS LDA #$1E ; 1st page where quikman is on STA SPRITEIMG+1 LDA FRUITLEVEL BNE @ok LDA EXTRAQMAN BNE @ok LDA LIVES CMP #$03 BCC @ok LDA #$A0 STA SPRITEIMG LDA #$01 ; only quikman as a ball STA SSS JSR TUNE @ok: LDA #$98 ; start quikman off with a smug smile STA SPRITEIMG LDA #$1F ; turn on sprites 0-4 STA SSS LDX #$0C @smug: LDA #$0A JSR PAUSE ; then he sees there are monsters ... DEX BPL @smug ; LDX #FRUITCELLX-2 LDY #FRUITCELLY JSR SSSPLOT LDA #$07 STA COLORCODE LDX #$00 @loop2: LDA $C378,X ; print READY from ROM AND #$BF ORA #$80 JSR SSSPRINT INX TXA ASL TAY LDA #$88 STA SPRITEIMG,Y ; restore monster caged image (heh) LDA #$1E STA SPRITEIMG+1,Y CPX #$05 BNE @loop2 ; how geeky is that? LDX #$B8 STX SPRITEIMG ; quikman gets ready LDX #$10 @ready: LDA #$08 JSR PAUSE ; wait 2+ seconds DEX BPL @ready LDX #FRUITCELLX-2 LDY #FRUITCELLY JSR SSSPLOT LDX #$00 @loop4: LDA #$60 ; erase READY JSR SSSPRINT INX CPX #$05 BNE @loop4 ; ; zero $39 - $43 ZEROVARS: LDX #$00 STX FRUITFLAG STX PPILLFLAG LDX #$02 STX QMANDIR ; start off going LEFT STX JOYVAL ; preload last joystick value as going LEFT ; ;********************************************************************* PLAYLOOP: LDA #$07 ; 8-levels to warp SEC SBC FRUITLEVEL ; progressive speed BCC @warp BEQ @warp TAY @sleep: INX BNE @sleep DEY BNE @sleep ; one 1000, two 1000, three 1000, ... @warp: LDY #$00 STY $00 ; quikman is sprite #0 STY $01 LDA QMANDIR STA OLDDIR ; save last direction quikman was going in LDA SPRITEX CMP #$11 BCC @skip1 ; no new moves while in the void CMP #$B0 BCS @skip1 ; no new moves while in the void LDX JOYVAL ; recall last joystick value STY $9113 LDA #$7F STA $9122 LDA $9120 AND #$80 ; JOY 3 BNE @joy0 LDX #$00 @joy0: LDA #$FF STA $9122 LDY $9111 TYA AND #$08 BNE @joy1 LDX #$01 @joy1: TYA AND #$10 BNE @joy2 LDX #$02 @joy2: TYA AND #$04 BNE @joy3 LDX #$03 @joy3: STX JOYVAL ; save TXA STA NEWDIR ; do the same for the joystick JSR MAZEMOVE BCS @skip1 ; is the direction valid? LDA JOYVAL ; yes, STA QMANDIR ; request quikman to move in direction of joystick CLC BCC @skip2 @skip1: LDA QMANDIR STA NEWDIR JSR MAZEMOVE ; keep the current direction going? @skip2: LDA SPRITEX CMP #$09 BCS @skip3 ; is quikman at end of tunnel left? LDX SSSCLIPX DEX TXA @skip3: CMP SSSCLIPX ; is quikman at end of tunnel right? BCC @skip4 LDA #$09 @skip4: STA SPRITEX ; put quikman at beginning of tunnel left ; LDX #$A0 ; closed mouth LDA SPRITEX ORA SPRITEY AND #$02 BNE @anim LDA QMANDIR ; take 0=right, 1=down, 2=left, 3=up value ASL ; multiply by 8 to get address ASL ASL CLC ADC #$A8 ; add base offset TAX @anim: STX SPRITEIMG ; LDX #$00 ; use X as a flag LDA SPRITEX AND #$07 CMP #$04 BNE @skip5 ; is quikman in the middle of a left/right cell? INX LDA QMANDIR ; yes, 0=right, 2=left EOR #$02 TAY BEQ @skip6 ; going left, use 1st saveback cell DEY BNE @skip6 ; going right, use overflow saveback cell @skip5: LDA SPRITEY AND #$07 CMP #$03 BNE @skip6 ; is quikman in the middle of an up/down cell? INX LDY QMANDIR CPY #$01 ; going down, use overflow saveback cell BNE @up LDY PLAYCOLS BNE @skip6 @up: LDY #$00 ; going up, use 1st saveback cell @skip6: CPX #$00 BNE @skip7 ; does quikman have something in its mouth? JMP NPCNEXT ; no, continue play @skip7: STY R0 LDX SPRITEX LDY SPRITEY LDA #$A0 ; when you are in the void, JSR SSSPEEKXY ; you are over a space CMP #$A0 BEQ @q LDA CRSRCOL CLC ADC R0 TAY LDA (SCRNLINE),Y ; retrieve the character from quikman's saveback buffer CMP #$60 BNE @skip8 @q: JMP PLAYLOOP ; nothing to eat here, so move a bit faster ; check what was just eaten ... @skip8: TAX ; save that something in X CPX #$5E BCC @next CPX #$69 BCC @erase @next: JMP NPCNEXT @erase: LDA #$60 ; replace the cell quikman is on with an empty space STA (SCRNLINE),Y CPX #$5E ; is it a dot? BNE POWERUP LDA #$01 STA POINTS ; score 1 STA CHEWING ; quikman has to chew this dot, monsters keep movin' LDA #$0A ; score it @ 10-point digit STA DIGIT ; POWERUP: CPX #$61 BCC @skip1 ; is X < 33 ? CPX #$69 ; no, is X >= 41 ? BCC @cc ; ate a piece of fruit? JMP NPCNEXT @cc: TXA ; YUMMY! SEC SBC #$61 ; strip off char code for score index PHA TAX LDA FRUITSCORE,X STA POINTS ; award points LDA #$09 STA DIGIT ; in hundreds STA CHOMP LDA #$80 STA FRUITTIMER LDA #$03 STA COLORCODE LDX #FRUITCELLX-1 LDY #FRUITCELLY JSR SSSPLOT PLA STA R0 ASL CLC ADC R0 TAX LDY #$03 @fs: LDA FRUITCHAR,X JSR SSSPRINT INX DEY BNE @fs BEQ NPCNEXT @skip1: CPX #$5F ; ate a powerpill? BNE EATING ; no, but I did eat a dot LDA #$05 STA POINTS ; award 5-points LDA #$0A STA DIGIT ; score @ 10-digit STA PPILLFLAG BEQ NPCNEXT ; powerpills are dots on steroids, account for it ; EATING: INC DOTS ; ate a dot, account for it LDA DOTS CMP #$AA ; are all dots eaten? BNE NPCNEXT ;=== achieved end of level === WONLEVEL: LDA #$98 ; quikman ends with a smug smile STA SPRITEIMG LDA #$40 STA FRAME JSR PAUSE @loop: DEC FRAME LDA FRAME AND #$07 TAX JSR MAZEPAINT LDA FRAME AND #$07 BNE @next LDA SSS EOR #$1E STA SSS ; blink monsters @next: LDX #$04 @tiny: TXA ASL TAY LDA #$60 ; ghost ends small STA SPRITEIMG,Y DEX BNE @tiny LDY #$00 JSR SSSFLIP LDA FRAME CMP #$06 BNE @loop ; continue until true blue LDA #$40 JSR PAUSE JMP STARTLVL ; NPCNEXT: JSR GETIN ; get keyboard CMP #$85 ; got F1 ? BEQ WONLEVEL ; cheater! JSR NPC JMP PLAYLOOP ; ;********************************************************************* ; non-player characters & events NPC: LDA FRUITFLAG BNE @skip3 ; is fruit already on display? LDA DOTS CMP #$4B ; has the 75th dot been eaten? BEQ @skip1 CMP #$7D ; has the 125th dot been eaten? BNE @skip3 @skip1: LDX FRUITLEVEL ; prepare thy bonus CPX #$0C ; reach the last level? BCC @skip2 LDX #$0C ; only the key is left, and it leaves a bad metallic after-taste @skip2: TXA PHA LDA FRUITCLR,X STA COLORCODE LDX #FRUITCELLX LDY #FRUITCELLY JSR SSSPLOT PLA TAX LDA FRUIT,X JSR SSSPOKE ; display fruit LDA #$FA ; 250-moves and counting STA FRUITTIMER ; reset fruit timer STA FRUITFLAG @skip3: LDA FRUITTIMER ; fruit is on display BEQ @skip4 ; nothing to do DEC FRUITTIMER ; remove a tick BNE @skip4 ; there is still time left LDX #FRUITCELLX-1 LDY #FRUITCELLY LDA LIVES BNE @demo INX @demo: JSR SSSPLOT LDA #$60 ; time's up! JSR SSSPRINT ; no more fruit LDA LIVES BEQ @skip4 LDA #$60 ; time's up! JSR SSSPRINT ; no more fruit score LDA #$60 ; time's up! JSR SSSPRINT ; no more fruit score @skip4: LDA DOTS CMP #$4C ; has the 76th dot been eaten? BEQ @skip5 CMP #$7E ; has the 126th dot been eaten? BNE @skip6 @skip5: LDA #$00 STA FRUITFLAG ; more fruit potential on this level ; @skip6: LDA PPILLFLAG BEQ KISSING ; just swallowed a powerpill? LDA #$00 ; account for that action STA PPILLFLAG LDA #$02 ; start scoring @ 200-points STA FLEEINGSCORE LDX FRUITLEVEL TXA AND #$07 BEQ @break ; every 8-levels, keep timer up CPX #$10 BCS @timer ; 16-levels of powerpill timing TXA @break: ASL ; x2 ASL ; x2 AND #$3F EOR #$3F ; invert A CPX #$05 BCC @timer ; timer good to the 1st apple LSR ; 1/2 @timer: STA PPILLTIMER ; set powerpill timer LDY #$04 @loop1: LDX PENALTY-1,Y BNE @skip7 ; is monster waiting in cage already? LDA #%00110110 ; no, make monster blue STA SPRITEDEF,Y TYA ASL TAX LDA #$90 ; make monster fleeing STA SPRITEIMG,X LDA $4E,Y EOR #$02 ; and reverse its direction STA $4E,Y @skip7: DEY BNE @loop1 ; ; check all monsters if any are in contact with quikman KISSING: LDY #$04 KISSME: LDA LIVES BEQ NEXTKISS LDA SPRITEX CMP SPRITEX,Y BNE @skip3 LDA SPRITEY SEC SBC SPRITEY,Y BCS @skip2 EOR #$FF @skip2: CMP #$05 BCS @skip3 BCC ENGAGED ; is quikman engaged with a monster? @skip3: LDA SPRITEY CMP SPRITEY,Y BNE NEXTKISS LDA SPRITEX SEC SBC SPRITEX,Y BCS @skip4 EOR #$FF @skip4: CMP #$05 BCC ENGAGED ; is quikman engaged with a monster? ; NEXTKISS: DEY ; next monster BNE KISSME JMP MONSTERS ; quikman is still freely running! ; ENGAGED: TYA ASL TAX LDA SPRITEIMG,X CMP #$60 ; is monster returning to cage? BEQ NEXTKISS CMP #$90 ; is monster fleeing? BNE DEAD ; no, quikman bites the dust LDA #$09 ; ahah! caught a little sickly one! STA DIGIT ; in hundreds LDA FLEEINGSCORE STA POINTS ; fleeing monster score ASL ; next is worth x2 bonus STA FLEEINGSCORE TYA PHA TXA PHA LDA #$D0 STA VIC+$0A LDA SSS EOR SSSMASK,Y STA SSS LDX PPILLTIMER LDA #$01 JSR PAUSE LDA #$98 ; quikman smiles STA SPRITEIMG LDA #$01 JSR PAUSE LDA JIFFYL CLC ADC #$20 @loop: LDY JIFFYL INY @loop1: CPY JIFFYL BNE @loop1 STX PPILLTIMER INC VIC+$0A CMP JIFFYL BNE @loop ; wait up to a jiffy LDA #$00 STA VIC+$0A PLA TAX PLA TAY LDA #$60 ; monster runs back to cage STA SPRITEIMG,X LDA SSS EOR SSSMASK,Y STA SSS LDA QUIKMANCLR,Y STA SPRITEDEF,Y JMP NEXTKISS ; is there another monster here? ; DEAD: PLA ; remove quikman's call to NPC from stack PLA ; because he just died . . . LDX #$10 @oops: LDA #$06 JSR PAUSE DEX BNE @oops ; death sequence LDA #$01 ; only feature quikman dying STA SSS LDA #$A0 ; low-order byte of 1st quikman image STA SPRITEIMG LDX #$01 @loop: LDA QUIKMANCLR,X ; reset monsters starting colors STA SPRITEDEF,X ; into their sprite color registers TXA ASL TAY LDA #$70 ; reset monsters as looking down STA SPRITEIMG,Y INX CPX #$05 BNE @loop ; LDA #$F0 STA VIC+$0C LDA #$20 STA FRAME ; rotate quikman 8 times @loop1: LDA SPRITEIMG CMP #$C0 ; are we at the 4th quikman image? BCC @skip INC VIC+$0C LDA #$A0 ; reset to 1st quikman image @skip: CLC ADC #$08 ; advance to next image STA SPRITEIMG DEC VIC+$0C ; wooosh! DEC VIC+$0C DEC VIC+$0C LDA #04 JSR PAUSE DEC FRAME BNE @loop1 ; repeat next sequence ; LDX #$C8 ; POOF1 STX SPRITEIMG ; explode! LDA #$0A JSR PAUSE LDX #$D0 ; POOF2 STX SPRITEIMG ; smoke! LDA #$08 JSR PAUSE LDX #$D8 ; POOF3 STX SPRITEIMG ; dust! LDA #$06 JSR PAUSE LDA #$00 STA SSS STA VIC+$0C LDA #$0A JSR PAUSE DEC LIVES BEQ FINALITY ; any lives remaining? LDA #$07 STA COLORCODE LDY #$17 LDX LIVES JSR SSSPLOT LDA #$59 JSR SSSPOKE LDA #$0A JSR PAUSE LDA #$5A JSR SSSPOKE LDA #$08 JSR PAUSE LDA #$5B JSR SSSPOKE LDA #$01 STA SSS LDA #$C8 ; POOF1 STA SPRITEIMG JSR INITVARS LDA #$06 JSR PAUSE LDA #$60 JSR SSSPOKE JMP RESETCHR ; quikman still has life -- try again! ; FINALITY: LDY #$00 JSR GAMEOVER LDY #$00 STY SSS JSR SSSFLIP LDA #$A0 JSR PAUSE JMP DEMO ; this game is really over now ; ;********************************************************************* MONSTERS: LDA #$04 STA $00 ; start with monster #4 ; DOMONSTER: LDA $00 TAY ASL ; x2 STA $01 LDX PENALTY-1,Y BEQ ITMOVES ; is this monster free to roam? LDA FRAME AND #$03 BEQ @anim DEX ; no, countdown to freedom STX PENALTY-1,Y @anim: LDA #$88 ; reset monster as caged, but coming out CPX #$10 BCC @eyes TXA AND #$08 BNE @skip LDA #$68 ; reset monster as caged looking right BNE @eyes @skip: LDA #$78 ; reset monster as caged looking left @eyes: LDX $01 STA SPRITEIMG,X LDA SPRITEX,Y AND #$F8 STA SPRITEX,Y ; NEXTMONSTER: DEC $00 ; process next monster BNE DOMONSTER INC FRAME INC $00 ; let's see if red needs a burst LDA SPRITEY+1 CMP #$68 ; no bonus at cage row BEQ @fini AND #$07 ORA SPRITEX+1 AND #$0F BEQ DOMONSTER LDA CHEWING BNE @skip1 ; is quikman eating a dot? @fini: LDY LIVES BEQ @quit LDY #$00 JSR SSSFLIP @quit: RTS ; no, we're done @skip1: LDA DOTS AND #$01 BNE @fini ; quikman can swallow every other dot faster LDY #$00 JSR SSSFLIP JMP MONSTERS ; yes, chasing monsters get another turn ; ITMOVES: LDX $01 ; get pairing index LDA SPRITEIMG,X CMP #$60 BNE @go ; small ghost going home? LDA SPRITEX,Y CMP #$60 BNE @caged LDA SPRITEY,Y CMP #$58 BNE @caged ; is monster above cage ($60,$58 coord) doorway ? LDX $00 INC SPRITEY,X ; move into doorway LDX #$01 STX $4E,Y ; make direction DOWN to go into cage @caged: LDX $01 ; get pairing index LDA SPRITEY,Y CMP #$68 BNE @skip1 ; is monster at cage row level? TYA ASL ASL ASL CLC ADC #$50 CMP SPRITEX,Y ; is monster inside cage? BNE @skip1 @home: LDA #$88 ; restore monster caged image STA SPRITEIMG,X LDA CAGEDATA-1,Y EOR #$FF LSR ADC #$20 ; compute waiting room time STA PENALTY-1,Y ; monster is waiting JMP NEXTMONSTER ; done moving @go: LDA FRAME ROR BCC @cont ; check for powerpill active? LDA SPRITEY,Y CMP #$68 BNE @flee ; is monster at cage row level? LDA SPRITEX,Y CMP #$30 BCC @next ; in tunnel left? LDA SPRITEX,Y CMP #$91 ; in tunnel right? BCS @next @flee: LDA SPRITEIMG,X CMP #$90 ; this monster IS fleeing BNE @cont @next: JMP NEXTMONSTER ; skip its turn @cont: LDX $00 LDA SPRITEX,X CMP #$60 BNE @skip1 LDA SPRITEY,X CMP #$68 BNE @skip1 ; is monster in cage ($60,$68 coord) doorway ? DEC SPRITEY,X ; move it a pixel UP to force it through the closed door LDX #$03 STX $4E,Y ; make direction UP to get out of cage BNE @skip3 @skip1: LDA SPRITEX,Y CMP #$11 BCS @skip2 ; is monster against the left-side of the tunnel? LDA #$00 LDX $00 STA $4E,X ; force a change of direction to the right @skip2: CMP #$AF ; is monster against the right-side of the tunnel? BCC @skip3 LDA #$02 LDX $00 STA $4E,X ; force a change of direction to the left @skip3: LDY #$00 LDX #$04 @loop1: STX MONMOVE-1,Y ; preset move priority as 0=right,1=down,2=left,3=up INY DEX BNE @loop1 LDY $00 ; start of monster's calculated move LDA SPRITEX,Y AND #$07 BEQ @skip4 ; is monster horizontally aligned with a screen cell? LDA SPRITEY,Y AND #$07 BNE @skip5 ; is monster vertically aligned with a screen cell? @skip4: JSR AI ; yes, check to see if a direction change is in its future CLC BCC @skip6 @skip5: LDX $4E,Y ; not in a position to make a direction change, STX $61 ; so just keep monster going in its current direction @skip6: LDY #$00 STY $04 @loop2: LDX $61,Y TXA LDX $00 EOR $4E,X CMP #$02 BEQ @skip7 ; don't allow monsters to reverse direction on their own LDX $61,Y STX NEWDIR LDY $00 LDX $4E,Y STX OLDDIR JSR MAZEMOVE ; validate BCC MAKEMOVE ; is this a good move? @skip7: INC $04 LDY $04 CPY #$04 BNE @loop2 LDY $00 ; reverse direction LDA OLDDIR EOR #$02 STA $4E,Y JMP NEXTMONSTER ; MAKEMOVE: LDY $00 ; commit to this move LDX NEWDIR STX $4E,Y ; save as monster's current direction LDY $01 LDA SPRITEIMG,Y CMP #$60 ; running back to cage BEQ @mommy ; to give birth again CMP #$90 ; fleeing from quikman BEQ @anim TXA ASL ; multiply by 8 to get address ASL ASL CLC ADC #$68 ; add base offset @anim: STA SPRITEIMG,Y @jmp: JMP NEXTMONSTER @mommy: LDY $00 ; start of monster's calculated move LDA SPRITEX,Y ORA SPRITEY,Y AND #$02 BEQ @jmp JMP ITMOVES ; ; monster's artificial intelligence AI: ; first, preload $61-$64 with "best" moves this monster can make ; to give quikman the kiss of death LDY $00 LDX $01 LDA $51,X ; retrieve this monster's "X" knowledge where quikman was CMP SPRITEX,Y ; aligned? BNE @math1 ; nope, compute intersect LDA JIFFYL AND #$01 BEQ @skip1 ; flip a coin @math1: SEC SBC SPRITEX,Y BCS @skip1 LDY #$02 STY MONMOVE ; LEFT is better LDY #$00 STY $64 ; RIGHT is worse BEQ @skip2 @skip1: LDY #$00 STY MONMOVE ; RIGHT is better LDY #$02 STY $64 ; LEFT is worse @skip2: LDA $52,X ; retrieve this monster's "Y" knowledge where quikman was LDY $00 CMP SPRITEY,Y ; aligned? BNE @math2 ; nope, compute intersect LDA JIFFYL AND #$01 BEQ @skip3 ; flip a coin @math2: SEC SBC SPRITEY,Y BCS @skip3 LDY #$03 STY $62 ; UP is 2nd best LDY #$01 STY $63 ; DOWN is 3rd best BNE AI2 @skip3: LDY #$01 ; DOWN is 2nd best STY $62 LDY #$03 ; UP is 3rd best STY $63 ; ; next, prioritize monster move, based upon its current location in respect to ; its knowledge where quikman was considered last. AI2: LDY $00 LDX $01 TXA ASL ASL ASL ; x8 CMP JIFFYL BCS @skip3 ; ignore priority during this time window LDA $51,X SEC SBC SPRITEX,Y BCS @skip1 EOR #$FF @skip1: STA $69 LDA $52,X SEC SBC SPRITEY,Y BCS @skip2 EOR #$FF @skip2: CMP $69 BCC @skip3 ; can monster improve upon order of choices? LDX MONMOVE ; swap 1st & 2nd choices LDY $62 STX $62 STY MONMOVE LDY $63 ; swap 3rd & 4th choices LDX $64 STY $64 STX $63 @skip3: LDY $01 LDA SPRITEIMG,Y CMP #$90 ; is this monster fleeing? BNE @fini ; no, chase! LDX MONMOVE ; swap 1st & 3rd choices LDY $63 STX $63 STY MONMOVE @fini: RTS ; ; reset monsters to default starting location INITVARS: LDX #$00 @loop1: LDA STARTPOSX,X STA SPRITEX,X LDA STARTPOSY,X STA SPRITEY,X LDA #$08 STA SPRITEH,X INX CPX #$05 BNE @loop1 LDY #$00 @loop2: LDX CAGEDATA,Y STX PENALTY,Y INY CPY #$10 BNE @loop2 ; LDA DOTS BNE @fini LDY FRUITLEVEL BEQ @fini LDX #$03 @loop3: LDA PENALTY,X LDY FRUITLEVEL @loop4: LSR DEY BNE @loop4 STA PENALTY,X ; after each level, the monsters dispatch quicker DEX BPL @loop3 @fini: RTS ; ; restore sound/screen RESTORE: INC FRUITLEVEL LDA #$00 STA SSS ; turn off all sprites ; @skip: LDX #$00 LDY #$1A STX VECTORBG STY VECTORBG+1 ; LDX #$00 LDY #$01 STY COLORCODE ; default to white space JSR SSSPLOT LDY #$15 @loop: LDA (VECTORBG),Y JSR SSSPRINT INY BNE @loop INC VECTORBG+1 LDA VECTORBG+1 CMP #$1C BNE @loop LDX #$00 LDY PLAYROWS DEY JSR SSSPLOT @erase: LDA #$A0 JSR SSSPRINT LDY CRSRCOL BNE @erase ; LDX #$06 ; paint the maze blue JSR MAZEPAINT ; LDX #$00 STX DOTS ; and no dots are eaten (yet) @loop2: LDA QUIKMANCLR,X ; reset monsters starting colors STA SPRITEDEF,X ; into their sprite color registers LDA #$08 STA SPRITEH,X TXA ASL TAY LDA #$70 ; reset monsters as looking down @ quikman STA SPRITEIMG,Y LDA #$1E STA SPRITEIMG+1,Y INX CPX #$05 BNE @loop2 ; LDY LIVES ; paint lives remaining BEQ @next JSR GAMEOVER LDX #$01 LDY PLAYROWS DEY JSR SSSPLOT LDA #$07 STA COLORCODE LDY LIVES BNE @less @loop4: LDA #$57 ; quikman character JSR SSSPRINT @less: DEY BNE @loop4 ; @next: LDA #$13 SEC SBC FRUITLEVEL BCC @l13 CMP #$0D BCS @rj @l13: LDA #$0D @rj: TAX ; right-justify fruit LDY PLAYROWS DEY JSR SSSPLOT LDY FRUITLEVEL @loop5: TYA TAX CPX #$0C ; are we at the last level (key)? BCC @nokey LDX #$0C ; only keys remain @nokey: LDA FRUITCLR,X ; get its color STA COLORCODE LDA FRUIT,X ; fruit character JSR SSSPRINT CPY #$00 ; did we paint the cherry yet? BEQ BEGIN ; if so, we're done DEY LDA #$13 CMP CRSRCOL BCS @loop5 BEGIN: LDA #$01 JSR PAUSE RTS ; ; recolor maze with some new paint in X MAZEPAINT: STX COLORCODE LDX #$00 LDY #$01 JSR SSSPLOT LDY #$15 @loop: LDA MAZEDATA,Y CMP #$69 BCC @page2 CMP #$7F BCS @page2 LDA $1600,Y AND #$E0 ORA #$40 ORA COLORCODE STA $1600,Y @page2: LDA MAZEDATA+$E3,Y CMP #$69 BCC @skip CMP #$7F BCS @skip LDA $16E3,Y AND #$E0 ORA #$20 ORA COLORCODE STA $16E3,Y @skip: INY BNE @loop LDA #$29 STA PLAYCOLOR+$DC LDA #$00 TAY @dirty: STA DIRTYLINE,Y INY CPY PLAYROWS BNE @dirty LDY #$01 JSR SSSFLIP RTS ; ; if move is valid, carry flag will be clear on return MAZEMOVE: LDY $00 ; get X,Y coord index LDA OLDDIR ; get the last direction moving AND #$01 ; mask UP/DOWN BEQ @skip1 ; is direction LEFT/RIGHT? LDA SPRITEY,Y ; no, then fetch the "Y" coordinate AND #$07 BEQ MAZEANY ; at a crossroad? check move in any 4-directions BNE @skip2 @skip1: LDA SPRITEX,Y ; get one of sprite's coord AND #$07 BEQ MAZEANY ; at a crossroad? check move in any 4-directions @skip2: LDA NEWDIR CMP OLDDIR BEQ MYMOVE ; still want to move in the same direction? EOR OLDDIR CMP #$02 BEQ MYMOVE ; is this a reverse direction request? @ng: SEC ; no new move made RTS ; MAZEANY: LDY $00 LDX NEWDIR CPX #$02 BPL @skip2 ; is X (2=left) or (3=up)? CPX #$01 BEQ @d01 ; is X (1=down)? LDA SSSCLIPX SEC SBC SPRITEX,Y CMP #$09 BCC MYMOVE ; passthru tunnel right @d01: LDA SPRITEX,Y TAX LDA SPRITEY,Y TAY JSR SSSPEEKXY LDX NEWDIR LDA CRSRCOL CLC ADC PEEKAHEAD,X TAY ; look (0=right) or (1=down) LDA (SCRNLINE),Y JMP @skip4 ; go validate ; @skip2: LDA SPRITEX,Y CPX #$03 BEQ @d23 ; is X (3=up)? CMP #$10 ; going left, BEQ MYMOVE ; and allow passthru tunnel left @d23: TAX LDA SPRITEY,Y SEC SBC #$08 TAY JSR SSSPEEKXY LDX NEWDIR LDA CRSRCOL CLC ADC PEEKAHEAD,X TAY ; look (2=left) or (3=up) LDA (SCRNLINE),Y @skip4: CMP #$69 ; is this direction into a maze wall? BCC MYMOVE ; good move? RTS ; ; continue this sprite's move in whatever is loaded in NEWDIR MYMOVE: LDA NEWDIR ASL ; 0=0, 1=2, 2=4, 3=6, 4=8 TAX LDY $00 LDA INERTIA,X CLC ADC SPRITEX,Y STA SPRITEX,Y LDA INERTIA+1,X CLC ADC SPRITEY,Y STA SPRITEY,Y CLC RTS ; ;********************************************************************* ; This section is dedicated to background processing, accomplished ; via the keyboard IRQ service, called 60-times per second (jiffy). BACKGROUND: CLD @esc: LDA JIFFYL AND #$07 BNE FLASH LDA PPILLTIMER ; drain powerpill BEQ FLASH ; is there still power left? CMP #$1F ; yes ... but are they BCS DRAIN ; getting confidence back? AND #$03 ; yes, let's warn quikman BNE DRAIN LDY #$04 @pp1: TYA ASL TAX LDA SPRITEIMG,X CMP #$90 ; is monster fleeing? BNE @pp2 LDA SPRITEDEF,Y EOR #$07 ; flash white / blue STA SPRITEDEF,Y @pp2: DEY BNE @pp1 DRAIN: DEC PPILLTIMER BNE FLASH LDY #$04 @loop: LDA MONSTERCLR-1,Y STA SPRITEDEF,Y ; restore all monsters to their default colors TYA ASL TAX LDA SPRITEIMG,X CMP #$60 ; is monster already going home? BEQ @next LDA #$88 ; restore monster chasing image STA SPRITEIMG,X @next: DEY BNE @loop FLASH: LDA FLASHPILL ; powerpill flash CMP #$1E ; 30-jiffies? BNE @skip1 LDX #$00 ; reset counter STX FLASHPILL @loop1: LDA $1EF8,X ; custom graphic char EOR $8288,X ; rom graphic char STA $1EF8,X ; redraw 8x8 char cell INX CPX #$08 BNE @loop1 LDA #$FE ; render monster feet EOR $1E8F ; custom graphic char STA $1E8F ; redraw caged monster STA $1E97 ; redraw fleeing monster STA $1E7F ; looking left STA $1E87 ; looking up LDA #$7F ; render monster feet EOR $1E6F ; custom graphic char STA $1E6F ; looking right STA $1E77 ; looking down @skip1: INC FLASHPILL LDA LIVES BNE ADDPTS ; playing? LDA JIFFYL ; manufacture a moving quikman 'spirit' BEQ ADDPTS LDA JIFFYM AND #$03 BNE ADDPTS INC DEMOQMAN LDA DEMOQMAN AND #$03 ASL ; x2 for pair TAY ; for the monsters to 'chase' LDA CAGEDATA+$08,Y STA SPRITEX LDA CAGEDATA+$09,Y STA SPRITEY ; ADDPTS: LDY POINTS ; award points to score on screen BEQ CLRPTS @loop1: LDX DIGIT @loop2: LDA $1A00,X CMP #$B9 ; reach "9" ? BEQ @skip2 INC $1A00,X ; ding! DEY BNE @loop1 BEQ CLRPTS @skip2: LDA #$B0 STA $1A00,X ; wrap to "0" DEX ; and increment next order BNE @loop2 CLRPTS: STY POINTS @hi: LDX #$00 ; yes @loop3: LDA $1A06,X ; check current score against high score CMP $1A0F,X BCC @top ; is quikman beating the high score? BNE @skip4 ; yes! INX CPX #$06 BNE @loop3 @skip4: LDX #$00 @loop4: LDA $1A06,X ; woot! STA $1A0F,X INX CPX #$06 BNE @loop4 @top: LDX #$14 ; refresh SCORE line @loop5: LDA $1A00,X STA PLAYFIELD,X LDA #$21 STA PLAYCOLOR,X DEX CPX #$06 BPL @loop5 LDX #$00 @score: LDA $1A00,X STA PLAYFIELD,X LDA #$23 STA PLAYCOLOR,X INX CPX #$06 BNE @score LDX #$00 STX DIRTYLINE ; inform SSSCOMMIT ; LDX #$00 LDY #$00 @loop6: LDA PENALTY,X BNE @next ; not aware while caged LDA SPRITEIMG+2,Y CMP #$60 BNE @go ; small ghost going home? LDA #$60 STA $53,Y LDA #$58 STA $54,Y BNE @next @go: LDA DOTS CMP #$A6 ; make them all "smart" with 5-dots or less BCS @skip5 LDA CAGEDATA,X BEQ @skip5 ; is monster "smart"? Red one is ... CMP JIFFYL ; no, so check as often as it waits BNE @next ; is its wait time equal to the jiffy clock? @skip5: LDA SPRITEX ; update this monster's awareness to where quikman is CMP #$10 BCS @ok1 LDA #$60 @ok1: CMP #$B0 BCC @ok2 LDA #$60 @ok2: STA $53,Y LDA SPRITEY STA $54,Y @next: INY INY INX CPX #$04 BNE @loop6 ; wahka: LDA CHEWING BEQ @skip1 LDA #$91 ; start with an odd frequency STA VIC+$0C ; ignite a voice @skip1: LDA #$00 ; dot is swallowed STA CHEWING LDA VIC+$0C BEQ @next1 ; is this voice mute? LDA VIC+$0C AND #$01 BEQ @skip3 ; is it even? LDA VIC+$0C CLC ADC #$10 ; increase tone CMP #$F1 BCC @skip2 ; is voice too high? SEC SBC #$01 ; make it even @skip2: STA VIC+$0C CLC BCC @next1 ; goto next effect @skip3: LDA VIC+$0C SEC SBC #$10 ; drain tone STA VIC+$0C @next1: LDX CHOMP BEQ @skip4 LDA JIFFYL AND #$01 BNE @skip4 LDA SNDBIT,X ; load tone data STA VIC+$0B DEC CHOMP @skip4: LDA EXTRAQMAN BNE @fini ; already got bonus life LDA $1A07 CMP #$B1 ; did quikman just score 10,000-points? BNE @fini STA EXTRAQMAN LDX LIVES LDA #$57 STA $15E3,X LDA #$E7 STA $17E3,X LDA #$01 STA DIRTYLINE+23 INC LIVES ; reward @fini: ;JMP $EABF ; jump to hardware IRQ JMP SSSIRQ ; check for video flip ... ; ; Pass A for number of jiffies to wait, while preserving X PAUSE: TAY PHA TXA PHA JSR SSSFLIP ; redraw sprites PLA TAX PLA RTS ; ; Y > 0 erase; Y = 0 display GAMEOVER: STY R0 LDA #$02 STA COLORCODE ; red LDX #$06 LDY #$0D JSR SSSPLOT LDX #$00 STX R1 @loop: LDA GOTEXT,X ; GAME OVER LDY R0 BEQ @dead LDA #$60 ; space @dead: JSR SSSPRINT INC R1 LDX R1 CPX #$09 BNE @loop RTS ; TUNE: LDA #187 ; b1 STA VIC+$0A LDA #221 ; B4 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #238 ; B5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #221 ; b2 STA VIC+$0A LDA #232 ; F#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #228 ; D#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #187 ; b1 STA VIC+$0A LDA #238 ; B5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #232 ; F#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #221 ; b2 STA VIC+$0A LDA #228 ; D#5 STA VIC+$0B LDY #$09 JSR SSSFLIP ; LDA #191 ; c2 STA VIC+$0A LDA #223 ; C5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #239 ; C6 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #223 ; c3 STA VIC+$0A LDA #234 ; G5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #230 ; E5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #191 ; c2 STA VIC+$0A LDA #239 ; C6 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #234 ; G5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #223 ; c3 STA VIC+$0A LDA #230 ; E5 STA VIC+$0B LDY #$09 JSR SSSFLIP ; LDA #187 ; b1 STA VIC+$0A LDA #221 ; B4 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #238 ; B5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #221 ; b2 STA VIC+$0A LDA #232 ; F#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #228 ; D#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #187 ; b1 STA VIC+$0A LDA #238 ; B5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #232 ; F#5 STA VIC+$0B LDY #$07 JSR SSSFLIP LDA #221 ; b2 STA VIC+$0A LDA #228 ; D#5 STA VIC+$0B LDY #$09 JSR SSSFLIP ; LDA #210 ; f#2 STA VIC+$0A LDA #228 ; D#5 STA VIC+$0B LDY #$06 JSR SSSFLIP LDA #230 ; E5 STA VIC+$0B LDY #$06 JSR SSSFLIP LDA #231 ; F5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #0 ; mute STA VIC+$0B LDY #$01 JSR SSSFLIP LDA #215 ; g#2 STA VIC+$0A LDA #231 ; F5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #232 ; F#5 STA VIC+$0B LDY #$06 JSR SSSFLIP LDA #234 ; G5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #0 ; mute STA VIC+$0B LDY #$01 JSR SSSFLIP LDA #219 ; a#2 STA VIC+$0A LDA #234 ; G5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #235 ; G#5 STA VIC+$0B LDY #$06 JSR SSSFLIP LDA #236 ; A5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #0 ; mute STA VIC+$0B LDY #$01 JSR SSSFLIP LDA #221 ; b2 STA VIC+$0A LDA #236 ; A5 STA VIC+$0B LDY #$03 JSR SSSFLIP LDA #237 ; A#5 STA VIC+$0B LDY #$06 JSR SSSFLIP LDA #238 ; B5 STA VIC+$0B LDY #$09 JSR SSSFLIP ; LDA #0 STA VIC+$0B STA VIC+$0A RTS .segment "RODATA" ; ;********************************************************************* ; READ-ONLY DATA ; CAGEDATA: ; knowledge cycle time .byte $00, $33, $76, $F9 ; right, up, left, right .byte $00, $03, $02, $00 ; coordinate to consider going to upon release or demo .byte $A8, $30, $18, $30, $A8, $98, $18, $98 GOTEXT: ; GAME OVER .byte $87, $81, $8D, $85, $A0, $8F, $96, $85, $92 INERTIA: ; maintain direction .byte $01, $00, $00, $01, $FF, $00, $00, $FF PEEKAHEAD: ; .byte $01, $15 PEEKAHEAD2: ; .byte $14, $00 SNDBIT: ; yummy sound effect .byte $00, $00, $C0, $B8, $B0, $A8, $B0, $B8, $C0, $C8 STARTPOSX: ; .byte $60, $60, $60, $70, $50 STARTPOSY: ; .byte $98, $58, $68, $68, $68 ; ;********************************************************************* ; Maze data (copied to RAM: $1A00 - $1BFF) ; Screen size: 24-rows by 21-columns ; MAZEDATA: .byte $93, $83, $8F, $92, $85, $BA, $B0, $B0, $B0, $B0, $B0, $B0, $A0, $A0, $A0, $B0, $B2, $B0, $B0, $B0, $B0 .byte $77, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7D, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $78 .byte $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79 .byte $79, $5E, $6F, $70, $5E, $6F, $6B, $6B, $70, $5E, $79, $5E, $6F, $6B, $6B, $70, $5E, $6F, $70, $5E, $79 .byte $79, $5F, $6D, $6E, $5E, $6D, $6C, $6C, $6E, $5E, $72, $5E, $6D, $6C, $6C, $6E, $5E, $6D, $6E, $5F, $79 .byte $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79 .byte $79, $5E, $73, $74, $5E, $71, $5E, $73, $7A, $7A, $7D, $7A, $7A, $74, $5E, $71, $5E, $73, $74, $5E, $79 .byte $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79 .byte $75, $7A, $7A, $78, $5E, $7B, $7A, $7A, $74, $60, $72, $60, $73, $7A, $7A, $7C, $5E, $77, $7A, $7A, $76 .byte $A0, $A0, $A0, $79, $5E, $79, $60, $60, $60, $60, $60, $60, $60, $60, $60, $79, $5E, $79, $A0, $A0, $A0 .byte $7A, $7A, $7A, $76, $5E, $72, $60, $77, $7A, $69, $C5, $6A, $7A, $78, $60, $72, $5E, $75, $7A, $7A, $7A .byte $60, $60, $60, $60, $5E, $60, $60, $79, $60, $60, $60, $60, $60, $79, $60, $60, $5E, $60, $60, $60, $60 .byte $7A, $7A, $7A, $78, $5E, $71, $60, $75, $7A, $7A, $7A, $7A, $7A, $76, $60, $71, $5E, $77, $7A, $7A, $7A .byte $A0, $A0, $A0, $79, $5E, $79, $60, $60, $60, $60, $60, $60, $60, $60, $60, $79, $5E, $79, $A0, $A0, $A0 .byte $77, $7A, $7A, $76, $5E, $72, $60, $73, $7A, $7A, $7D, $7A, $7A, $74, $60, $72, $5E, $75, $7A, $7A, $78 .byte $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79 .byte $79, $5E, $73, $78, $5E, $73, $7A, $7A, $74, $5E, $72, $5E, $73, $7A, $7A, $74, $5E, $77, $74, $5E, $79 .byte $79, $5F, $5E, $79, $5E, $5E, $5E, $5E, $5E, $5E, $60, $5E, $5E, $5E, $5E, $5E, $5E, $79, $5E, $5F, $79 .byte $7B, $74, $5E, $72, $5E, $71, $5E, $73, $7A, $7A, $7D, $7A, $7A, $74, $5E, $71, $5E, $72, $5E, $73, $7C .byte $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79, $5E, $5E, $5E, $5E, $79 .byte $79, $5E, $73, $7A, $7A, $7E, $7A, $7A, $74, $5E, $72, $5E, $73, $7A, $7A, $7E, $7A, $7A, $74, $5E, $79 .byte $79, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $5E, $79 .byte $75, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $7A, $76 BANNERMSG: ; ©2009 RHURST F1START .byte $7F, $B2, $B0, $B0, $B9, $A0, $92, $88, $95, $92, $93, $94, $A0, $A0, $5C, $5D, $93, $94, $81, $92, $94 FRUITSCORE: .byte $01, $03, $05, $07, $0A, $14, $1E, $32 ; QUIKMANCLR: ; yellow .byte $37 MONSTERCLR: ; red, green, cyan, yellow .byte $32, $35, $33, $37 FRUIT: ; cherry, strawberry, 2-peach, 2-apple, 2-pineapple, 2-tbird, 2-bell, key .byte $61, $62, $63, $63, $64, $64, $65, $65, $66, $66, $67, $67, $68 FRUITCLR: ; red, red, 2-yellow, 2-red, 2-green, 2-magenta, 2-yellow, cyan .byte $02, $02, $07, $07, $02, $02, $05, $05, $04, $04, $07, $07, $03 FRUITCHAR: ; .byte $42, $41, $40 ; 100 .byte $43, $41, $40 ; 300 .byte $44, $41, $40 ; 500 .byte $45, $41, $40 ; 700 .byte $48, $47, $46 ; 1000 .byte $49, $47, $46 ; 2000 .byte $4A, $47, $46 ; 3000 .byte $4B, $47, $46 ; 5000 ; SPRITEDATA: ; ; GHAPHIC CHARACTERS: custom character data ; GRAPHICS2: FS00: .byte %00000000 .byte %10000000 .byte %01000000 .byte %01000000 .byte %01000000 .byte %01000000 .byte %10000000 .byte %00000000 ; .byte %00000000 .byte %00110001 .byte %01001010 .byte %01001010 .byte %01001010 .byte %01001010 .byte %00110001 .byte %00000000 ; FS100: .byte %00000000 .byte %00000010 .byte %00000110 .byte %00000010 .byte %00000010 .byte %00000010 .byte %00000111 .byte %00000000 ; FS300: .byte %00000000 .byte %00001111 .byte %00000001 .byte %00000110 .byte %00000001 .byte %00001001 .byte %00000110 .byte %00000000 ; FS500: .byte %00000000 .byte %00001111 .byte %00001000 .byte %00001110 .byte %00000001 .byte %00001001 .byte %00000110 .byte %00000000 ; FS700: .byte %00000000 .byte %00001111 .byte %00000001 .byte %00000010 .byte %00000100 .byte %00000100 .byte %00000100 .byte %00000000 ; FS000: .byte %00000000 .byte %00011000 .byte %10100100 .byte %10100100 .byte %10100100 .byte %10100100 .byte %00011000 .byte %00000000 ; .byte %00000000 .byte %01100011 .byte %10010100 .byte %10010100 .byte %10010100 .byte %10010100 .byte %01100011 .byte %00000000 ; FS1000: .byte %00000000 .byte %00000100 .byte %00001100 .byte %00000100 .byte %00000100 .byte %00000100 .byte %00001110 .byte %00000000 ; FS2000: .byte %00000000 .byte %00001100 .byte %00010010 .byte %00000010 .byte %00001100 .byte %00010000 .byte %00011110 .byte %00000000 ; FS3000: .byte %00000000 .byte %00011110 .byte %00000010 .byte %00001100 .byte %00000010 .byte %00010010 .byte %00001100 .byte %00000000 ; FS5000: .byte %00000000 .byte %00011110 .byte %00010000 .byte %00011100 .byte %00000010 .byte %00010010 .byte %00001100 .byte %00000000 ; GHOST0: .byte $00, $38, $7C, $54, $7C, $7C, $54, $00 ; $60 small GHOST1: .byte $1C, $3E, $7F, $64, $7F, $7F, $7F, $55 ; $68 right GHOST2: .byte $1C, $3E, $7F, $7F, $49, $7F, $7F, $55 ; $70 down GHOST3: .byte $38, $7C, $FE, $26, $FE, $FE, $FE, $AA ; $78 left GHOST4: .byte $38, $7C, $FE, $FE, $FE, $FE, $FE, $AA ; $80 up GHOST5: .byte $38, $7C, $FE, $92, $FE, $82, $FE, $AA ; $88 caged GHOST6: .byte $38, $7C, $FE, $92, $FE, $82, $FE, $54 ; $90 fleeing QMAN: .byte $3C, $7E, $BD, $FF, $BD, $C3, $7E, $3C ; $98 smiley QMAN0: .byte $3C, $7E, $FF, $FF, $FF, $FF, $7E, $3C ; $A0 closed QMAN1: .byte $3E, $7C, $F8, $F0, $F0, $F8, $7C, $3E ; $A8 right QMAN2: .byte $3C, $7E, $FF, $FF, $E7, $C3, $81, $00 ; $B0 down QMAN3: .byte $7C, $3E, $1F, $0F, $0F, $1F, $3E, $7C ; $B8 left QMAN4: .byte $00, $81, $C3, $E7, $FF, $FF, $7E, $3C ; $C0 up POOF1: .byte $00, $10, $10, $6C, $10, $10, $00, $00 ; $C8 explosion POOF2: .byte $10, $44, $28, $C6, $28, $44, $10, $00 ; $D0 smoke POOF3: .byte $92, $44, $00, $82, $00, $44, $92, $00 ; $D8 dust F1: .byte $FF, $EA, $EF, $EF, $EB, $EF, $EF, $FF ; $E0 [F .byte $FC, $EC, $EC, $EC, $EC, $EC, $EC, $FC ; $E8 1] .byte $00, $00, $00, $18, $18, $00, $00, $00 ; $F0 dot .byte $00, $3C, $7E, $7E, $7E, $7E, $3C, $00 ; $F8 powerpill (animated) GRAPHICS3: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; empty space .byte $04, $08, $18, $24, $62, $F7, $F2, $60 ; cherry .byte $10, $7C, $FE, $AA, $D6, $AA, $54, $28 ; strawberry .byte $20, $10, $7C, $FE, $FE, $FE, $7C, $38 ; peach .byte $08, $10, $7C, $FE, $FE, $FE, $7C, $28 ; apple .byte $08, $10, $38, $38, $7C, $FE, $FE, $6C ; pear .byte $10, $30, $92, $FE, $7C, $38, $10, $28 ; tbird .byte $10, $38, $7C, $7C, $7C, $7C, $FE, $10 ; bell .byte $18, $24, $18, $08, $08, $18, $08, $18 ; key .byte $00, $FF, $01, $01, $01, $01, $FE, $00 ; doorway east .byte $00, $FF, $80, $80, $80, $80, $7F, $00 ; doorway west .byte $00, $FF, $00, $00, $00, $00, $00, $00 ; maze wall h-top .byte $00, $00, $00, $00, $00, $00, $FF, $00 ; maze wall h-bottom .byte $40, $40, $40, $40, $40, $20, $1F, $00 ; maze wall s-w corner .byte $02, $02, $02, $02, $02, $04, $F8, $00 ; maze wall s-e corner .byte $00, $1F, $20, $40, $40, $40, $40, $40 ; maze wall n-w corner .byte $00, $F8, $04, $02, $02, $02, $02, $02 ; maze wall n-e corner .byte $00, $18, $24, $42, $42, $42, $42, $42 ; maze wall north .byte $42, $42, $42, $42, $42, $24, $18, $00 ; maze wall south .byte $00, $1F, $20, $40, $40, $20, $1F, $00 ; maze wall west .byte $00, $F8, $04, $02, $02, $04, $F8, $00 ; maze wall east .byte $42, $41, $40, $40, $40, $20, $1F, $00 ; maze wall s-w elbow .byte $42, $82, $02, $02, $02, $04, $F8, $00 ; maze wall s-e elbow .byte $00, $1F, $20, $40, $40, $40, $41, $42 ; maze wall n-w elbow .byte $00, $F8, $04, $02, $02, $02, $82, $42 ; maze wall n-e elbow .byte $42, $42, $42, $42, $42, $42, $42, $42 ; maze wall vertical .byte $00, $FF, $00, $00, $00, $00, $FF, $00 ; maze wall horizontal .byte $42, $41, $40, $40, $40, $40, $41, $42 ; maze wall west tee .byte $42, $82, $02, $02, $02, $02, $82, $42 ; maze wall east tee .byte $00, $FF, $00, $00, $00, $00, $81, $42 ; maze wall north tee .byte $42, $81, $00, $00, $00, $00, $FF, $00 ; maze wall south tee .byte $3C, $42, $99, $A1, $A1, $99, $42, $3C ; (C)copyright symbol ; ;********************************************************************* ; INTRODUCTION ; ; QUIKMAN TITLE: .byte $91, $95, $89, $8B, $8D, $81, $8E ; (C) 2009 ROBERT HURST AUTHOR: .byte $A0, $7F, $A0, $B2, $B0, $B0, $B9, $A0, $92, $8F, $82, $85, $92, $94, $A0, $88, $95, $92, $93, $94, $A0 ; PRESS F1 TO CONTINUE! CONT: .byte $90, $92, $85, $93, $93, $A0, $5C,$5D, $A0, $94, $8F, $A0, $83, $8F, $8E, $94, $89, $8E, $95, $85, $A1 ; SPRDEF: .byte %11110111 ; large quikman .byte %00100010 ; abraham .byte %00100101 ; rebecca .byte %00100011 ; isabella .byte %00100111 ; peanut .byte %11011010 ; large cherry / pink ghost / tbird .byte $00 .byte $00 ; .word BIGQMAN, $1E78, $1E78, $1E78, $1E78, BIGCHERRY, $00, $00 ; .byte $10, $08, $08, $08, $08, $10, $00, $00 ; .byte $00, $90, $D0, $10, $50, $58, $00, $00 .byte $6C, $90, $90, $90, $90, $00, $00, $00 ; NAME1: .byte $81, $82, $92, $81, $88, $81, $8D, $A0, $00 NAME2: .byte $92, $85, $82, $85, $83, $83, $81, $A0, $00 NAME3: .byte $89, $93, $81, $82, $85, $8C, $8C, $81, $00 NAME4: .byte $A0, $90, $85, $81, $8E, $95, $94, $A0, $00 ; BIGQMAN: .byte %00000111 .byte %00011111 .byte %00111111 .byte %01111111 .byte %01111111 .byte %11111111 .byte %11111111 .byte %11111111 ; .byte %11111111 .byte %11111111 .byte %11111111 .byte %01111111 .byte %01111111 .byte %00111111 .byte %00011111 .byte %00000111 ; .byte %11100000 .byte %11111000 .byte %11111100 .byte %11111110 .byte %11111110 .byte %11111111 .byte %11111111 .byte %11111111 ; .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111110 .byte %11111110 .byte %11111100 .byte %11111000 .byte %11100000 ; BIGQMAN2: .byte %00000111 .byte %00011111 .byte %00111111 .byte %01111111 .byte %01111111 .byte %11111111 .byte %11111111 .byte %11111111 ; .byte %11111111 .byte %11111111 .byte %11111111 .byte %01111111 .byte %01111111 .byte %00111111 .byte %00011111 .byte %00000111 ; .byte %11100000 .byte %11111000 .byte %11111100 .byte %11111110 .byte %11111100 .byte %11110000 .byte %11000000 .byte %00000000 ; .byte %00000000 .byte %11000000 .byte %11110000 .byte %11111100 .byte %11111110 .byte %11111100 .byte %11111000 .byte %11100000 ; BIGQMAN3: .byte %00000111 .byte %00011111 .byte %00111111 .byte %01111111 .byte %01111111 .byte %11111111 .byte %11111111 .byte %11111110 ; .byte %11111110 .byte %11111111 .byte %11111111 .byte %01111111 .byte %01111111 .byte %00111111 .byte %00011111 .byte %00000111 ; .byte %11100000 .byte %11111000 .byte %11110000 .byte %11100000 .byte %11000000 .byte %10000000 .byte %00000000 .byte %00000000 ; .byte %00000000 .byte %00000000 .byte %10000000 .byte %11000000 .byte %11100000 .byte %11110000 .byte %11111000 .byte %11100000 ; BIGDUDE: .byte %00001111 .byte %00111111 .byte %11111111 .byte %11111111 .byte %11101011 .byte %11101011 .byte %11011011 .byte %11011011 ; .byte %11111111 .byte %11111111 .byte %11110011 .byte %11001100 .byte %11111111 .byte %11111111 .byte %11001100 .byte %11001100 ; .byte %11110000 .byte %11111100 .byte %11111111 .byte %11111111 .byte %11101011 .byte %11101011 .byte %11011011 .byte %11011011 ; .byte %11111111 .byte %11111111 .byte %11001111 .byte %00110011 .byte %11111111 .byte %11111111 .byte %00110011 .byte %00110011 ; BIGCHERRY: .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000011 .byte %00000011 .byte %00001100 .byte %00001100 ; .byte %00101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %00101010 ; .byte %00110000 .byte %00110000 .byte %11110000 .byte %11110000 .byte %00110000 .byte %00110000 .byte %00110000 .byte %00110000 ; .byte %00101000 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %00101000 .byte %00000000 ; BIGTBIRD: .byte %01000010 .byte %01001010 .byte %01111010 .byte %01111110 .byte %01111110 .byte %01111110 .byte %01111111 .byte %01011111 ; .byte %00011111 .byte %00010111 .byte %00000101 .byte %00000111 .byte %00000011 .byte %00000011 .byte %00000011 .byte %00000011 ; .byte %00000100 .byte %10000100 .byte %10110100 .byte %11110100 .byte %11110100 .byte %11110100 .byte %11110100 .byte %11010100 ; .byte %11010000 .byte %01010000 .byte %01000000 .byte %01000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 ; ;********************************************************************* ; Introduction screen INTRO: ; my VIC chipset init LDA #$0E ; black / blue STA VIC+$0F ; background / border color LDA #$80 ; brown & mute STA VIC+$0E ; auxiliary color & volume LDA VIC+$01 SBC #$04 ; adjust top scan line to accomodate extra row STA VIC+$01 LDA #$80+$15 ; set for videoram @ $1E00 with 21-columns STA VIC+$02 ; video matrix address + columns LDA #$B0 ; $B0 = 10110000 = 24 rows + 8x8 height STA VIC+$03 ; rows / character height ; my Software Sprite Stack init LDA #$A0 ; clear screen LDY #$40 ; reserve first 64 custom chars to sprites JSR SSSINIT ; my interrupt vector init SEI LDX #SSSIRQ STX $0314 STY $0315 CLI ; seed BASIC RAM with game data LDX #MAZEDATA STX VECTORBG STY VECTORBG+1 LDX #$00 LDY #$1A STX VECTORFG STY VECTORFG+1 LDY #$00 @cpmaze: LDA (VECTORBG),Y STA (VECTORFG),Y INY BNE @cpmaze INC VECTORBG+1 INC VECTORFG+1 LDA VECTORFG+1 CMP #$1C BNE @cpmaze ; seed VIC custom character RAM with graphic data LDX #GRAPHICS2 STX VECTORBG STY VECTORBG+1 LDX #$00 LDY #$1E STX VECTORFG STY VECTORFG+1 LDY #$00 @copy2: LDA (VECTORBG),Y STA (VECTORFG),Y INY BNE @copy2 LDX #GRAPHICS3 STX VECTORBG STY VECTORBG+1 LDX #$00 LDY #$1F STX VECTORFG STY VECTORFG+1 LDY #$00 @copy3: LDA (VECTORBG),Y STA (VECTORFG),Y INY BNE @copy3 ; LDX #$07 ; yellow STX COLORCODE LDY #$0C JSR SSSPLOT LDX #$00 @title: LDA TITLE,X JSR SSSPRINT INX CPX #$07 BNE @title LDY #$10 JSR SSSFLIP ; LDX #$04 ; magenta STX COLORCODE LDX #$00 LDY #$15 JSR SSSPLOT LDX #$00 @author: LDA AUTHOR,X JSR SSSPRINT LDX CRSRCOL BNE @author LDY #$50 JSR SSSFLIP ; ;-- CHERRY -- LDA #$02 STA COLORCODE LDY #$02 LDX #$02 JSR SSSPLOT LDA #$61 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$00 @cherry: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$03 BNE @cherry ; ;-- STRAWBERRY -- LDA #$02 STA COLORCODE LDY #$04 LDX #$02 JSR SSSPLOT LDA #$62 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$03 @strawberry: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$06 BNE @strawberry ; ;-- PEACH -- LDA #$07 STA COLORCODE LDY #$06 LDX #$02 JSR SSSPLOT LDA #$63 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$06 @peach: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$09 BNE @peach ; ;-- APPLE -- LDA #$02 STA COLORCODE LDY #$08 LDX #$02 JSR SSSPLOT LDA #$64 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$09 @apple: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$0C BNE @apple ; ;-- PEAR -- LDA #$05 STA COLORCODE LDY #$02 LDX #$0F JSR SSSPLOT LDA #$65 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$0C @pear: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$0F BNE @pear ; ;-- PHOENIX -- LDA #$04 STA COLORCODE LDY #$04 LDX #$0F JSR SSSPLOT LDA #$66 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$0F @phoenix: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$12 BNE @phoenix ; ;-- BELL -- LDA #$07 STA COLORCODE LDY #$06 LDX #$0F JSR SSSPLOT LDA #$67 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$12 @bell: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$15 BNE @bell ; ;-- KEY -- LDA #$03 STA COLORCODE LDY #$08 LDX #$0F JSR SSSPLOT LDA #$68 JSR SSSPRINT LDA #$03 STA COLORCODE LDX #$15 @key: LDA FRUITCHAR,X JSR SSSPRINT INX CPX #$18 BNE @key ; ; PRESS F1 TO CONTINUE! LDX #$00 LDY PLAYROWS DEY JSR SSSPLOT LDX #$00 @f1cont: LDA CONT,X JSR SSSPRINT LDX CRSRCOL BNE @f1cont LDX #$06 LDY PLAYROWS DEY JSR SSSPLOT LDY CRSRCOL LDA (COLORLINE),Y AND #$E0 ORA #$09 STA (COLORLINE),Y INY STA (COLORLINE),Y LDY #$78 JSR SSSFLIP ; LDX #SPRDEF STX VECTORBG STY VECTORBG+1 LDX #SPRITEDEF STX VECTORFG STY VECTORFG+1 LDY #$00 @sprdef: LDA (VECTORBG),Y STA (VECTORFG),Y INY CPY #$30 BNE @sprdef ; LDA #$3F STA SSS ; LDA #$00 STA R0 ; 0=cherry, 1=dude, 2=tbird STA R1 ; 0=down or <>0=up ; @loop: LDX R1 BEQ @bigdown DEC SPRITEY+5 BNE @seq2 LDY #$00 STY R1 LDA R0 BEQ @bigdude CMP #$01 BEQ @bigtbird @bigcherry: STY R0 LDA #$80 ; brown & mute STA VIC+$0E ; auxiliary color & volume LDA #%11011010 STA SPRITEDEF+5 LDX #BIGCHERRY STX SPRITEIMG+10 STY SPRITEIMG+11 LDX #$58 STX SPRITEX+5 BNE @seq2 @bigdude: INC R0 LDA #$A0 ; pink & mute STA VIC+$0E ; auxiliary color & volume LDA #%11011001 STA SPRITEDEF+5 LDX #BIGDUDE STX SPRITEIMG+10 STY SPRITEIMG+11 LDX #$60 STX SPRITEX+5 BNE @seq2 @bigtbird: INC R0 LDA #$70 ; yellow & mute STA VIC+$0E ; auxiliary color & volume LDA #%11011010 STA SPRITEDEF+5 LDX #BIGTBIRD STX SPRITEIMG+10 STY SPRITEIMG+11 LDX #$68 STX SPRITEX+5 BNE @seq2 @bigdown: INC SPRITEY+5 LDY SPRITEY+5 CPY #$58 BNE @seq2 STY R1 ; @seq2: INC SPRITEX LDA SPRITEX AND #$02 BEQ @qman LDA SPRITEIMG CMP #BIGQMAN STX SPRITEIMG STY SPRITEIMG+1 ; @seq3: LDA #$7C @n1: DEC SPRITEX+1 CMP SPRITEX+1 BNE @n2 LDA #$02 STA COLORCODE LDY #$12 LDX #$07 JSR SSSPLOT LDX #$00 @iam1: LDA NAME1,X BEQ @n2 JSR SSSPRINT INX BNE @iam1 @n2: DEC SPRITEX+2 CMP SPRITEX+2 BNE @n3 LDA #$05 STA COLORCODE LDY #$12 LDX #$07 JSR SSSPLOT LDX #$00 @iam2: LDA NAME2,X BEQ @n3 JSR SSSPRINT INX BNE @iam2 @n3: DEC SPRITEX+3 CMP SPRITEX+3 BNE @n4 LDA #$03 STA COLORCODE LDY #$12 LDX #$07 JSR SSSPLOT LDX #$00 @iam3: LDA NAME3,X BEQ @n4 JSR SSSPRINT INX BNE @iam3 @n4: DEC SPRITEX+4 CMP SPRITEX+4 BNE @flip LDA #$07 STA COLORCODE LDY #$12 LDX #$07 JSR SSSPLOT LDX #$00 @iam4: LDA NAME4,X BEQ @flip JSR SSSPRINT INX BNE @iam4 ; @flip: LDY #$03 JSR SSSFLIP INC FRAME LDA FRAME AND #$07 BNE @scan LDA $1E7F EOR #$FE STA $1E7F ; looking left @scan: JSR GETIN ; get keyboard CMP #$85 ; got F1 ? BEQ @fini LDA #$FF STA $9122 LDA $9111 AND #$20 ; FIRE BEQ @fini JMP @loop ; @fini: LDA #$0E ; black / blue STA VIC+$0F ; background / border color JMP RESTART