-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPaddle.asm
1783 lines (1579 loc) · 82.8 KB
/
Paddle.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;****************************************************************************************************************
; Paddle - Mike Daley
; 26/09/15
;
; Paddle is a Break Out clone used to learn Z80 Assembly on the ZX Spectrum
;
; TODO
; * Implement reading IO Port 0x40FF for the colour attribute currently being read by the ULA. This can cause
; compatibility issues, but I want to see what can be done by using that rather than HALT to get more time
; to draw to the screen directly
; * Improve sound so that it does not use the ROM routine. This should allow part of a given sound FX to be
; generated each frame. The ROM routine blocks until its complete which causes everything to pause...not good
; * Power ups/downs:
; - Beer Bottle which makes paddle controls work backwards
; - Clock which slows down time
; - Multi ball powerups
;
;****************************************************************************************************************
;*******************************************************************************************
;Constants
;*******************************************************************************************
CONTENDEDADDR equ 24064 ; Address to load contended memory contents
CODESTART equ 32768 ; Address to load fast code
SCRNBFFR equ 57856 ; Address of screen back buffer
BTMPSCRNSDDR equ 16384 ; Address of bitmap screen file
BTMPSCRSZ equ 6144 ; Size of the bitmap screen
ATTRSCRNADDR equ 22528 ; Address of screen attribute data
ATTRSCRNSZ equ 768 ; Size of the screen attribute data
SCRNSZ equ BTMPSCRSZ + ATTRSCRNSZ
; Screen boundaries in pixels used when bouncing the ball
SCRNLFT equ 16
SCRNRGHT equ 240
SCRNTP equ 17
SCRNBTTM equ 180
; Offsets into the BALL structure
BLLXPS equ 0
BLLXSPD equ 1
BLLYPS equ 2
BLLYSPD equ 3
; BALL constants
BLLPXLHGHT equ 5
BLLPXLWIDTH equ 5
BLLHLFWIDTH equ 3
; Bat constants
BTMXRGHT equ SCRNRGHT - BTPXLWDTH ; Furthest pixel to the right the paddle can be drawn
BTMXLFT equ SCRNLFT ; Furthes pixel to the left the bat can be drawn
; Offsets into the BCC_AT structure
BTXPS equ 0
BTSPD equ 1
BTYPS equ 2
BTANMTONCNT equ 3 ; Counter used to time frames
BTANMTONFRM equ 4 ; Current frame number
BTANMTONDLY equ 5 ; 50/n frame delay between changing frames
BTANMTONTOTAL equ 6 ; Total number of frames in animation
; BCC_AT constants
BTPXLHGHT equ 8
BTPXLWDTH equ 24
BTHLFWDTH equ BTPXLWDTH / 2
; Block constants
BLCKWDTH equ 16
; Game States
GMESTTE_PLYNG equ 1
GMESTTE_WTNG equ 2
GMESTTE_DEAD equ 4
GMESTTE_DSPLYLVL equ 8
GMESTTE_NXTLVL equ 16
GMESTTE_LSTLFE equ 32
; Colours
BLACK equ 0
BLUE equ 1
RED equ 2
MAGENTA equ 3
GREEN equ 4
CYAN equ 5
YELLOW equ 6
WHITE equ 7
BRIGHT equ 64
CC_PAPER equ 17 ; RST 10 control codes for colour
CC_INK equ 16
CC_AT equ 22 ; RST 10 control codes for location
CC_FLASH equ 18
CC_BRIGHT equ 19
NUMPRTCLS equ 6
MAX_BLOCK_DATA_INDEX equ 112
ROMPRINT equ 8252
; Powerups
PWRUP_BEER equ 1
;****************************************************************************************************************
; Start of Contended Memory
;****************************************************************************************************************
org CONTENDEDADDR ; Set origin just above the system variables in contended memory
include Menu.asm ; Load the main menu code
include Font.asm ; Load the custom font graphics
include Levels.asm ; Load the level code
bffrLkup ; Location for the screen buffer line lookup table
ds 0x180
;****************************************************************************************************************
; PAGE 0: Page boundary for tables and variables
;****************************************************************************************************************
PAGE0
org 0x8000
gmeStte db 0x00 ; 1 = GMESTTE_PLYNG, 2 = GMESTTE_WTNG to Start, 4 = GMESTTE_DEAD
lvlBlckCnt db 0x00 ; Number of blocks in this level
crrntLvl db 0x00 ; Stores the current level index
currntBlckRw db 0x00 ; Variables used to store detalis of the blocks when rendering...
currntBlckCl db 0x00 ; ...a level
currntBlckY db 0x00
currntBlckX db 0x00
crrntLvlAddr dw 0x00 ; Address of the currently loaded level
; Stores the x, y attr position of the balls collision points
ballMT dw 0x00 ; Middle Top
ballMR dw 0x00 ; Middle Right
ballMB dw 0x00 ; Middle Bottom
ballML dw 0x00 ; Middle Left
lives db 0x05 ; Number of lives each player has at the start of the game
prShftWdth db 0x00 ; Holds the width of the sprite to be shifted
prShftHght db 0x00 ; Holds the height of the sprite to be shifted
prShftSize dw 0x00 ; Holds the size of a sprite to shift in bytes
crrntScrCnt db 0x00 ; How many scores are visible on screen
grvty dw 0x0035 ; Gravity to be applied to particles each frame
index db 0x00 ; Index into the level data for collision detection
pwrUpCnt db 0x00 ; Stores the number of current powerups on screen
crrntPwrUps db 0x00 ; Each bit of this byte defines a different powerup. 1 = active
sndFxDrtn db 0x00
inptOption db 0x00 ; Holds the input selection that has been chossen
; 0 = Keyboard, 1 = Sinclair, 2 = Kempston
tempSprite ds 2 * 13
; Text
; Colour, Yellow, Position, X, Y, Text
scrLblTxt db CC_INK, YELLOW, CC_AT, 0, 1, 'SCORE'
scrLblTxtEnd
scrTxt db '0000000', 0x00
scrTxtEnd
lvsLblTxt db CC_INK, YELLOW, CC_AT, 0, 24, 'LIVES'
lvsLblTxtEnd
lvsTxt db '5', 0x00
rndTxt db '1', 0x00
; Object data
; Xpos, XSpeed, Ypos, YSpeed
objctBall db 0x00, 0x01, 0x00, -2
; Xpos, XSpeed, Ypos
objctBat db 0x70 ; X position (112)
db 0x04 ; X Speed (4)
db 0x96 ; Y position (150)
db 0x00 ; Delay counter used to time how long each frame should be visible
db 0x00 ; Animation Frame
db 0x08 ; Frame delay
db 0x04 ; Total number of frames
; PAGE0 END
;****************************************************************************************************************
;****************************************************************************************************************
; PAGE 1: Page boundary Temp Level Data
PAGE1
org ($ + 0xff) & $ff00
lvlData ; Temp Level Data. Holds a copy of the levels row data that defines how many hits it takes to destroy a block
ds 0xe0
; PAGE1 END
;****************************************************************************************************************
;****************************************************************************************************************
; PAGE 2: Page boundary Particle Storage
PAGE2
org ($ + 0xff) & $ff00
objctPrtcls
db 0 ; Lifespan
db 0 ; Timer
dw 0x0000, 0x0000 ; Xvector, Xpos
dw 0x0000, 0x0000 ; YVector, Ypos
ds 0x0a ; Space needed to store the background of the particle sprite
objctPrtclsEnd
PRTCLSZ equ objctPrtclsEnd - objctPrtcls; Calculate the size of a particle
ds PRTCLSZ * (NUMPRTCLS - 1) ; Reserve the space for particles
; PAGE2 END
;****************************************************************************************************************
;****************************************************************************************************************
; PAGE 3: IM 2 jump table
PAGE3
org ($ + 255) & $ff00
intJmpTbl
ds 0x100
; PAGE3 END
;****************************************************************************************************************
;****************************************************************************************************************
; PAGE 4: Page boundary Particle Storage
PAGE4
org ($ + 0xff) & $ff00
pxlData
db %10000000, %01111111
db %01000000, %10111111
db %00100000, %11011111
db %00010000, %11101111
db %00001000, %11110111
db %00000100, %11111011
db %00000010, %11111101
db %00000001, %11111110
; PAGE4 END
;****************************************************************************************************************
;****************************************************************************************************************
; PAGE 5: Page boundary Powerups
PAGE5
org ($ + 0xff) & $ff00
objctPwrUps
db 0 ; Xpos
db 0 ; YPos
ds 16 * 13 ; Space needed to store the background behind the powerup sprite
objctPwrUpsEnd
PWRUPSZ equ objctPwrUpsEnd - objctPwrUps; Calculate the size of a powerup object
; PAGE5 END
;****************************************************************************************************************
;****************************************************************************************************************
; Main code
;****************************************************************************************************************
.debug equ 0
init
call stupInt ; Setup IM 2
call genLnrYLkupTbl ; Generate linear YAxis lookup table
xor a ; Set the border colour
out (0xfe), a ; Output the border colour to the FE port
ld a, CYAN + BRIGHT ; Set the CC_INK colour
ld (0x5c8d), a ; Set the SYSVAR for CC_INK colour
call shftSprts ; Create shifted versions of the sprites being used
call menu ; Start off by showing the main menu
; Just in case we get here go back to basic
IM 1 ; Switch back to IM 1
ret ; Return to basic
;****************************************************************************************************************
; Pre-shift the sprites
shftSprts
ld hl, SpriteBlock0
ld de, SpriteBlock0 + 3 * 8
ld b, 0x03
ld c, 0x08
call prShft
; Shift Sprite Ball
ld hl, SmallBallData0
ld de, SmallBallData0 + 2 * 5
ld b, 0x02
ld c, 0x05
call prShft
; Shift Sprite Bat animation frames
ld hl, SpriteBatData0
ld de, SpriteBatData0 + 4 * 8
ld b, 0x04
ld c, 0x08
call prShft
ld hl, SpriteBatData1
ld de, SpriteBatData1 + 4 * 8
ld b, 0x04
ld c, 0x08
call prShft
ld hl, SpriteBatData2
ld de, SpriteBatData2 + 4 * 8
ld b, 0x04
ld c, 0x08
call prShft
ret
;****************************************************************************************************************
; Debug Print
;****************************************************************************************************************
IF .debug
dbgPrnt
ld e, 168
ld d, 8 * 4
call getPixelAddr
ld a, (inptOption) ; Bat X Position
call HexByte
; ld e, 168
; ld d, 8*6
; call getPixelAddr
; ld a, (objctPrtcls + 1 + PRTCLSZ * 1) ; Bat X Position
; call HexByte
; ld e, 168
; ld d, 8*9
; call getPixelAddr
; ld a, (objctPrtcls + 1 + (PRTCLSZ * 2)) ; Bat X Position
; call HexByte
ret
ENDIF
;****************************************************************************************************************
; Start new game
;****************************************************************************************************************
strtNewGame
call fdeToBlck
call romClrScrn
call rstScr ; Reset the score
call rstBt
call stupPrtcls
ld a, 0x05
ld (lives), a
ld a, 0x35 ; The number five in the character set
ld (lvsTxt), a
xor a ; Reset the level...
ld (lvlBlckCnt), a ; ...block count
ld a, 0x01
ld (crrntLvl), a ; Save the level
call drwUI
call ldLvl ; Load the current level
call drwBrdrs
ld a, GMESTTE_DSPLYLVL ; Set the game state to DISPLAY LEVEL
ld (gmeStte), a ; Save the game state
;****************************************************************************************************************
; Main loop
;****************************************************************************************************************
mnLp
ld a, (gmeStte) ; Check the game state
;****************************************************************************************************************
; PLAYING
_chckGmeSttePlyng ; *** Game state PLAYING
cp GMESTTE_PLYNG ; Is the game state PLAYING
jr nz, _chckGmeStteWtng ; If not then check if the state is WAITING
call rdCntrlKys ; Read the keyboard
ld de, MskdBeerSprtData
ld bc, 0x1845
call drwMskdSprt
call mvBll ; Move the ball
call drwBll ; Erase the ball (XOR)
call drwPrtcls ; Draw any active particles
ld ix, objctBat ; Point IX at the sprite whos animation is to be updated
call updtAnmtn ; Update the sprites animation frame
call drwBt ; Draw the bat
halt ; Wait for the scan line to reach the top of the screen
call drwBll ; Draw the ball
call rstrScrBckgrnd ; Restore the background behind the particles
call drwBt ; Erase the bat (XOR)
call updtPrtcls ; Update any active particles
call genRndmNmbr ; Generate three random numbers
ld a, (lvlBlckCnt) ; Load A with the number of blocks that are still visible
or a ; Check the number of blocks against 0
jr nz, mnLp ; If not yet 0 then loop
ld a, GMESTTE_NXTLVL ; No more blocks so set the game state to NEXT LEVEL
ld (gmeStte), a ; Save the game state and loop
jp mnLp
;****************************************************************************************************************
; WAITING
_chckGmeStteWtng ; *** Game state WAITING
cp GMESTTE_WTNG ; Is the game state WAITING
jp nz, _chckGmeStteLstLfe ; If not then check if the state is PLAYER DEAD
call rdCntrlKys ; Read the keyboard
ld a, (objctBat + BTYPS) ; Get the bats Y position
ld b, BLLPXLHGHT ; Get the pixel height of the ball
sub b ; Calculate the bats Y pos minus the balls height putting the ball on top of the bat
ld (objctBall + BLLYPS), a ; Update the balls Y Position with the bats Y position
ld a, (objctBat + BTXPS) ; Load the bats X pos
ld b, BTHLFWDTH - BLLHLFWIDTH ; Calc the X pos middle of the bat
add a, b ; Calc the new X pos for the ball so its in the middle of the bat
ld (objctBall + BLLXPS), a ; Save the new X pos for the ball
call drwBll ; Draw the ball
ld ix, objctBat ; Point IX at the sprite whos animation is to be updated
call updtAnmtn ; Update the sprites animation frame
call drwBt ; Draw the bat
halt ; Wait for the scan line to reach the top of the screen
call drwBll ; Erase the ball (XOR)
call drwBt ; Erase the bat (XOR)
call genRndmNmbr
ld a, (inptOption) ; Get the currently selected input option
_keybrdFire
cp 0x00 ; KEYBOARD
jr nz, _sincJoyFire
ld bc, 0x7ffe ; B = 0xDF (QUIOP), C = port 0xFE
in a, (c) ; Load A with the keys that have been pressed
rra ; Outermost bit = key 1
jp nc, _gameOn ; Space bar has been pressed
jp mnLp
_sincJoyFire
cp 0x01 ; SINCLAIR PORT 1
jr nz, _kempJoyFire
ld bc, 0xf7fe
in a, (c)
rra
rra
rra
rra
rra
jp nc, _gameOn
jp mnLp
_kempJoyFire ; KEMPSTON
cp 0x02
ret nz
ld bc, 0x1f ; 31
in a, (c)
and 0x10 ; 16
jp nz, _gameOn
jp mnLp
_gameOn
ld a, GMESTTE_PLYNG ; Otherwise update the game state to GMESTTE_PLYNG
ld (gmeStte), a ; Save the game state
jp mnLp ; Loop
;****************************************************************************************************************
; LOST LIFE
_chckGmeStteLstLfe ; *** Game state LOST LIFE
cp GMESTTE_LSTLFE ; Is the game state LOST LIFE
jr nz, _gmeStteNxtLvl ; If not then check if the state is NEXT LEVEL
ld a, (lives) ; Load A with the lives left
dec a ; -1 from lives
push af ; Save AF
ld (lives), a ; Save the new number of lives
add a, 0x30 ; Add 48 to the number of lives to get the character code for the lives number
ld (lvsTxt), a ; Update the lives text with the new lives character at position 5 in the string
ld de, 0xf000
ld bc, lvsTxt ; Load DE with the lives text
call prntStrng
pop af ; Restore AF
or a ; Check if the players lives have reached 0
jp z, _setGmeStteDead ; Jump to set the game state to DEAD
call rstBt ; Reset the bats location
call plyDthSnd ; Play a death sound
ld a, GMESTTE_WTNG ; Set the game state to WAITING
ld (gmeStte), a ; Save the game state
jp mnLp
_setGmeStteDead
ld a, GMESTTE_DEAD
ld (gmeStte), a
jp mnLp
;****************************************************************************************************************
; NEXT LEVEL
_gmeStteNxtLvl ; *** Game state NEXT LEVEL
cp GMESTTE_NXTLVL ; Is the game state NEXT LEVEL
jr nz, _chckGmeStteDsplyLvl ; If not then check if the game state is DISPLAY LEVEL
ld a, (crrntLvl) ; Load A with the current level
inc a ; +1 to the current level
ld (crrntLvl), a ; Save the current level
cp 0x02 ; Is the current level 2?
jr nz, _incLvl ; If not then increment the level
ld a, 0x0 ; Otherwise set the level back to 1
ld (crrntLvl), a ; and save it.
_incLvl
ld a, GMESTTE_DSPLYLVL ; Set the game state to DISPLAY LEVEL
ld (gmeStte), a ; Save the game state
call stupPrtcls ; Clear any current particles
call ldLvl ; Load the new level
jp mnLp ; Loop
;****************************************************************************************************************
; DISPLAY LEVEL
_chckGmeStteDsplyLvl ; *** Game state DISPLAY LEVEL
cp GMESTTE_DSPLYLVL ; Is the game state DISPLAY LEVEL
jp nz, _chckGmeSttePlyrDead ; If not then check if the game state is PLAYER DEAD
ld hl, (crrntLvlAddr) ; Load HL with the current level address
ld de, LEVEL_TITLE ; Load DE with the offset in the level data to the level title
add hl, de ; Move HL to the level title
ld b, 0x00 ; Set b to 0
ld c, (hl) ; Load C with the length of the string to print
ld d, h ; Load HL the address of the text...
ld e, l ; ...into DE
inc de ; + 1 DE which is the start of the actual string
call ROMPRINT ; ROM print the title
ld de, 0x64 ; Load DE with 100 for a delay loop
_lvlDsplyWtng
halt ; Wait for the scan line to reach the top of the screen (50hz)
dec de ; -1 from DE
ld a, d ; Check to see if...
or e ; ...the timer has run down
jr nz, _lvlDsplyWtng ; If not then loop again
ld hl, (crrntLvlAddr) ; Load HL with the address of the current level data
ld de, LEVEL_TITLE ; Load DE with the levels title position...
add hl, de ; ...and add it to DE
ld b, 0x00 ; Reset B
ld c, (hl) ; Put the length of the level title into C
add hl, bc
ld b, 0x00
inc hl
ld c, (hl)
ld e, l
ld d, h
inc de
call ROMPRINT
ld a, GMESTTE_WTNG ; Set the game state to WAITING
ld (gmeStte), a
jp mnLp
;****************************************************************************************************************
; PLAYER DEAD
_chckGmeSttePlyrDead
cp GMESTTE_DEAD
jp nz, mnLp
call romPrntStrng
db CC_FLASH, 1, CC_INK, WHITE, CC_PAPER, RED, CC_AT, 15, 11, ' GAME OVER ', CC_FLASH, 0, 0xff
call watFrSpc
call fdeToBlck
jp menu
;****************************************************************************************************************
; Setup the particle objects by clearing out all the values
;
; Entry Registers:
; NONE
; Registers Used:
; H, L, B, C
; Returned Registers:
; NONE
;****************************************************************************************************************
stupPrtcls
ld hl, objctPrtcls ; Point HL at the particle pool
ld bc, NUMPRTCLS * 26 ; Load BC with the number of bytes to clear
call clrMem ; Call the clear mem routine
ret
;****************************************************************************************************************
; Updates a sprites animation frame. The delay between frames being updated and how many frames a sprite has is
; taken from the sprite data that is pointed at by IX
;
; Entry Registers:
; IX = Address of animation object
; Registers Used:
; A, B
; Returned Registers:
; NONE
;****************************************************************************************************************
updtAnmtn
ld a, (ix + BTANMTONCNT) ; Get the current frame timer
inc a ; Increment the frame timer
ld (ix + BTANMTONCNT), a ; Save it
ld b, a
ld a, (ix + BTANMTONDLY)
cp b ; Check the delay (1/50 * n)
ret nz ; and return if we've not reached the delay value
xor a ; Delay has been reached so reset the delay...
ld (ix + BTANMTONCNT), a ; ...and save it
ld a, (ix + BTANMTONFRM) ; Load A with the current frame count
inc a ; Increment the counter
ld b, a ; Setup checking the current counter...
ld a, (ix + BTANMTONTOTAL) ;
cp b ; ...and compare it against the max value allowed...
ld a, b
jr nz, _svFrm ; ...and save the new frame count if the max has not been reached
xor a ; Reset the animation frame to 0
_svFrm
ld (ix + BTANMTONFRM), a ; Save the new frame number
ret ; Return
;****************************************************************************************************************
; Restores the background behind each active particle. When a particle sprite is drawn the contents of the screen
; buffer at the particles location is saved to the particle to be drawn. This data is then restored to erase the
; particle sprite and restore the background underneath it using this routine.
;
; Entry Registers:
; NONE
; Used Registers:
; A, B, C, D, E, H, L
; Returned Registers:
; NONE
;****************************************************************************************************************
rstrScrBckgrnd
ld b, NUMPRTCLS ; Load B with number of particles
ld hl, objctPrtcls + 1 ; Point HL at timer in the first particle
_nxtBckgrnd ld a, (hl) ; Load A with the timer value for the score
or a ; Is the timer 0?
jp nz, _updtBckgrnd ; If not then update it as its active...
ld de, PRTCLSZ ; Move to the next...
add hl, de ; ...particle
djnz _nxtBckgrnd ; Loop if there are particles objects left
ret
_updtBckgrnd
push hl
push bc
inc l ; Point HL at the
inc l ; ...
inc l ; ...
inc l ; high byte of the x position
ld b, (hl) ; Load B with the x pos high byte
inc l ; Point HL at the
inc l ; ...
inc l ; ...
inc l ; high byte of the y position
ld c, (hl) ; Load C with the y pos high byte
inc l ; Point HL at background data
ex de, hl ; Put HL into DE
ld hl, 0x0205 ; Load HL with the size of sprite to restore
call rstrScrnBlck ; Restore the screen with the background data held with the particle
pop bc ; Restore the particle counter
pop hl ; Restore the table pointer
ld de, PRTCLSZ ; Load DE with the size of a single particle...
add hl, de ; ...and add that to HL to move to the next particle
djnz _nxtBckgrnd ; Loop if there are particle objects left
ret
;****************************************************************************************************************
; Update Balls collision points
; Four variables store collision points on the ball, these are middle top, middle right, middle bottom and middle left.
;
; Entry Registers:
; NONE
; Used Registers:
; A, B, C, D, E, H, L
; Returned Registers:
; NONE
;****************************************************************************************************************
updtBllChrPs ; Update the balls character position used in block collision detection
ld hl, objctBall ; Load HL with the address of the ball object data
ld a, (hl) ; Load A with the X position of the ball
add a, BLLPXLWIDTH / 2 ; Increment A by half the width of the ball sprite
ld d, a ; Store A in D
inc hl ; Point HL at the...
inc hl ; ...Y position of the ball
ld e, (hl) ; Load the Y position into E
call getChrLctn ; Get the character location based on D = X and Y = E
ld (ballMT), bc ; The character location is returned in BC so we save that
dec hl ; Point HL at...
dec hl ; X position of the ball object
ld a, (hl) ; Load A with the balls X position...
add a, BLLPXLWIDTH ; ...and add the width of the ball to find the right hand edge
ld d, a ; Save A to D
inc hl ; Point HL at...
inc hl ; ...balls Y position
ld a, (hl) ; Load A with the Y position
add a, BLLPXLHGHT / 2 ; Add half the height of the ball sprite to Y
ld e, a ; Save A in E
call getChrLctn ; Get the character location based on D = X and E = Y
ld (ballMR), bc ; The character location is returned in BC so we save that
dec hl
dec hl
ld a, (hl) ; Middle Bottom
add a, BLLPXLWIDTH / 2
ld d, a
inc hl
inc hl
ld a, (hl)
add a, BLLPXLHGHT
ld e, a
call getChrLctn
ld (ballMB), bc
dec hl
dec hl
ld d, (hl) ; Middle Left
inc hl
inc hl
ld a, (hl)
add a, BLLPXLHGHT / 2
ld e, a
call getChrLctn
ld (ballML), bc
call chckBlckCllsn ; Now go see if the ball has hit something :)
ret ; Return
;****************************************************************************************************************
; Draw the text UI elements e.g. the score, round and lives
;
; Entry Registers:
; NONE
; Registers Used:
; B, C, D, E, H, L
; Returned Registers:
; NONE
;****************************************************************************************************************
drwUI
call romPrntStrng
db CC_INK, YELLOW, CC_AT, 0, 1, 'SCORE', 0xff
call romPrntStrng
db CC_PAPER, GREEN, CC_INK, BLACK, CC_AT, 0, 7, '0000000', 0xff
call romPrntStrng
db CC_PAPER, BLACK, CC_INK, YELLOW, CC_AT, 0, 24, 'LIVES', 0xff
call romPrntStrng
db CC_PAPER, GREEN, CC_INK, BLACK, CC_AT, 0, 30, '5', 0xff
ld de, 0xf000
ld bc, lvsTxt ; Load DE with the address of the Lives Text
call prntStrng
call romPrntStrng
db CC_PAPER, BLACK, CC_INK, YELLOW, CC_AT, 0, 15, "ROUND", 0xff
call romPrntStrng
db CC_PAPER, GREEN, CC_INK, BLACK, CC_AT, 0, 21, "02", 0xff
; ld de, 0xa800
; ld bc, rndTxt
; call prntStrng
ret
;****************************************************************************************************************
; Draw borders
; Draws the left, top and right borders of the playing area
;
; Entry Registers:
; NONE
; Registers Used:
; A, B, C, D, E, H, L
; Returned Registers:
; NONE
;****************************************************************************************************************
drwBrdrs
; Setup the attributes for the borders
ld d, 0x01
ld e, 0x01
_hrzClr
ld a, MAGENTA
push de
call setChrctrAttr
pop de
inc e
ld a, e
cp 31
jr nz, _hrzClr
ld d, 0x01
ld e, 0x01
_VrtClr
ld e, 0x01
ld a, MAGENTA
push de
call setChrctrAttr
pop de
ld e, 30
push de
call setChrctrAttr
pop de
inc d
ld a, d
cp 0x18
jr nz, _VrtClr
; Draw top wall
ld h, 0x00
ld b, SCRNLFT
ld c, 0x08
_hrzntlLp
push hl
push bc
ld de, LoopHSpriteData
xor a
call drwSprt
pop bc
push bc
ld de, LoopHSpriteData
ld a, 0x01
call drwSprt
pop bc
pop hl
ld a, b
add a, 0x10
ld b, a
inc h
ld a, h
cp 0x0e
jr nz, _hrzntlLp
; Draw right hand wall
ld h, 0x00
ld b, SCRNRGHT
ld c, 0x10
_vrtclLp1
push hl
push bc
ld de, LoopVSpriteData
xor a
call drwSprt
pop bc
push bc
ld de, LoopVSpriteData
ld a, 0x01
call drwSprt
pop bc
pop hl
ld a,c
add a, 0x10
ld c, a
inc h
ld a, h
cp 0x0b
jr nz, _vrtclLp1
; Draw Left hand wall
ld h, 0x00
ld b, SCRNLFT - 8
ld c, 0x10
_vrtclLp2
push hl
push bc
ld de, LoopVSpriteData
xor a
call drwSprt
pop bc
push bc
ld de, LoopVSpriteData
ld a, 0x01
call drwSprt
pop bc
pop hl
ld a,c
add a, 0x10
ld c, a
inc h
ld a, h
cp 0x0b
jr nz, _vrtclLp2
ld de, LoopLCSpriteData
ld b, SCRNLFT - 8
ld c, 0x08
ld a, 0x00
call drwSprt
ld de, LoopRCSpriteData
ld b, SCRNRGHT
ld c, 0x08
ld a, 0x00
call drwSprt
ret
;****************************************************************************************************************
; Loop through all particles and draw active ones on the screen
;
; Entry Registers:
; NONE
; Used Registers:
; A, B, C, D, E, H, L
; Returned Registers:
; NONE
;****************************************************************************************************************
drwPrtcls
ld b, NUMPRTCLS
ld hl, objctPrtcls + 1 ; Point HL at the first particles timer data
_chkPrtclActv
ld a, (hl) ; Get the timer for the particle
or a
jp nz, _drwCrrntPrtcl ; If its not zero then its active so draw it
ld de, PRTCLSZ ; Move to the next particle
add hl, de
djnz _chkPrtclActv ; Loop if there are more particles
ret ; Finished
_drwCrrntPrtcl
push bc ; Save BC as its holding our score loop count in B
push hl ; Save HL as this is our pointer into the object table
inc l ; XVector Low
inc l ; XVector high
inc l ; Xpos low
inc l ; Xpos high
ld b, (hl)
inc l
inc l
inc l
inc l
ld c, (hl)
inc l
ex de, hl
push bc
ld hl, 0x0205
call sveScrnBlck
pop bc
xor a
ld de, ParticleSpriteData
call drwMskdSprt
pop hl
pop bc
ld de, PRTCLSZ ; Move to the next particle
add hl, de
djnz _chkPrtclActv ; Loop if there are more particles
ret
;****************************************************************************************************************
; Draw Ball Sprite
; Draws the ball sprite at its current location
;
; Entry Registers:
; NONE
; Used Registers:
; A, B, C, DE
; Returned Registers:
; NONE
;****************************************************************************************************************
drwBll
ld de, SmallBallData ; Point DE to the ball sprite data
ld a, (objctBall + BLLXPS) ; Load A with the balls X position
ld b, a ; Put A into B
ld a, (objctBall + BLLYPS) ; Load A with the balls Y position
ld c, a ; Load C with A so B = X, C = Y
xor a
call drwSprt ; Draw sprite
ret
;****************************************************************************************************************
; Draw Bat
; Draws the bat at its current location
;
; Entry Registers:
; NONE
; Used Registers:
; A, B, C, DE, HL
; Returned Registers:
; NONE