1: ; Quikman 2K8 for Commodore VIC20
2: ; written by Robert Hurst <robert@hurst-ri.us>
3: ; originally used Commodore VICMON (SYS 45056)
4: ; updated version: 29-Nov-2008
5: ;
6: ; to assemble this source using cc65.org project:
7: ; ca65.exe --cpu 6502 --listing quikman2k8.s
8: ; ld65.exe -C doc/vic20.cfg -o quikman2k8.prg quikman2k8.o
9: ;
10: ; to run the binary using viceteam.org project:
11: ; xvic -memory none -ntsc -sound -joydev1 2 -autostart quikman2k8.prg
12: ; to run the binary using mess.org project:
13: ; mess -view "Pixel Aspect (25:31)" vic20 -quik quikman2k8.prg
14: ;
15: ; pertinent VIC20 symbols
16: JIFFYH = $A0 ; jiffy-clock hi byte value
17: JIFFYM = $A1 ; jiffy-clock mid byte value
18: JIFFYL = $A2 ; jiffy-clock low byte value
19: CLRPAGE = $F4 ; color memory page (unexpanded = $97)
20: SCRNPAGE = $0288 ; screen memory page (unexpanded = $1E)
21: CTRLCSHIFT = $028D ; keyboard flag: control/commodore/shift
22: CASSBUFF = $033C ; cassette buffer
23: VIC = $9000 ; start of video interface chip registers
24: RESET = $FD22 ; warm startup
25: CHROUT = $FFD2 ; print character with cursor translation
26: GETIN = $FFE4 ; get a character from keyboard queue
27: ;
28: ; my symbol / memory map
29: ; = $00 ; base index (monster, sprite)
30: ; = $01 ; index x2
31: ; = $02 ; index x8
32: PPILLTIMER = $10 ; powerpill effectiveness timer
33: FRUITTIMER = $39 ; 0 - 242
34: FRUITFLAG = $3A ; zero or non-zero, if fruit has been activated
35: PPILLFLAG = $3B ; just ate a powerpill this turn (0=no)
36: CHOMP = $3C ; pointer into sound effect for fruit and fleeing monsters
37: CHEWING = $3D ; flag whether quikman just ate a dot or not
38: DIGIT = $3E ; award points at this digit place
39: POINTS = $3F ; how many points scored
40: OLDDIR = $40 ; direction sprite was last moving in
41: NEWDIR = $41 ; direction sprite wants to take, if valid by MAZEMOVE
42: JOYVAL = $42 ; last joystick read value
43: QMANDIR = $43 ; quikman's current direction (0=right,1=down,2=left,3=up)
44: FRAME = $44 ; frame rate
45: LIVES = $45 ; 0 - 3
46: FLASHPILL = $46 ; powerpill blink counter (0-30)
47: EXTRAQMAN = $47 ; bonus quickman flag (0=unused)
48: DEMOQMAN = $48 ; spirit of quickman index (0-3)
49: FRUITLEVEL = $49 ; 0 - 12
50: DOTS = $4A ; 0 - 174
51: PENALTY = $4B ; $4B-$4E monsters are free-to-roam flag
52: ; = $4F ; $4F-$52 monsters current direction (0=right,1=down,2=left,3=up)
53: ; = $53 ; $53,$55,$57,$59 monster's knowledge of quikman's "X" coord was
54: ; = $54 ; $54,$56,$58,$5A monster's knowledge of quikman's "Y" coord was
55: MONMOVE = $61 ; $61-$64 monster array for its next best move
56: ; = $69 ; temporary var
57: FLEEINGSCORE= $70 ; fleeing monster score: 2, 4, 8, 16
58: ; = $F7 ; $F7/$F8,$F9,$FA are screen cell pointers for sprite's position
59: ; = $FE ; $FC/$FD,$FE/$FF are color cell pointers for same
60: ;
61: ; program indirects (my sprite registers)
62: SPRITE = $02A1 ; bitmask 0-7 controls sprite on/off
63: SPRITEX = $02A2 ; $02A2,A4,A6,A8,AA,AC,AE,B0 each "X" coordinate
64: SPRITEY = $02A3 ; $02A3,A5,A7,A9,AB,AD,AF,B1 each "Y" coordinate
65: SPRITECLR = $02B2 ; $02B2-$02B9 color
66: SPRITEIMG1 = $02BA ; $02BA-$02C1 low-byte of SPRITE image
67: SPRITEIMG2 = $02C2 ; $02C2-$02C9 hi-byte of SPRITE image
68: SPRITELAST = $02CC ; $02CC-$02DC keep last state of SPRITE registers
69: SAVEBACK = $02DD ; $02DD-$02E6 keep what's under the sprite's 2-cell
70: ;
71: ; other constants
72: FRUITCELL = $1F1B ; screen cell address of fruit
73: FRUITCELLCLR= $971B ; color cell address of fruit
74: ;
75: ; uses standard VIC20 (unexpanded)
76: .org $0FFF
77: .segment "STARTUP"
78: ;
79: ;********************************************************************
80: ; LOAD "QUIKMAN2K8.PRG",8,1
81: .word $1001 ; starting load address
82: BASIC: .byte $0B, $10
83: ; 2008 SYS4109
84: .byte $D8, $07, $9E, $34, $31, $30, $39
85: .byte $00, $00, $00
86: ;
87: ;********************************************************************
88: ; Main entry point into the game
89: START:
90: LDA #$08 ; lock uppercase / graphic set
91: JSR CHROUT
92: LDA VIC+$01
93: SBC #$04
94: STA VIC+$01
95: LDA #$80+$15 ; set for videoram @ $1E00 with 21-columns
96: STA VIC+$02 ; video matrix address + columns
97: LDA #$B0 ; $B0 = 10110000 = 24 rows + 8x8 height
98: STA VIC+$03 ; rows / character height
99: LDX #$FF ; set for $1C00
100: STX VIC+$05 ; use programmable char set
101: JSR RESTORE
102: LDX #$16
103: @loop: LDA BANNERMSG-1,X
104: STA BANNERMSG+$03FF,X
105: LDA #$03
106: STA BANNERMSG+$7BFF,X
107: DEX
108: BNE @loop
109: SEI
110: LDX #<BACKGROUND
111: LDY #>BACKGROUND
112: STX $0314 ; enable my IRQ vector jump
113: STY $0315
114: CLI
115: ;
116: RESTART:
117: JSR INITVARS
118: LDY #$00
119: STY LIVES
120: STY FRUITLEVEL
121: JSR GAMEOVER
122: LDY #$0A
123: STY SPRITE
124: @loop: LDA FRAME
125: AND #$7F
126: BNE @slow
127: LDX VIC+$0F
128: INX
129: TXA
130: AND #$07
131: TAX
132: ORA #$08
133: STA VIC+$0F
134: JSR MAZEPAINT
135: LDA JIFFYM
136: AND #$0F
137: BNE @skip
138: STX PPILLFLAG ; demo powerpill
139: @skip: TAX
140: CPX #$0D
141: BCC @fruit
142: LDX #$00
143: @fruit: LDA FRUIT,X
144: STA FRUITCELL
145: LDA FRUITCLR,X
146: STA FRUITCELLCLR
147: LDA #$40
148: STA FRUITTIMER
149: STA FRUITFLAG
150: @slow: LDX JIFFYL
151: INX
152: INX
153: @wait: CPX JIFFYL
154: BNE @wait
155: LDA SPRITE
156: EOR #$1E
157: STA SPRITE
158: JSR NPC ; demo mode
159: @scan: JSR SPRITES
160: JSR GETIN ; get keyboard
161: CMP #$03 ; got STOP ?
162: BNE @skip1
163: JMP RESET ; bye-bye
164: @skip1: CMP #$88 ; got F7 ?
165: BNE @loop ; try again ...
166: ;
167: ;********************************************************************
168: RESETGAME:
169: JSR INITVARS
170: LDA #$03 ; start with 3-lives
171: STA LIVES
172: LDY #$FF ; -1 will become 0 at start of "next" level
173: STY FRUITLEVEL
174: JSR GAMEOVER ; clear status
175: LDX #$00 ; reset score
176: STX EXTRAQMAN ; reset bonus
177: @loop1: LDA #$B0 ; each digit to "0"
178: STA SCORE,X ; into savebuffer
179: INX ; do next digit
180: CPX #$06 ; all 6 of them
181: BNE @loop1
182: ;
183: STARTLVL:
184: JSR RESTORE ; initialize new level
185: ;
186: RESETCHR:
187: LDX #$00
188: STX QMANDIR ; start off going RIGHT
189: STX JOYVAL ; preload last joystick value as going RIGHT
190: @loop1: LDA STARTPOS,X ; reset each sprite starting position
191: STA SPRITEX,X
192: INX
193: CPX #$0A ; 5 sprites per X,Y coordinate pair
194: BNE @loop1
195: LDA #$1D ; 2nd page where quikman is on
196: STA SPRITEIMG2
197: LDA #$08 ; start quikman off with a smug smile
198: STA SPRITEIMG1
199: LDA #$1F ; turn on sprites 0-4
200: STA SPRITE
201: LDA #$40
202: JSR PAUSE ; then he sees there are monsters ...
203: LDX #$05
204: @loop2: LDA $C377,X ; print READY from ROM
205: AND #$BF
206: ORA #$80
207: STA $1F18,X
208: LDA #$07 ; make it yellow
209: STA $9718,X
210: DEX
211: BNE @loop2 ; how geeky is that?
212: LDA #$58 ; quikman gets ready
213: STA SPRITEIMG1
214: LDA #$A0
215: JSR PAUSE ; wait 2+ seconds
216: LDX #$00
217: LDA #$20 ; erase READY
218: @loop4: STA $1F19,X
219: INX
220: CPX #$05
221: BNE @loop4
222: ;
223: ; zero $39 - $43
224: ZEROVARS:
225: LDY #$39
226: LDX #$00
227: @loop: STX $00,Y
228: INY
229: CPY #$44
230: BNE @loop
231: ;
232: ;********************************************************************
233: PLAYLOOP:
234: LDA CTRLCSHIFT ; is the player holding down any
235: BNE PLAYLOOP ; control, commodore, shift key(s)?
236: LDA FRUITCELL
237: CMP #$22 ; is there fruit on display?
238: BCC @warp
239: LDX FRUITLEVEL
240: LDA FRUITCLR,X ; restore fruit color
241: STA FRUITCELLCLR
242: @warp: LDA #$0C ; 10-levels to warp
243: SEC
244: SBC FRUITLEVEL ; progressive speed
245: BCC @cruz
246: CMP #$03
247: BCS @pace
248: @cruz: LDA #$03
249: @pace: JSR SLOWDOWN
250: STA $00 ; quikman is sprite #0
251: STA $01
252: LDA QMANDIR
253: STA OLDDIR ; save last direction quikman was going in
254: LDX JOYVAL ; recall last joystick value
255: STY $9113
256: LDA #$7F
257: STA $9122
258: LDA $9120
259: AND #$80 ; JOY 3
260: BNE @joy0
261: LDX #$00
262: @joy0: LDA #$FF
263: STA $9122
264: LDY $9111
265: TYA
266: AND #$08
267: BNE @joy1
268: LDX #$01
269: @joy1: TYA
270: AND #$10
271: BNE @joy2
272: LDX #$02
273: @joy2: TYA
274: AND #$04
275: BNE @joy3
276: LDX #$03
277: @joy3: STX JOYVAL ; save
278: TXA
279: STA NEWDIR ; do the same for the joystick
280: JSR MAZEMOVE
281: BCS @skip1 ; is the direction valid?
282: LDA JOYVAL ; yes,
283: STA QMANDIR ; request quikman to move in direction of joystick
284: CLC
285: BCC @skip2
286: @skip1: LDA QMANDIR
287: STA NEWDIR
288: JSR MAZEMOVE ; keep the current direction going?
289: @skip2: LDA SPRITEX
290: BNE @skip3 ; is quikman at end of tunnel left?
291: LDA #$9E
292: STA SPRITEX ; put quikman at beginning of tunnel right
293: @skip3: CMP #$A0 ; is quikman at end of tunnel right?
294: BNE @skip4
295: LDA #$00
296: STA SPRITEX ; put quikman at beggining of tunnel left
297: @skip4: LDX #$00 ; use X as a flag
298: LDA SPRITEX
299: AND #$07
300: CMP #$04
301: BNE @skip5 ; is quikman in the middle of a left/right cell?
302: INX
303: LDA QMANDIR ; yes, 0=right, 2=left
304: EOR #$02
305: TAY
306: BEQ @skip6 ; going left, use 1st saveback cell
307: DEY
308: BNE @skip6 ; going right, use overflow saveback cell
309: @skip5: LDA SPRITEY
310: AND #$07
311: CMP #$03
312: BNE @skip6 ; is quikman in the middle of an up/down cell?
313: INX
314: LDY QMANDIR
315: CPY #$01 ; going down, use overflow saveback cell
316: BEQ @skip6
317: LDY #$00 ; going up, use 1st saveback cell
318: @skip6: CPX #$00
319: BNE @skip7 ; does quikman have something in its mouth?
320: JMP NPCNEXT ; no, continue play
321: @skip7: LDA SAVEBACK,Y ; retrieve the character from quikman's saveback buffer
322: CMP #$20
323: BNE @skip8
324: JMP PLAYLOOP ; nothing to eat here, so move a bit faster
325: ; check what was just eaten ...
326: @skip8: TAX ; save that something in X
327: LDA #$20
328: STA SAVEBACK,Y ; replace the cell quikman is on with an empty space
329: CPX #$1E ; is it a dot?
330: BNE POWERUP
331: LDA #$01
332: STA POINTS ; score 1
333: STA CHEWING ; quikman has to chew this dot, monsters keep movin'
334: LDA #$0A ; score it @ 10-point digit
335: STA DIGIT
336: ;
337: POWERUP:
338: CPX #$22
339: BCC @skip1 ; is X < 34 ?
340: CPX #$2A ; no, is X >= 42 ?
341: BCS NPCNEXT ; ate a piece of fruit?
342: TXA ; YUMMY!
343: SEC
344: SBC #$22 ; strip off char code for score index
345: TAX
346: LDA FRUITSCORE,X
347: STA POINTS ; award points
348: LDA #$09
349: STA DIGIT ; in hundreds
350: STA CHOMP
351: CLC
352: BCC NPCNEXT
353: @skip1: CPX #$1F ; ate a powerpill?
354: BNE EATING ; no, but I did eat a dot
355: LDA #$05
356: STA POINTS ; award 5-points
357: LDA #$0A
358: STA DIGIT ; score @ 10-digit
359: STA PPILLFLAG
360: BEQ NPCNEXT ; powerpills are dots on steroids, account for it
361: ;
362: EATING: INC DOTS ; ate a dot, account for it
363: LDA DOTS
364: CMP #$AA ; are all dots eaten?
365: BNE NPCNEXT
366: ;=== achieved end of level ===
367: WONLEVEL:
368: LDA #$08 ; quikman ends with a smug smile
369: STA SPRITEIMG1
370: LDA #$80
371: JSR PAUSE
372: STA FRAME
373: @loop: DEC FRAME
374: LDA FRAME
375: AND #$07
376: TAX
377: JSR MAZEPAINT
378: TXA
379: AND #$1F
380: BNE @next
381: LDA SPRITE
382: EOR #$1E
383: STA SPRITE ; blink monsters
384: JSR SPRITES
385: @next: LDA FRAME
386: CMP #$06
387: BNE @loop ; continue until true blue
388: LDA #$40
389: JSR PAUSE
390: JSR INITVARS
391: LDX #$04
392: @loop1: LDA PENALTY-1,X
393: LDY FRUITLEVEL
394: INY
395: @loop2: LSR
396: DEY
397: BNE @loop2
398: STA PENALTY-1,X ; after each level, the monsters dispatch quicker
399: DEX
400: BNE @loop1
401: JMP STARTLVL
402: ;
403: NPCNEXT:
404: JSR GETIN ; get keyboard
405: CMP #$03 ; got STOP ?
406: BEQ WONLEVEL ; CHEATER!!
407: JSR NPC
408: LDX #$50 ; closed mouth
409: LDA SPRITEX
410: ORA SPRITEY
411: AND #$02
412: BNE @anim
413: LDA QMANDIR ; take 0=right,1=down,2=left,3=up value
414: ASL ; multiply by 8 to get address
415: ASL
416: ASL
417: CLC
418: ADC #$58 ; add base offset
419: TAX
420: @anim: STX SPRITEIMG1
421: JSR SPRITES
422: JMP PLAYLOOP
423: ;
424: ;********************************************************************
425: ; non-player characters & events
426: NPC:
427: LDA FRUITFLAG
428: BNE @skip3 ; is fruit already on display?
429: LDA DOTS
430: CMP #$4B ; has the 75th dot been eaten?
431: BEQ @skip1
432: CMP #$7D ; has the 125th dot been eaten?
433: BNE @skip3
434: @skip1: LDX FRUITLEVEL ; prepare thy bonus
435: CPX #$0C ; reach the last level?
436: BCC @skip2
437: LDX #$0C ; only the key is left, and it leaves a bad metallic after-taste
438: @skip2: LDA FRUIT,X
439: STA FRUITCELL ; display fruit
440: LDA FRUITCLR,X
441: STA FRUITCELLCLR
442: LDA #$FA ; 250-moves and counting
443: STA FRUITTIMER ; reset fruit timer
444: STA FRUITFLAG
445: @skip3: LDA FRUITTIMER ; fruit is on display
446: BEQ @skip4 ; nothing to do
447: DEC FRUITTIMER ; remove a tick
448: BNE @skip4 ; there is still time left
449: LDA #$20 ; time's up!
450: STA FRUITCELL ; no more fruit
451: @skip4: LDA DOTS
452: CMP #$4C ; has the 76th dot been eaten?
453: BEQ @skip5
454: CMP #$7E ; has the 126th dot been eaten?
455: BNE @skip6
456: @skip5: LDA #$00
457: STA FRUITFLAG ; more fruit potential on this level
458: ;
459: @skip6: LDA PPILLFLAG
460: BEQ KISSING ; just swallowed a powerpill?
461: LDA #$00 ; account for that action
462: STA PPILLFLAG
463: LDA #$02 ; start scoring @ 200-points
464: STA FLEEINGSCORE
465: LDX FRUITLEVEL
466: TXA
467: AND #$07
468: BEQ @break ; every 8-levels, keep timer up
469: CPX #$10
470: BCS @timer ; 16-levels of powerpill timing
471: TXA
472: @break: ASL ; x2
473: ASL ; x2
474: AND #$3F
475: EOR #$3F ; invert A
476: CPX #$05
477: BCC @timer ; timer good to the 1st apple
478: LSR ; 1/2
479: @timer: STA PPILLTIMER ; set powerpill timer
480: LDY #$04
481: @loop1: LDX PENALTY-1,Y
482: BNE @skip7 ; is monster waiting in cage already?
483: LDA #$06 ; no, make monster blue
484: STA SPRITECLR,Y
485: LDA #$80 ; make monster fleeing (0)
486: STA SPRITEIMG1,Y
487: LDA $4E,Y
488: EOR #$02 ; and reverse its direction
489: STA $4E,Y
490: @skip7: DEY
491: BNE @loop1
492: ;
493: ; check all monsters if any are in contact with quikman
494: KISSING:
495: LDY #$08
496: KISSME:
497: LDA SPRITEX
498: CMP SPRITEX,Y
499: BNE @skip3
500: LDA SPRITEY
501: SEC
502: SBC SPRITEY,Y
503: BCS @skip2
504: EOR #$FF
505: @skip2: CMP #$05
506: BCS @skip3
507: LDX #$FF
508: BNE ENGAGED ; is quikman engaged with a monster?
509: @skip3: LDA SPRITEY
510: CMP SPRITEY,Y
511: BNE NEXTKISS
512: LDA SPRITEX
513: SEC
514: SBC SPRITEX,Y
515: BCS @skip4
516: EOR #$FF
517: @skip4: CMP #$05
518: BCC ENGAGED ; is quikman engaged with a monster?
519: ;
520: NEXTKISS:
521: DEY ; next monster
522: DEY ; X,Y coord pair check
523: BNE KISSME
524: JMP MONSTERS ; quikman is still freely running!
525: ;
526: ENGAGED:
527: TYA
528: LSR
529: TAX
530: LDA SPRITEIMG1,X
531: CMP #$80 ; is monster fleeing?
532: BNE DEAD ; no, quikman bites the dust
533: LDA #$09 ; ahah! caught a little sickly one!
534: STA DIGIT ; in hundreds
535: LDA FLEEINGSCORE
536: STA POINTS ; fleeing monster score
537: ASL ; next is worth x2 bonus
538: STA FLEEINGSCORE
539: LDA #$78
540: STA SPRITEIMG1,X ; reset monster as chasing
541: LDA #$51 ; reset "X" coord in cage
542: STA SPRITEX,Y
543: LDA #$58 ; reset "Y" coord in cage
544: STA SPRITEY,Y
545: LDA #$09
546: STA CHOMP
547: LDA JIFFYL
548: @loop1: CMP JIFFYL
549: BEQ @loop1 ; wait up to a jiffy
550: DEX
551: LDA MONSTERCLR,X
552: STA SPRITECLR+1,X
553: LDA CAGEDATA,X ; load waiting room time
554: EOR #$FF
555: LSR
556: ADC #$20
557: STA PENALTY,X ; monster is waiting
558: JMP NEXTKISS ; is there another monster here?
559: ;
560: DEAD:
561: PLA ; remove quikman's call to NPC from stack
562: PLA ; because he just died . . .
563: LDA #$30
564: JSR PAUSE
565: ; death sequence
566: LDA #$01 ; only feature quikman dying
567: STA SPRITE
568: LDA #$50 ; low-order byte of 1st quikman image
569: STA SPRITEIMG1
570: LDA #$20
571: STA FRAME ; rotate quikman 8 times
572: @loop1: LDA SPRITEIMG1
573: CMP #$70 ; are we at the 4th quikman image?
574: BCC @skip
575: LDA #$50 ; reset to 1st quikman image
576: @skip: CLC
577: ADC #$08 ; advance to next image
578: STA SPRITEIMG1
579: LDA #$04
580: JSR PAUSE
581: DEC FRAME
582: BNE @loop1 ; repeat next sequence
583: LDX #$D8
584: LDY #$1C
585: STX SPRITEIMG1 ; explode!
586: STY SPRITEIMG2
587: LDA #$0A
588: JSR PAUSE
589: LDX #$E0
590: STX SPRITEIMG1 ; smoke!
591: LDA #$08
592: JSR PAUSE
593: LDX #$E8
594: STX SPRITEIMG1 ; dust!
595: LDA #$06
596: JSR PAUSE
597: JSR INITVARS
598: DEC LIVES
599: BEQ FINALITY ; any lives remaining?
600: LDX LIVES
601: LDA #$20
602: STA $1FE4,X ; erase the avatar
603: JMP RESETCHR ; quikman still has life -- try again!
604: ;
605: FINALITY:
606: LDY LIVES
607: STY SPRITE
608: JSR GAMEOVER
609: LDA #$F0 ; 4-second pause
610: JSR PAUSE
611: JMP RESTART ; this game is really over now
612: ;
613: ;********************************************************************
614: MONSTERS:
615: LDA #$04
616: STA $00 ; start with monster #4
617: ;
618: DOMONSTER:
619: LDA $00
620: TAY
621: ASL ; x2
622: STA $01
623: LDX PENALTY-1,Y
624: BEQ ITMOVES ; is this monster free to roam?
625: DEX ; no, countdown to freedom
626: STX PENALTY-1,Y
627: ;
628: NEXTMONSTER:
629: DEC $00 ; process next monster
630: BNE DOMONSTER
631: INC FRAME
632: INC $00
633: LDA SPRITEY+$02
634: AND #$07
635: ORA SPRITEX+$02
636: AND #$0F
637: BEQ DOMONSTER
638: LDA CHEWING
639: BNE @skip1 ; is quikman eating a dot?
640: @fini: RTS ; no, we're done
641: @skip1: JSR SPRITES ; yes, chasing monsters get another turn
642: JMP MONSTERS
643: ;
644: ITMOVES:
645: LDA FRAME
646: AND #$01
647: BEQ @cont ; powerpill active?
648: LDA SPRITEIMG1,Y
649: CMP #$80 ; this monster IS fleeing
650: BEQ NEXTMONSTER ; skip its turn
651: @cont: LDX $01 ; no, get pairing index
652: LDA SPRITEX,X
653: CMP #$50
654: BNE @skip1
655: LDA SPRITEY,X
656: CMP #$58
657: BNE @skip1 ; is monster in cage ($50,$58 coord) doorway ?
658: LDA #$57 ; could have just used DEC SPRITEY,X instead
659: STA SPRITEY,X ; move it a pixel UP to force it through the closed door
660: LDX #$03
661: STX $4E,Y ; make direction UP to get out of cage
662: BNE @skip3
663: @skip1: LDA SPRITEX,X
664: BNE @skip2 ; is monster against the left-side of the tunnel?
665: LDX $00
666: STA $4E,X ; force a change of direction to the right
667: @skip2: CMP #$9F ; is monster against the right-side of the tunnel?
668: BNE @skip3
669: LDX $00
670: LDA #$02
671: STA $4E,X ; force a change of direction to the left
672: @skip3: LDY #$00
673: LDX #$04
674: @loop1: STX MONMOVE-1,Y ; preset move priority as 0=right,1=down,2=left,3=up
675: INY
676: DEX
677: BNE @loop1
678: LDY $01 ; start of monster's calculated move
679: LDA SPRITEX,Y
680: AND #$07
681: BEQ @skip4 ; is monster horizontally aligned with a screen cell?
682: LDA SPRITEY,Y
683: AND #$07
684: BNE @skip5 ; is monster vertically aligned with a screen cell?
685: @skip4: JSR AI ; yes, check to see if a direction change is in its future
686: CLC
687: BCC @skip6
688: @skip5: LDX $4E,Y ; not in a position to make a direction change,
689: STX $61 ; so just keep monster going in its current direction
690: @skip6: LDY #$00
691: STY $04
692: @loop2: LDX $61,Y
693: TXA
694: LDX $00
695: EOR $4E,X
696: CMP #$02
697: BEQ @skip7 ; don't allow monsters to reverse direction on their own
698: LDX $61,Y
699: STX NEWDIR
700: LDY $00
701: LDX $4E,Y
702: STX OLDDIR
703: JSR MAZEMOVE ; validate
704: BCC MAKEMOVE ; is this a good move?
705: @skip7: INC $04
706: LDY $04
707: CPY #$04
708: BNE @loop2
709: LDY $00 ; reverse direction
710: LDA OLDDIR
711: EOR #$02
712: STA $4E,Y
713: JMP NEXTMONSTER
714: ;
715: MAKEMOVE:
716: LDY $00 ; commit to this move
717: LDX NEWDIR
718: STX $4E,Y ; save as monster's current direction
719: JMP NEXTMONSTER
720: ;
721: ; monster's artificial intelligence
722: AI:
723: ; first, preload $61-$64 with "best" moves this monster can make
724: ; to give quikman the kiss of death
725: LDX $01
726: LDA $51,X ; retrieve this monster's "X" knowledge where quikman was
727: SEC
728: SBC SPRITEX,X
729: BCS @skip1
730: LDY #$02
731: STY MONMOVE ; LEFT is best
732: LDY #$00
733: STY $64 ; RIGHT is worst
734: BEQ @skip2
735: @skip1: LDY #$00
736: STY MONMOVE ; RIGHT is best
737: LDY #$02
738: STY $64 ; LEFT is worst
739: @skip2: LDA $52,X ; retrieve this monster's "Y" knowledge where quikman was
740: SEC
741: SBC SPRITEY,X
742: BCS @skip3
743: LDY #$03
744: STY $62 ; UP is 2nd best
745: LDY #$01
746: STY $63 ; DOWN is 3rd best
747: BNE AI2
748: @skip3: LDY #$01 ; DOWN is 2nd best
749: STY $62
750: LDY #$03 ; UP is 3rd best
751: STY $63
752: ;
753: ; next, prioritize monster move, based upon its current location in respect to
754: ; its knowledge where quikman was considered last.
755: AI2: LDX $01
756: LDA $51,X
757: SEC
758: SBC SPRITEX,X
759: BCS @skip1
760: EOR #$FF
761: @skip1: STA $69
762: LDA $52,X
763: SEC
764: SBC SPRITEY,X
765: BCS @skip2
766: EOR #$FF
767: @skip2: CMP $69
768: BCC @skip3 ; can monster improve upon order of choices?
769: LDX MONMOVE ; swap 1st & 2nd choices
770: LDY $62
771: STX $62
772: STY MONMOVE
773: LDY $63 ; swap 3rd & 4th choices
774: LDX $64
775: STY $64
776: STX $63
777: @skip3: LDY $00
778: LDA SPRITEIMG1,Y
779: CMP #$80 ; is this monster fleeing?
780: BNE @fini ; no, chase!
781: LDX #$04
782: @loop1: LDA MONMOVE-1,X
783: PHA
784: DEX
785: BNE @loop1
786: @loop2: PLA
787: STA $61,X ; reverse logic when in flee mode
788: INX
789: CPX #$04
790: BNE @loop2
791: @fini: RTS
792: ;
793: INITVARS:
794: LDY #$00
795: @loop: LDX CAGEDATA,Y
796: STX PENALTY,Y
797: LDA STARTPOS,Y ; reset each sprite starting position
798: STA SPRITEX,Y
799: INY
800: CPY #$10
801: BNE @loop
802: RTS
803: ;
804: ; restore sound/screen
805: RESTORE:
806: INC FRUITLEVEL
807: LDA #$00
808: STA SPRITE ; turn off all sprites
809: LDA #$0E ; black / blue
810: STA VIC+$0F ; background / border color
811: LDA #$AF ; pink & highest
812: STA VIC+$0E ; auxiliary color & volume
813: LDA #$93 ; Shift-HOME is clearscreen
814: JSR CHROUT ; print it
815: LDX #$15 ; skip 1st & last row
816: @draw: LDA MAZEDATA,X
817: STA $1E00,X
818: LDA MAZEDATA+$EB,X
819: STA $1EEB,X
820: INX
821: BNE @draw
822: STX DOTS ; and no dots are eaten (yet)
823: LDX #$06 ; blue
824: JSR MAZEPAINT
825: LDX #$00
826: @loop2: LDA QUIKMANCLR,X ; reset monsters starting colors
827: STA SPRITECLR,X ; into their sprite color registers
828: LDA #$78 ; reset monsters as chasing
829: STA SPRITEIMG1,X
830: LDA #$1D
831: STA SPRITEIMG2,X
832: INX
833: CPX #$05
834: BNE @loop2
835: LDY LIVES ; paint lives remaining
836: JSR GAMEOVER
837: DEY
838: BEQ @next
839: @loop4: LDA #$2D ; quikman character
840: STA $1FE4,Y ; bottom-left of screen
841: LDA #$07 ; use yellow
842: STA $97E4,Y ; and paint it
843: DEY
844: BNE @loop4
845: @next: LDY FRUITLEVEL
846: @loop5: CPY #$0C ; are we at the last level (key)?
847: BCC @skip1
848: LDY #$0C ; only keys remain
849: @skip1: LDA FRUIT,Y ; fruit character
850: STA $1FF1,X ; bottom right of screen
851: LDA FRUITCLR,Y ; get its color
852: STA $97F1,X ; and paint it
853: CPY #$00 ; did we paint the cherry yet?
854: BEQ BEGIN ; if so, we're done
855: INX
856: STX $FF
857: LDA FRUITLEVEL
858: SEC
859: SBC $FF
860: TAY
861: CPX #$07 ; no more than 7 fruits to display
862: BNE @loop5
863: BEGIN: LDA LIVES ; allow new screen to be processed
864: BEQ @cont
865: LDA #$40
866: @cont: JSR PAUSE ; by player
867: RTS
868: ;
869: ; recolor maze with some new paint in X
870: MAZEPAINT:
871: LDA #>MAZEDATA
872: STA @loop+2
873: LDA #$96
874: STA @color+2
875: LDY #$15
876: @loop: LDA MAZEDATA,Y
877: CMP #$31
878: BCC @skip1
879: CMP #$3F
880: BCS @skip1
881: TXA
882: @color: STA $9600,Y
883: @skip1: INY
884: BNE @loop
885: INC @loop+2
886: INC @color+2
887: LDA @color+2
888: CMP #$98
889: BNE @loop
890: RTS
891: ;
892: ; if move is valid, carry flag will be clear on return
893: MAZEMOVE:
894: LDY $01 ; get X,Y coord index
895: LDA OLDDIR ; get the last direction moving
896: AND #$01 ; mask UP/DOWN
897: BEQ @skip1 ; is direction LEFT/RIGHT?
898: INY ; no, then fetch the "Y" coordinate
899: @skip1: LDA SPRITEX,Y ; get one of sprite's coord
900: AND #$07
901: BEQ MAZEANY ; at a crossroad? check move in any 4-directions
902: LDA NEWDIR
903: CMP OLDDIR
904: BEQ MYMOVE ; still want to move in the same direction?
905: EOR OLDDIR
906: CMP #$02
907: BEQ MYMOVE ; is this a reverse direction request?
908: SEC ; no new move made
909: RTS
910: ;
911: MAZEANY:
912: JSR SPRITEPREP
913: LDA $F8 ; reset screen hi-byte back into saved maze data
914: SEC
915: SBC #$04
916: STA $F8
917: LDX NEWDIR
918: CPX #$02
919: BCS @skip2 ; is X (2=left) or (3=up)?
920: LDA $F7 ; no
921: CLC
922: ADC PEEKAHEAD,X ; look (0=right) or (1=down)
923: BCC @skip1
924: INC $F8
925: @skip1: STA $F7
926: CLC
927: BCC @skip4 ; go validate
928: @skip2: LDA $F7
929: SEC
930: SBC PEEKAHEAD-2,X
931: BCS @skip3 ; look (2=left) or (3=up)
932: DEC $F8
933: @skip3: STA $F7
934: @skip4: LDY #$00 ; validate
935: LDA ($F7),Y
936: CMP #$31 ; is this direction into a maze wall?
937: BCC MYMOVE ; good move?
938: RTS
939: ;
940: ; continue this sprite's move in whatever is loaded in NEWDIR
941: MYMOVE:
942: LDA NEWDIR
943: ASL ; 0=0, 1=2, 2=4, 3=6, 4=8
944: TAX
945: LDY $01
946: LDA INERTIA,X
947: CLC
948: ADC SPRITEX,Y
949: STA SPRITEX,Y
950: LDA INERTIA+1,X
951: CLC
952: ADC SPRITEY,Y
953: STA SPRITEY,Y
954: CLC
955: RTS
956: ;
957: ;********************************************************************
958: ; my very own sprite routines
959: ; major custom hack for this maze game implementation
960: SPRITES:
961: LDA #$00 ; start with sprite #0
962: STA $00 ; current sprite # to render
963: @loop1: ASL
964: STA $01 ; current sprite (x2) pairing index
965: ASL
966: ASL
967: STA $02 ; current sprite (x8) image index
968: LDX $00
969: LDA SPRITE
970: AND SPRITEMASK,X
971: BEQ @skip2 ; nothing to do?
972: LDA SPRITELAST ; what state was this sprite before?
973: AND SPRITEMASK,X
974: BEQ @skip1 ; it was "off"
975: JSR ERASESPRITE ; was "on" before, and we still want it "on"
976: @skip1: JSR SPRITEPREP ; new sprite, go turn it "on"
977: JSR PREPMATRIX
978: JSR RENDER
979: JSR PLACEMATRIX
980: JMP @next
981: @skip2: LDA SPRITELAST
982: AND SPRITEMASK,X
983: BEQ @next ; still nothing to do? Then do nothing ...
984: JSR ERASESPRITE ; make this sprite disappear
985: @next: INC $00
986: LDA $00
987: CMP #$05 ; only 5-sprites needed in this game
988: BNE @loop1
989: LDX #$00
990: @loop2: LDA SPRITE,X ; save copy of current sprite registers
991: STA SPRITELAST,X
992: INX
993: CPX #$11 ; all 17 values, not including colors
994: BNE @loop2
995: RTS ; fini
996: ;
997: ; remove sprite from screen
998: ERASESPRITE:
999: JSR LASTSPRITEPREP
1000: JSR PREPMATRIX
1001: JSR RESTOREMATRIX
1002: RTS
1003: ;
1004: LASTSPRITEPREP:
1005: LDA $01 ; 0, 2, 4, 6, 8
1006: CLC
1007: ADC #<SPRITELAST
1008: BNE SPRITEPREP2
1009: ;
1010: ; prepares the following registers:
1011: ; $F7/$F8,$F9/$FA screen cell pointers for sprite position
1012: ; $FC/$FD,$FE/$FF color cell pointers for same
1013: SPRITEPREP:
1014: LDA $01 ; 0, 2, 4, 6, 8 index
1015: CLC
1016: ADC #<SPRITE
1017: SPRITEPREP2:
1018: TAX ; save this register index
1019: LDA $0201,X ; get "X" coordinate
1020: CMP #$A0
1021: BCC @skip1 ; is "X" at or beyond last column?
1022: SBC #$A0 ; yes, subtract 160-pixels wide
1023: @skip1: LSR ; and divide by 8-pixel width
1024: LSR
1025: LSR
1026: STA $F7 ; save column offset from left screen
1027: STA $FC ; save column offset from left color
1028: LDA SCRNPAGE ; get high order byte of screen memory page
1029: STA $F8
1030: LDA CLRPAGE ; get high order byte of screen color page
1031: AND #$FE ; make it and "even" number
1032: STA $FD ; save high order
1033: LDA $0202,X ; get "Y" coordinate
1034: CMP #$B8
1035: BCC @skip2 ; is "Y" at or beyond last row?
1036: SBC #$B8 ; yes, subtract 184-pixels high
1037: @skip2: LSR ; and divide by 8-pixel height
1038: LSR
1039: LSR
1040: TAY
1041: BEQ @fini ; if on top row, no math required
1042: LDA $F7 ; get column offset
1043: @loop1: CLC
1044: ADC #$15 ; add 21 for next row
1045: BCC @skip3 ; overflow to next page?
1046: INC $F8 ; yes, increment high order bytes
1047: INC $FD
1048: @skip3: STA $F7 ; save column offset
1049: STA $FC
1050: DEY
1051: BNE @loop1 ; do for each "row"
1052: @fini: LDA $F8 ; copy high-order bytes
1053: STA $FA ; for overflow sprite character
1054: LDA $FD ; do the same
1055: STA $FF ; for color
1056: ; determine whether overflow character is to the right or down
1057: LDA $0201,X ; get "X" coordinate
1058: AND #$07
1059: BEQ @vert ; 0 assumes moving up/down?
1060: LDA $F7 ; ok, moving left/right then ...
1061: CLC
1062: ADC #$01 ; make overflow character to the right
1063: BCC @savel
1064: @saveh: INC $FA
1065: INC $FF
1066: @savel: STA $F9 ; save character offset
1067: STA $FE ; save color offset
1068: RTS
1069: @vert: LDA $F7
1070: CLC
1071: ADC #$15 ; make overflow character below
1072: BCC @savel
1073: BCS @saveh
1074: ;
1075: ; prepares saveback buffers for restoring, should a larger-numbered sprite be
1076: ; overlapping any part of a smaller-numbered sprite
1077: PREPMATRIX:
1078: LDY #$00
1079: LDA ($F7),Y ; retrieve screen cell
1080: PHA
1081: LDY $01 ; 0, 2, 4, 6, 8 index
1082: LDA $0201,X
1083: AND #$07
1084: BNE @2cell
1085: LDA $0202,X
1086: AND #$07
1087: BEQ @start
1088: @2cell: LDY #$00
1089: LDA ($F9),Y ; retrieve overflow cell
1090: PHA
1091: LDY $01 ; 0, 2, 4, 6, 8 index
1092: INY
1093: @start: TYA
1094: TAX
1095: @loop: PLA
1096: @retry: CMP $01
1097: BCC @skip ; is A < ME ?
1098: CMP #$0A
1099: BCS @skip ; is A >= MAX ?
1100: ; there is a sprite # greater than us on top ...
1101: TAY
1102: LDA SAVEBACK,Y ; get > sprite# saveback info
1103: CLC
1104: BCC @retry
1105: @skip: STA SAVEBACK,X
1106: DEX
1107: CPX $01
1108: BEQ @loop
1109: RTS
1110: ;
1111: ; restores the sprite's saveback buffer to the screen squares it occupies
1112: ; erasure part 3
1113: RESTOREMATRIX:
1114: LDX $01
1115: LDA SAVEBACK,X ; recover character
1116: LDY #$00
1117: STA ($F7),Y ; restore to screen
1118: LDA #$01
1119: STA ($FC),Y ; just leave "white" behind
1120: LDA SPRITELAST+1,X
1121: AND #$07
1122: BNE @2cell
1123: LDA SPRITELAST+2,X
1124: AND #$07
1125: BEQ @fini
1126: @2cell: LDA SAVEBACK+1,X
1127: STA ($F9),Y ; restore to screen
1128: LDA #$01
1129: STA ($FE),Y ; only color overflow if X or Y are offset
1130: @fini: RTS
1131: ;
1132: ; render sprite within its character matrix by merging its image over its saveback
1133: ; $05/$06 points to graphic character
1134: RENDER:
1135: LDX $00 ; 0-4
1136: LDA SPRITEIMG1,X
1137: STA $05
1138: LDA SPRITEIMG2,X
1139: STA $06
1140: LDX $01 ; 0,2,4,6,8
1141: LDA SPRITEY,X
1142: AND #$07
1143: STA $03
1144: TAX ; X will hold the sprite's Y coord
1145: LDY #$00 ; erase temp image matrix area
1146: TYA
1147: @loop1: STA CASSBUFF+$20,Y
1148: INY
1149: CPY #$10 ; customized from 4 to 2 character cells
1150: BNE @loop1
1151: TAY ; copy 8x8 character image into temp matrix
1152: @loop2: LDA ($05),Y ; $05/$06 points to character matrix to draw
1153: STA CASSBUFF+$20,X
1154: INX
1155: INY
1156: CPY #$08
1157: BNE @loop2
1158: LDX $01
1159: LDA SPRITEX,X
1160: AND #$07 ; get modulos on X coordinate
1161: TAY
1162: BEQ @skip1 ; if its zero, no shifting required
1163: @loop3: LDX #$00
1164: @loop4: CLC
1165: ROR CASSBUFF+$20,X
1166: ROR CASSBUFF+$28,X
1167: INX
1168: CPX #$08
1169: BNE @loop4
1170: DEY
1171: BNE @loop3
1172: @skip1: STY $FB ; Y is always zero here
1173: @loop5: LDA $01 ; index x2
1174: CLC
1175: ADC $FB
1176: TAX ; X is sprite custom character
1177: LDA #$1C ; 1st page is where sprites are stored
1178: STA $06
1179: LDA SAVEBACK,X
1180: CMP #$80
1181: BCC @skip2 ; is character reversed?
1182: LDY #$80 ; yes, use start of ROM character set
1183: STY $06
1184: @skip2: AND #$1F ; get modulos of first 32-characters
1185: ASL ; and multiply by 8-pixel height
1186: ASL
1187: ASL
1188: STA $05 ; save as low-order byte index
1189: LDA SAVEBACK,X
1190: AND #$60 ; mask 01100000
1191: LSR ; divide by 16
1192: LSR
1193: LSR
1194: LSR
1195: LSR
1196: CLC
1197: ADC $06 ; add result to high-order page index
1198: STA $06
1199: LDY #$00
1200: LDA $FB
1201: ASL
1202: ASL
1203: ASL
1204: TAX
1205: @loop6: LDA ($05),Y ; copy 8x8 character image into behind matrix
1206: STA CASSBUFF+$30,X
1207: INX
1208: INY
1209: CPY #$08
1210: BNE @loop6
1211: INC $FB
1212: LDA $FB
1213: CMP #$02 ; only a 2-cell sprite now
1214: BNE @loop5
1215: LDY #$00
1216: LDA $02 ; 0, 8, 16, 24, 32
1217: ASL ; 0, 16, 32, 48, 64
1218: TAX
1219: @loop7: LDA CASSBUFF+$20,Y
1220: ORA CASSBUFF+$30,Y
1221: STA $1C00,X
1222: INX
1223: INY
1224: CPY #$10 ; customized from 4 to 2 character cells
1225: BNE @loop7
1226: RTS
1227: ;
1228: ; puts the sprite character matrix on the screen
1229: PLACEMATRIX:
1230: LDA $01 ; 0, 2, 4, 6, 8
1231: LDY #$00
1232: STA ($F7),Y
1233: LDX $00
1234: LDA SPRITECLR,X
1235: STA ($FC),Y
1236: LDX $01
1237: LDA SPRITEX,X
1238: AND #$07
1239: BNE @color
1240: LDA SPRITEY,X
1241: AND #$07
1242: BEQ @fini
1243: @color: LDA ($FC),Y
1244: STA ($FE),Y ; only color overflow if X & Y are offset
1245: INX
1246: TXA
1247: STA ($F9),Y
1248: @fini: RTS
1249: ;
1250: ;********************************************************************
1251: ; This section is dedicated to background processing, accomplished
1252: ; via the keyboard IRQ service, called 60-times per second (jiffy).
1253: BACKGROUND:
1254: LDA $1EDC
1255: CMP #$C5
1256: BNE @esc
1257: LDA #$09
1258: STA $96DC ; paint the cage door
1259: @esc: LDA JIFFYL
1260: AND #$07
1261: BNE FLASH
1262: LDA PPILLTIMER ; drain powerpill
1263: BEQ FLASH ; is there still power left?
1264: CMP #$1F ; yes ... but are they
1265: BCS DRAIN ; getting confidence back?
1266: AND #$03 ; yes, let's warn quikman
1267: BNE DRAIN
1268: LDY #$04
1269: @pp1: LDA SPRITEIMG1,Y
1270: CMP #$80 ; is monster fleeing?
1271: BNE @pp2
1272: LDA SPRITECLR,Y
1273: EOR #$07 ; flash white / blue
1274: STA SPRITECLR,Y
1275: @pp2: DEY
1276: BNE @pp1
1277: DRAIN: DEC PPILLTIMER
1278: BNE FLASH
1279: LDY #$04
1280: @loop: LDA MONSTERCLR-1,Y
1281: STA SPRITECLR,Y ; restore all monsters to their default colors
1282: LDA #$78 ; restore monster chasing image (/)
1283: STA SPRITEIMG1,Y
1284: DEY
1285: BNE @loop
1286: FLASH: LDA FLASHPILL ; powerpill flash
1287: CMP #$1E ; 30-jiffies?
1288: BNE @skip1
1289: LDX #$00 ; reset counter
1290: STX FLASHPILL
1291: @loop1: LDA $1CF8,X ; custom graphic char
1292: EOR $8288,X ; rom graphic char
1293: STA $1CF8,X ; redraw 8x8 char cell
1294: INX
1295: CPX #$08
1296: BNE @loop1
1297: LDA #$FE ; render monster feet
1298: EOR $1D7F ; custom graphic char
1299: STA $1D7F ; redraw agressive monster
1300: STA $1D87 ; redraw fleeing monster
1301: @skip1: INC FLASHPILL
1302: LDA LIVES
1303: BNE @hi ; playing?
1304: LDA JIFFYL ; manufacture a moving quikman 'spirit'
1305: AND #$03
1306: BEQ @hi
1307: CLC
1308: ADC JIFFYM
1309: AND #$03
1310: BEQ @hi
1311: INC DEMOQMAN
1312: LDA DEMOQMAN
1313: AND #$03
1314: ASL
1315: TAY ; for the monsters to 'chase'
1316: LDA CAGEDATA+$08,Y
1317: STA SPRITEX
1318: LDA CAGEDATA+$09,Y
1319: STA SPRITEY
1320: @hi: LDX #$00 ; yes
1321: @loop3: LDA SCORE,X ; check current score against high score
1322: CMP MAZEDATA+$0F,X
1323: BCC @top ; is quikman beating the high score?
1324: BNE @skip4 ; yes!
1325: INX
1326: CPX #$06
1327: BNE @loop3
1328: @skip4: LDX #$00
1329: @loop4: LDA SCORE,X ; woot!
1330: STA MAZEDATA+$0F,X
1331: INX
1332: CPX #$06
1333: BNE @loop4
1334: @top: LDX #$15 ; refresh top line
1335: @loop5: LDA MAZEDATA-1,X
1336: STA $1DFF,X
1337: DEX
1338: BNE @loop5
1339: ADDPTS: LDY POINTS ; award points to score on screen
1340: BEQ CLRPTS
1341: @loop1: LDX DIGIT
1342: @loop2: LDA MAZEDATA,X
1343: CMP #$B9 ; reach "9" ?
1344: BEQ @skip2
1345: INC MAZEDATA,X ; ding!
1346: DEY
1347: BNE @loop1
1348: BEQ CLRPTS
1349: @skip2: LDA #$B0
1350: STA MAZEDATA,X ; wrap to "0"
1351: DEX ; and increment next order
1352: BNE @loop2
1353: CLRPTS: STY POINTS
1354: LDX #$00
1355: LDY #$00
1356: @loop6: LDA PENALTY,X
1357: BNE @next ; not aware while caged
1358: LDA DOTS
1359: CMP #$A6 ; make them all "smart" with 5-dots or less
1360: BCS @skip5
1361: LDA CAGEDATA,X
1362: BEQ @skip5 ; is monster "smart"? Red one is ...
1363: CMP JIFFYL ; no, so check as often as it waits
1364: BNE @next ; is its wait time equal to the jiffy clock?
1365: @skip5: LDA SPRITEX ; update this monster's awareness to where quikman is
1366: STA $53,Y
1367: LDA SPRITEY
1368: STA $54,Y
1369: @next: INY
1370: INY
1371: INX
1372: CPX #$04
1373: BNE @loop6
1374: ;
1375: wahka: LDA CHEWING
1376: BEQ @skip1
1377: LDA #$91 ; start with an odd frequency
1378: STA VIC+$0C ; ignite a voice
1379: @skip1: LDA #$00 ; dot is swallowed
1380: STA CHEWING
1381: LDA VIC+$0C
1382: BEQ @next1 ; is this voice mute?
1383: LDA VIC+$0C
1384: AND #$01
1385: BEQ @skip3 ; is it even?
1386: LDA VIC+$0C
1387: CLC
1388: ADC #$10 ; increase tone
1389: CMP #$F1
1390: BCC @skip2 ; is voice too high?
1391: SEC
1392: SBC #$01 ; make it even
1393: @skip2: STA VIC+$0C
1394: CLC
1395: BCC @next1 ; goto next effect
1396: @skip3: LDA VIC+$0C
1397: SEC
1398: SBC #$10 ; drain tone
1399: STA VIC+$0C
1400: @next1: LDX CHOMP
1401: BEQ @skip4
1402: LDA JIFFYL
1403: AND #$01
1404: BNE @skip4
1405: LDA SNDBIT,X ; load tone data
1406: STA VIC+$0B
1407: DEC CHOMP
1408: @skip4: LDA EXTRAQMAN
1409: BNE @fini ; already got bonus life
1410: LDA SCORE+1
1411: CMP #$B1 ; did quikman just score 10,000-points?
1412: BNE @fini
1413: STA EXTRAQMAN
1414: LDX LIVES
1415: LDA #$2D
1416: STA $1FE4,X
1417: LDA #$07
1418: STA $97E4,X
1419: INC LIVES ; reward
1420: @fini: JMP $EABF ; jump to hardware IRQ
1421: ;
1422: ; Pass A for number of jiffies to wait
1423: PAUSE: STA @tick+1 ; rewrite CMP operand below
1424: JSR SPRITES ; redraw sprites
1425: LDA JIFFYL
1426: STA $69 ; save this jiffy
1427: @loop: LDA JIFFYL
1428: SEC
1429: SBC $69
1430: @tick: CMP #$00 ; wait
1431: BNE @loop
1432: RTS
1433: ;
1434: ;********************************************************************
1435: ; Maze data ($1A00 - $1BFF)
1436: ; Screen size: 24-rows by 21-columns
1437: .res $1A00 - *
1438: MAZEDATA:
1439: SCORE = * + $06
1440: .byte $93, $83, $8F, $92, $85, $BA, $B0, $B0, $B0, $B0, $B0, $B0, $A0, $A0, $A0, $B0, $B2, $B0, $B0, $B0, $B0
1441: .byte $37, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3D, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $38
1442: .byte $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39
1443: .byte $39, $1E, $37, $38, $1E, $37, $3A, $3A, $38, $1E, $39, $1E, $37, $3A, $3A, $38, $1E, $37, $38, $1E, $39
1444: .byte $39, $1F, $35, $36, $1E, $35, $3A, $3A, $36, $1E, $32, $1E, $35, $3A, $3A, $36, $1E, $35, $36, $1F, $39
1445: .byte $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39
1446: .byte $39, $1E, $33, $34, $1E, $31, $1E, $33, $3A, $3A, $3D, $3A, $3A, $34, $1E, $31, $1E, $33, $34, $1E, $39
1447: .byte $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39
1448: .byte $35, $3A, $3A, $38, $1E, $3B, $3A, $3A, $34, $20, $32, $20, $33, $3A, $3A, $3C, $1E, $37, $3A, $3A, $36
1449: .byte $20, $20, $20, $39, $1E, $39, $20, $20, $20, $20, $20, $20, $20, $20, $20, $39, $1E, $39, $20, $20, $20
1450: .byte $3A, $3A, $3A, $36, $1E, $32, $20, $37, $3A, $3A, $C5, $3A, $3A, $38, $20, $32, $1E, $35, $3A, $3A, $3A
1451: .byte $20, $20, $20, $20, $1E, $20, $20, $39, $20, $20, $20, $20, $20, $39, $20, $20, $1E, $20, $20, $20, $20
1452: .byte $3A, $3A, $3A, $38, $1E, $31, $20, $35, $3A, $3A, $3A, $3A, $3A, $36, $20, $31, $1E, $37, $3A, $3A, $3A
1453: .byte $20, $20, $20, $39, $1E, $39, $20, $20, $20, $20, $20, $20, $20, $20, $20, $39, $1E, $39, $20, $20, $20
1454: .byte $37, $3A, $3A, $36, $1E, $32, $20, $33, $3A, $3A, $3D, $3A, $3A, $34, $20, $32, $1E, $35, $3A, $3A, $38
1455: .byte $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39
1456: .byte $39, $1E, $33, $38, $1E, $33, $3A, $3A, $34, $1E, $32, $1E, $33, $3A, $3A, $34, $1E, $37, $34, $1E, $39
1457: .byte $39, $1F, $1E, $39, $1E, $1E, $1E, $1E, $1E, $1E, $20, $1E, $1E, $1E, $1E, $1E, $1E, $39, $1E, $1F, $39
1458: .byte $3B, $34, $1E, $32, $1E, $31, $1E, $33, $3A, $3A, $3D, $3A, $3A, $34, $1E, $31, $1E, $32, $1E, $33, $3C
1459: .byte $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39, $1E, $1E, $1E, $1E, $39
1460: .byte $39, $1E, $33, $3A, $3A, $3E, $3A, $3A, $34, $1E, $32, $1E, $33, $3A, $3A, $3E, $3A, $3A, $34, $1E, $39
1461: .byte $39, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $1E, $39
1462: .byte $35, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $3A, $36
1463: BANNERMSG: ; ©2008 RHURST F7=PLAY
1464: .byte $3F, $B2, $B0, $B0, $B8, $A0, $92, $88, $95, $92, $93, $94, $A0, $A0, $86, $B7, $BD, $90, $8C, $81, $99
1465: FRUITSCORE:
1466: .byte $01, $03, $05, $07, $0A, $14, $1E, $32
1467: ;
1468: ;********************************************************************
1469: ; Custom character data -- must reside $1C00 - $1DFF
1470: .assert * = $1C00, error, "Graphics not at $1C00"
1471: .byte $3E, $7C, $F8, $F0, $F0, $F8, $7C, $3E ; @ sprite #0 - quikman
1472: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; A
1473: .byte $38, $7C, $FE, $92, $FE, $FE, $FE, $AA ; B sprite #1 - red
1474: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; C
1475: .byte $38, $7C, $FE, $92, $FE, $FE, $FE, $AA ; D sprite #2 - green
1476: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; E
1477: .byte $38, $7C, $FE, $92, $FE, $FE, $FE, $AA ; F sprite #3 - cyan
1478: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; G
1479: .byte $38, $7C, $FE, $92, $FE, $FE, $FE, $AA ; H sprite #4 - yellow
1480: .byte $00, $00, $00, $00, $00, $00, $00, $00 ; I
1481: ;
1482: ;********************************************************************
1483: ; DATA
1484: QUIKMANCLR: ; yellow
1485: .byte $07
1486: MONSTERCLR: ; red, green, cyan, yellow
1487: .byte $02, $05, $03, $07
1488: CAGEDATA: ;
1489: .byte $00, $33, $76, $F9
1490: .byte $02, $03, $02, $00
1491: .byte $A0, $10, $00, $10, $A0, $B8, $00, $B8
1492: FRUIT: ; cherry, strawberry, 2-peach, 2-apple, 2-pineapple, 2-tbird, 2-bell, key
1493: .byte $22, $23, $24, $24, $25, $25, $26, $26, $27, $27, $28, $28, $29
1494: FRUITCLR: ; red, red, 2-yellow, 2-red, 2-green, 2-magenta, 2-yellow, cyan
1495: .byte $02, $02, $07, $07, $02, $02, $05, $05, $04, $04, $07, $07, $03
1496: GOTEXT: ; GAME OVER
1497: .byte $87, $81, $8D, $85, $A0, $8F, $96, $85, $92
1498: INERTIA: ; maintain direction
1499: .byte $01, $00, $00, $01, $FF, $00, $00, $FF
1500: PEEKAHEAD: ;
1501: .byte $01, $15
1502: STARTPOS: ;
1503: .byte $50, $88, $50, $48, $50, $58, $60, $58, $40, $58
1504: SNDBIT: ; yummy sound effect
1505: .byte $00, $00, $C0, $B8, $B0, $A8, $B0, $B8, $C0, $C8
1506: SPRITEMASK: ; really?
1507: .byte $01, $02, $04, $08, $10, $20, $40, $80
1508: ;
1509: ; Y > 0 erase; Y = 0 display
1510: GAMEOVER:
1511: LDX #$09
1512: @loop: LDA GOTEXT-1,X ; GAME OVER
1513: CPY #$00
1514: BEQ @dead
1515: LDA #$20 ; space
1516: STA BANNERMSG+$03FF,X
1517: @dead: STA $1F16,X ; print character
1518: STA $1B16,X
1519: LDA #$02
1520: STA $9716,X
1521: DEX
1522: BNE @loop
1523: RTS
1524: ;
1525: ; A contains governor - all registers are reset to zero
1526: SLOWDOWN:
1527: TAY
1528: TAX
1529: @sleep: INX
1530: BNE @sleep
1531: DEY
1532: BNE @sleep ; one 1000, two 1000, three 1000, ...
1533: TYA
1534: RTS
1535: ;
1536: ; resume graphic character data
1537: .res $1CD8 - *
1538: .byte $00, $10, $10, $6C, $10, $10, $00, $00 ; [ explosion
1539: .byte $10, $44, $28, $C6, $28, $44, $10, $00 ; # smoke
1540: .byte $92, $44, $00, $82, $00, $44, $92, $00 ; ] dust
1541: .byte $00, $00, $00, $18, $18, $00, $00, $00 ; ^ dot
1542: .byte $00, $3C, $7E, $7E, $7E, $7E, $3C, $00 ; <- powerpill (animated)
1543: .byte $00, $00, $00, $00, $00, $00, $00, $00 ;$20 empty space
1544: .byte $3C, $7E, $BD, $FF, $BD, $C3, $7E, $3C ; ! smiley
1545: .byte $04, $08, $18, $24, $62, $F7, $F2, $60 ; " cherry
1546: .byte $10, $7C, $FE, $AA, $D6, $AA, $54, $28 ; # strawberry
1547: .byte $20, $10, $7C, $FE, $FE, $FE, $7C, $38 ; $ peach
1548: .byte $08, $10, $7C, $FE, $FE, $FE, $7C, $28 ; % apple
1549: .byte $08, $10, $38, $38, $7C, $FE, $FE, $6C ; & pear
1550: .byte $10, $30, $92, $FE, $7C, $38, $10, $28 ; ' tbird
1551: .byte $10, $38, $7C, $7C, $7C, $7C, $FE, $10 ; ( bell
1552: .byte $18, $24, $18, $08, $08, $18, $08, $18 ; ) key
1553: .byte $3C, $7E, $FF, $FF, $FF, $FF, $7E, $3C ; * pacman closed
1554: .byte $3E, $7C, $F8, $F0, $F0, $F8, $7C, $3E ; + pacman right
1555: .byte $3C, $7E, $FF, $FF, $E7, $C3, $81, $00 ; , pacman down
1556: .byte $7C, $3E, $1F, $0F, $0F, $1F, $3E, $7C ; - pacman left
1557: .byte $00, $81, $C3, $E7, $FF, $FF, $7E, $3C ; . pacman up
1558: .byte $38, $7C, $FE, $92, $FE, $FE, $FE, $AA ; / ghost chasing
1559: .byte $38, $7C, $FE, $92, $FE, $82, $FE, $54 ; 0 ghost fleeing
1560: .byte $00, $18, $24, $42, $42, $42, $42, $42 ; 1 maze wall north
1561: .byte $42, $42, $42, $42, $42, $24, $18, $00 ; 2 maze wall south
1562: .byte $00, $1F, $20, $40, $40, $20, $1F, $00 ; 3 maze wall west
1563: .byte $00, $F8, $04, $02, $02, $04, $F8, $00 ; 4 maze wall east
1564: .byte $42, $41, $40, $40, $40, $20, $1F, $00 ; 5 maze wall s-w elbow
1565: .byte $42, $82, $02, $02, $02, $04, $F8, $00 ; 6 maze wall s-e elbow
1566: .byte $00, $1F, $20, $40, $40, $40, $41, $42 ; 7 maze wall n-w elbow
1567: .byte $00, $F8, $04, $02, $02, $02, $82, $42 ; 8 maze wall n-e elbow
1568: .byte $42, $42, $42, $42, $42, $42, $42, $42 ; 9 maze wall vertical
1569: .byte $00, $FF, $00, $00, $00, $00, $FF, $00 ; : maze wall horizontal
1570: .byte $42, $41, $40, $40, $40, $40, $41, $42 ; ; maze wall west tee
1571: .byte $42, $82, $02, $02, $02, $02, $82, $42 ; < maze wall east tee
1572: .byte $00, $FF, $00, $00, $00, $00, $81, $42 ; = maze wall north tee
1573: .byte $42, $81, $00, $00, $00, $00, $FF, $00 ; > maze wall south tee
1574: .byte $3C, $42, $99, $A1, $A1, $99, $42, $3C ;(C)copyright symbol