-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBANK_FIXED.asm
executable file
·1538 lines (1123 loc) · 49.9 KB
/
BANK_FIXED.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
; Sokoboo - a Sokoban implementation
; using a generic tile-based display engine for the Atari 2600
; Sokoban (倉庫番)™ is © Falcon Co., Ltd.
;
; Code related to this Sokoban™ implementation was developed by Andrew Davie.
;
; Code related to the generic tile-based display engine was developed by
; Andrew Davie and Thomas Jentzsch during 2003-2011 and is
; Copyright(C)2003-2019 Thomas Jentzsch and Andrew Davie - contacts details:
; Andrew Davie ([email protected]), Thomas Jentzsch ([email protected]).
;
; Code related to music and sound effects uses the TIATracker music player
; Copyright 2016 Andre "Kylearan" Wichmann - see source code in the "sound"
; directory for Apache licensing details.
;
; Some level data incorporated in this program were created by Lee J Haywood.
; See the copyright notices in the License directory for a list of level
; contributors.
;
; Except where otherwise indicated, this software is released under the
; following licensing arrangement...
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; see https://www.gnu.org/licenses/gpl-3.0.en.html
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;------------------------------------------------------------------------------
;############################### FIXED BANK #################################
;------------------------------------------------------------------------------
ORIGIN SET FIXED_BANK
NEWBANK THE_FIXED_BANK
RORG $f800
;------------------------------------------------------------------------------
DEFINE_SUBROUTINE DrawTimeFromROM
lda #BANK_SCORING
sta SET_BANK_RAM
jsr DrawTime
jsr DrawBCD_targetsRequired
lda ROM_Bank
sta SET_BANK
rts
;------------------------------------------------------------------------------
DEFINE_SUBROUTINE GetROMByte ;=23(A)
; a = ROM bank to retrieve
; y = page index
; ROM_Bank = bank to return to
; (Board_AddressR) = page
; out a = byte from (Board_AddressR)
sta SET_BANK ;3
jmp GetBoardCharacter2 ;3+17(A) unconditional
;------------------------------------------------------------------------------
DEFINE_SUBROUTINE GetBoardCharacter ;=20(A)
; call from ROM bank
; switches back to ROM_Bank on exit
; pass A = bank containing character
; Y = x character position
; (Board_AddressR) points to character position
; returns character from board
sta SET_BANK_RAM ;3 switch to bank to read
GetBoardCharacter2 ;=17(A)
lax (Board_AddressR),y ;5
ldy ROM_Bank ;3
sty SET_BANK ;3 switch back caller's bank
rts ;6 and go back
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE PutBoardCharacter ;=21(A)
stx SET_BANK_RAM ; 3
PutBoardCharacterSB ; =18
sta (Board_AddressW),y ; 6
lda ROM_Bank ; 3
sta SET_BANK ; 3
rts ; 6 = 21
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE GetBoardCharacter__CALL_FROM_RAM__ ;=61[-2](A)
ldy POS_Y ;3
lda #BANK_GetBoardAddressR ;
sta SET_BANK ;
jsr GetBoardAddressR ;11+24[-2](A)
;DEFINE_SUBROUTINE PartialGetBoardCharacter ;=23
sta SET_BANK_RAM ;3
ldy POS_X ;3
lax (Board_AddressR),y ;5
ldy RAM_Bank ;3
sty SET_BANK_RAM ;3 return to RAM caller
rts ;6 and go back
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE PutBoardCharacterFromRAM ;=71[-2]
; POS_Y = row
; POS_Type = character to write
; POS_X = column
; RAM_Bank = caller's bank
ldy POS_Y ;3
lda #BANK_GetBoardAddressW ;
sta SET_BANK ;
jsr GetBoardAddressW ;11+24[-2](A)
stx SET_BANK_RAM ;3
ldy POS_X ;3
lda POS_Type ;3
sta (Board_AddressW),y ;6
ldy RAM_Bank ;3
sty SET_BANK_RAM ;3 return to RAM caller
rts ;6
DEFINE_SUBROUTINE PutBoardCharacterFromROM
pha
jsr PutBoardCharacterFromRAM
pla
sta SET_BANK
rts
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE ProcessObjStack ; @31✅ called from Vector
; 15 minimum segtime abort
lda INTIM ; 4
cmp #MINIMUM_SEGTIME ; 2
bcc EarlyAbort ; 2(3)= 8
; => [31]+9+6rts = 46✅ on abort
; @0✅
lda ObjStackNum ; 3
eor #1 ; 2
tax ; 2 = 7✅
lda ObjIterator ; 3
cmp ObjStackPtr,x ; 5
bcs nextPhase ; 2/3 = 10/11[+11] ==> @22✅ on exit
; @17✅
; Process an object...
; Actual object code (the handlers) starts 82 cycles after previous segtime check!
ldy BankObjStack,x ; 4
sty SET_BANK_RAM ; 3 = 7
tax ; 2
ldy SortedObjPtr,x ; 4 = 6 indirect object pointer list (sorted)
lda ObjStackX,y ; 4
sta POS_X ; 3
lda ObjStackY,y ; 4
sta POS_Y ; 3
lda ObjStackVar,y ; 4
sta POS_VAR ; 3
ldx ObjStackType,y ; 4
stx POS_Type ; 3 = 28
lda #BANK_VectorProcess ; 2
sta SET_BANK ; 3
jmp VectorProcess ; 3 = 8
; => [17]+7+6+28+8 = @64 entry to VectorProcess
; + 31 minimum timeout return
; = 95✅
;---------------------------------------------------------------------------
; Now process the blank stack. This stack holds all the recently blanked squares
; and determines (and moves) BOXs or TARGETs into these squares. The space vacated
; by these objects are added again to the blank stack.
nextPhase ; +11✅ for exit from here
inc ScreenDrawPhase ;5 obj/blank finished -- let the draw stuff proceed
EarlyAbort rts ;6
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE SwitchObjects ; = 31 ✅
; The game loop has come to an end. The only possible "still happening" thing is the sort, which runs
; in parallel with other processes (objects, draw stack, etc). We may or may not want to wait for the
; sort to complete. This code does all the checks needed to switch to the next game frame.
lda INTIM ; 4
cmp #SEGTIME_SWITCHOBJECTS ; 2
bcc EarlyAbort ; 2(3) => [31]+(9)+6rts = 46✅ on abort
; If we're undertime, then abort. The sort will continue to run, and that's great. Only when
; we're at the throttle cutoff do we switch game-frames.
; ;sec
; lda Throttle ;3
; sbc #MAX_THROTTLE ;2
; ; bcc EarlyAbort ;2/3 plenty of time left!
; sta Throttle ;3 = 10 save fractional 'left over' bit
; Now that we have completed processing the object stack, we switch
; the stack bank pointers for the next time around.
lda ObjStackNum ;3
eor #1 ;2
tax ;2
stx ObjStackNum ;3 = 10 swap stacks @here
; Initialise the iterator and stack pointer for next time around.
; Previously the stack pointer auto-initialised by popping the stack. Now we have an iterator it's
; necessary to initialise both.
ldy #0 ;2
sty ObjIterator ;3
sty ObjStackPtr,x ;4
sty ScreenDrawPhase ;3
rts ;6
;---------------------------------------------------------------------------
EarlyAbort4 rts
DEFINE_SUBROUTINE PROCESS_MAN
lda INTIM ; 3
cmp #SEGTIME_MAN ; 2
bcc EarlyAbort4 ; 2/3 = 7 + 6rts = 13✅ on abort
lda #BANK_ManProcess
sta ROM_Bank
sta SET_BANK
jsr ManProcess
lda #-1
sta TB_CHAR ; pre-set box takeback to NONE
;sta BufferedJoystick
jsr MovePlayer
DoNothing lda ManMode
cmp #MANMODE_NEXTLEVEL ; kludge
bcs notComplete
lda BCD_targetsRequired
bne notComplete
lda #MANMODE_NEXTLEVEL
sta ManMode
notComplete
lda #BANK_TrackPlayer ;
sta SET_BANK ;
jsr TrackPlayer ;11+145
lda #TYPE_MAN ; 2
sta POS_Type ; 3
jsr InsertObjectStack ; 6+76(B) re-insert man (POS X/Y DOESN'T MATTER)
lda #$FF
sta BufferedJoystick
gnobj jmp NextObject
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE PutCharacterAtXY
; POS_X character location
; POS_Y
; POS_VAR character to put on board
; ROM_Bank ROM bank to return to
ldy POS_Y
lda #BANK_GetBoardAddressW
sta SET_BANK
jsr GetBoardAddressW
stx SET_BANK_RAM
ldy POS_X
lda POS_VAR
sta (Board_AddressW),y
lda ROM_Bank
sta SET_BANK
rts
;---------------------------------------------------------------------------
; IF the creature runs out of time to do stuff, then rts HOWEVER the creature must eventually do something
; as it will be continually called in available time-slices until it does. This can lockup the system.
; if the creature is done, and is alive next cycle, then jump ReInsertObject
; if the creature dies then jump NextObject
ReInsertObject jsr InsertObjectStack ; 6+76(B) = 98 (if jumping here) place on stack so it keeps moving
NextObject inc ObjIterator ; 5
; dec ObjStackPtr,x ; 6
rts ;jmp ProcessObjStack ; 3 = 16 ; DON'T chain, instead return
; let the segtime stuff do its job!
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE InsertObjectStackFromRAM ;=94(B)
jsr InsertObjectStack ;6+76(B)
lda RAM_Bank ;3
sta SET_BANK_RAM ;3
NotEnoughTime rts ;6
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE InsertObjectStack ;=81(B)
; POS_X x position
; POS_Y y position
; POS_VAR direction or other variable
; POS_Type type of object
ldx ObjStackNum ; 3
ldy BankObjStack,x ; 4
sty SET_BANK_RAM ; 3
ldy ObjStackPtr,x ; 4 = 14
lda POS_Y ; 3
sta ObjStackY+RAM_WRITE,y ; 5
lda POS_X ; 3
sta ObjStackX+RAM_WRITE,y ; 5
lda POS_VAR ; 3
sta ObjStackVar+RAM_WRITE,y ; 5
lda POS_Type ; 3
sta ObjStackType+RAM_WRITE,y ; 5 = 32
; Nice addition limits overflow of the stack, BUT always reserves a spot for the man.
; Objects are unceremoniously dumped when there's not enough space. This is just trying to cater
; for a no-win situation. Try and preserve the player at the cost of correct gameplay. Avoid crashing.
IF TYPE_MAN != 0
cmp #TYPE_MAN ; 2
ENDIF
beq alwaysAllowMan ; 2/3
cpy #OBJ_STACK_SIZE-2 ; 2 reserve 1 last-gasp slot for man only
bcs insertDone ; 2/3= 6 no room -- drop object
alwaysAllowMan
tya ; 2
sta SortedObjPtr+RAM_WRITE,y ; 5 indirection pointer for later sorting
inc ObjStackPtr,x ; 7 overflow is assumed not to happen!
insertDone ldy ROM_Bank ; 3
sty SET_BANK ; 3
ManIsDead2
rts ; 6 = 29
;---------------------------------------------------------------------------
BankObjStack .byte BANK_OBJSTACK, BANK_OBJSTACK2
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE MovePlayer
ldy POS_Y_NEW
lda #BANK_GetBoardAddressRW ;2
sta SET_BANK ;3
jsr GetBoardAddressRW ;6+32[-2]
; IF MULTI_BANK_BOARD = YES
; stx RAM_Bank
; ENDIF
stx SET_BANK_RAM ; 3
ldy POS_X_NEW
lax (Board_AddressR),y
lda #BANK_MoveVecLO
sta SET_BANK
lda MoveVecLO,x
sta MAN_Move
lda MoveVecHI,x
sta MAN_Move+1
; IF MULTI_BANK_BOARD = YES
; lda RAM_Bank
; ELSE
lda #BANK_BOARD
; ENDIF
sta SET_BANK_RAM
jmp (MAN_Move)
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE RecordTakeBackPosition
; Pass...
; TB_X the man's position before he moved
; TB_Y
; TB_CHAR if -1 then there is no box push involved, else..
; holds the character that was under the box in its new position
; TB_PUSHX Position of pushed box AFTER it is pushed
; TB_PUSHY
; On making a move,
; man's position before move --> TB_X,TB_Y
; TB_CHAR = -1
; IF a box was pushed,
; TB_CHAR = character under the box's new position (i.e., restoration char)
; box's new position --> TB_PUSHX, TB_PUSHY
; ENDIF
; BCD_moveCounter++
lda TakebackInhibit
bne noLog
lda #BANK_TAKEBACK
sta SET_BANK_RAM
ldx takebackIndex
lda TB_X
sta RAM_WRITE+TakeBackPreviousX,x
lda TB_Y
sta RAM_WRITE+TakeBackPreviousY,x
lda TB_CHAR
sta RAM_WRITE+TakeBackPushChar,x
; if TB_CHAR is -1 that means there is no box component, and the following values are random
lda TB_PUSHX
sta RAM_WRITE+TakeBackPushX,x
lda TB_PUSHY
sta RAM_WRITE+TakeBackPushY,x
lda ROM_Bank
sta SET_BANK
; fall through
DEFINE_SUBROUTINE IncrementMoveCount
lda #BANK_IMC
sta SET_BANK
jsr IMC
lda ROM_Bank
sta SET_BANK
noLog lda #0
sta TakebackInhibit
rts
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE MOVE_BLANK
DEFINE_SUBROUTINE MOVE_SOIL
DEFINE_SUBROUTINE MOVE_TARGET
txa ; character man will be standing on
pha
lda #$FF
sta BufferedJoystick
lda ManAnimationID
cmp #ANIMATION_PUSH_ID
bne immediate
inc idleCount
lda idleCount
cmp #10
bcc walkingOK
lda #0
sta idleCount
immediate
lda ManAnimationID
cmp #ANIMATION_WALK_ID
beq walkingOK
cmp #ANIMATION_WALK2_ID
beq walkingOK
lda #ANIMATION_WALK_ID
sta ManAnimationID
LOAD_ANIMATION WALK
walkingOK
lda ManX
sta POS_X
sta TB_X
lda ManY
sta POS_Y
sta TB_Y
jsr PutCharacterAtXY ; RESTORE (previous XY) under-man character
lda POS_X_NEW
sta ManX
sta POS_X
lda POS_Y_NEW
sta ManY
sta POS_Y
lda #CHARACTER_MANOCCUPIED
sta POS_VAR
jsr PutCharacterAtXY
; TB_X the man's position before he moved
; TB_Y
; TB_CHAR if -1 then there is no box push involved, else..
; holds the character that was under the box in its new position
; this can be inferred by the box character (ONTARGET)
; TB_PUSHX Position of pushed box AFTER it is pushed
; TB_PUSHY
jsr RecordTakeBackPosition
pla
sta POS_VAR ; save 'restore' character
MOVE_GENERIC lda #0 ; 2
sta ManPushCounter ; 3
rts ; 6 = 11
;---------------------------------------------------------------------------
; takeback buffer empty - flash red
noMovesToTake ldx Platform
lda redColour,x
sta BGColour
lda #8
sta ColourTimer
rts
redColour .byte $32, $32, $62, $62
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE MOVE_BOX
ldx #CHARACTER_BLANK ; restoration character
lda #BANK_PushBox
sta SET_BANK
jmp PushBox
DEFINE_SUBROUTINE MOVE_BOX_ON_TARGET
ldx #CHARACTER_TARGET ; restoration character
lda #BANK_PushBox
sta SET_BANK
jmp PushBox
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE takebackRestoreEarlierPosition
; on reverting a move
; IF BCD_moveCounter > 0
; BCD_moveCounter--
; IF TakeBackPushChar != -1
; //restore the character under box (and remove box)
; board[TakeBackPreviousX,TakeBackPreviousY] = TakeBackPushChar
; ENDIF
; // We will "fix" any box going back on the board through the man's restoration char
; board[ManX,ManY] = POS_VAR
; POS_VAR = board[TakeBackX,TakeBackY]
; board[TakeBackX,TakeBackY] = MANOCCUPIED
; ManX,ManY = TakeBackX, TakeBackY
ldx takebackIndex
cpx takebackBaseIndex
beq noMovesToTake
inc TakebackInhibit ; non-zero
dex
txa
and #TAKEBACK_MASK
sta takebackIndex
tax
sed
sec
lda BCD_moveCounter
sbc #1
sta BCD_moveCounter
lda BCD_moveCounter+1
sbc #0
sta BCD_moveCounter+1
cld
#if 0
lda Platform
clc
adc #8
sta BGColour ;ColourFlash ; yellow flash
lda #3
sta ColourTimer
#endif
lda #BANK_TAKEBACK
sta SET_BANK_RAM
; TB_X the man's position before he moved
; TB_Y
; TB_CHAR if -1 then there is no box push involved, else..
; holds the character that was under the box in its new position
; TB_PUSHX Position of pushed box AFTER it is pushed
; TB_PUSHY
; //restore the character under box (and remove box)
; board[TakeBackPreviousX,TakeBackPreviousY] = TakeBackPushChar
lda POS_VAR
pha
ldx takebackIndex
lda TakeBackPushChar,x
bmi noPushInvolved ; -1 = no box
sta POS_VAR
cmp #CHARACTER_TARGET
beq isaTarget
cmp #CHARACTER_TARGET2
bne notTarget1
isaTarget jsr RegisterTarget
notTarget1
lda TakeBackPushX,x
sta POS_X
lda TakeBackPushY,x
sta POS_Y
jsr PutCharacterAtXY ; fixup BOX!
pla
beq blnkre
jsr DeRegisterTarget
lda #CHARACTER_BOX_ON_TARGET
bne skls
blnkre lda #CHARACTER_BOX
skls sta POS_VAR
pha
noPushInvolved pla ; man's replacement char
sta POS_VAR
; // We will "fix" any box going back on the board through the man's restoration char
; board[ManX,ManY] = POS_VAR
; POS_VAR = board[TakeBackX,TakeBackY]
; board[TakeBackX,TakeBackY] = MANOCCUPIED
; ManX,ManY = TakeBackX, TakeBackY
lda ManX
sta POS_X
lda ManY
sta POS_Y
jsr PutCharacterAtXY ; put what man was on... back
lda #BANK_TAKEBACK
sta SET_BANK_RAM
ldx takebackIndex
lda TakeBackPreviousX,x
sta POS_X_NEW
sta ManX
lda TakeBackPreviousY,x
sta POS_Y_NEW
sta ManY
; Grab the character from the board at man's location and use as "restore character" for man
; POS_VAR = board[takebackx,takebacky]
lda #BANK_GetBoardAddressR
sta SET_BANK
ldy POS_Y_NEW
jsr GetBoardAddressR
sta SET_BANK_RAM
ldy POS_X_NEW
lda (Board_AddressR),y
;pha
;lda #CHARACTER_MANOCCUPIED
;sta POS_VAR
;jsr PutCharacterAtXY ????
;pla
sta POS_VAR
lda ROM_Bank
sta SET_BANK
timeExit rts
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE StealCharDraw; in FIXED_BANK
lda #BANK_DRAW_BUFFERS ; 2
sta SET_BANK_RAM ; 3
ldy DrawStackPointer ; 3 MUST have been set by BuildDrawStack!
bpl EnterStealCharDraw ; 2(3) = 10(11)
ExitStealCharDraw
; fall through...
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE TimeSlice
; FIRST check the time is sufficient for the smallest of the timeslices. Not much point
; going ahead if there's insufficient time. This allows the previous character drawing to
; be much smaller in time, as they don't have to include the timeslice code overhead.
lda INTIM ; 4
cmp #SEGTIME_MINIMUM_TIMESLICE ; 2
bcc timeExit ; 2(3)
; @0✅
; Uses the phase variable to vector to the correct processing code for the given timeslice
; Code may be in any bank. Avoid the fixed bank at all costs! Once a section is complete
; it should increment ScreenDrawPhase.
; Switched-in bank(s) are undefined after this function is called!
lda #BANK_TS_PhaseVectorLO ; 2
sta SET_BANK ; 3 = 5
ldx ScreenDrawPhase ; 3 current phase of drawing
lda TS_PhaseVectorLO,x ; 4
sta TS_Vector ; 3
lda TS_PhaseVectorHI,x ; 4
sta TS_Vector+1 ; 3 = 17
lda TS_PhaseBank,x ; 4
sta SET_BANK ; 3 = 7 switch bank
jmp (TS_Vector) ; 5 = 31✅ vector to timeslice handler
;---------------------------------------------------------------------------
DrawAnother ;344✅SCD_QUICK
;676✅SCD_SLOW
; add 44✅ cycles for the following in the case where there is something to draw
; but no time to do it. As this is executed after EVERY type of draw, then this
; is the base "extra" cost to add to each draw
CYCLES_DRAWANOTHER = 53 ;✅
lda #BANK_DRAW_BUFFERS ; 2 A = SCREEN_LINES
sta SET_BANK_RAM ; 3 = 5
ldy DrawStackPointer ; 3 = 3 MUST have been set by BuildDrawStack!
ldx DrawStack,y ; 4 in actuality a character index
lda ScreenBuffer,x ; 4 new character to draw
and #~128 ; 2
sta ScreenBuffer+RAM_WRITE,x ; 4 = 14 clear hint bit
dey ; 2
sty DrawStackPointer ; 3 one less to draw
bmi ExitStealCharDraw ; 2(3)=7 NOTE1: (3)+(15exit) -->45✅ <CYCLES_DRAWANOTHER)
; => 29
EnterStealCharDraw: ; @11✅ from initial StealCharDraw call
; RAM bank MUST be at BANK_DRAW_BUFFERS
lda INTIM ; 4
cmp #SEGTIME_SCD_MIN ; 2
bcc ExitStealCharDraw ; 2(3) = 8 ((9)+(15exit) IF EXITING HERE, from DrawAnother... 53✅)
; else exit from StealCharDraw ... 26✅
; @0✅
ldx DrawStack,y ; 4 in actuality a character index
ldy ScreenBuffer,x ; 4 = 8✅ new character to draw
lda ROW_BankChar,x ; 4 A = 0..SCREEN_LINES-1
sta SET_BANK_RAM ; 3
jmp StealPart3 ; 3 = 10✅ --> 18✅ cycles after check for SEGTIME_SCD_MIN
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE writePlayerFrame
lda Platform
and #%10
asl
asl
adc ethnic
sta ethnicity
; todo - compare with last + frame and skip if same
lda #PLAYER_FRAMES
sta SET_BANK
lda animation_delay
beq getDelay ; FIRST usage
dec animation_delay
bne nextAnimation2 ; just get shape
nextAptr clc
lda animation
adc #2
sta animation
bcc ahiok
inc animation+1
ahiok
getDelay ldy #1
lda (animation),y
sta animation_delay
nextAnimation2 ldy #0
lda (animation),y
cmp #JUMP
beq aJump
cmp #FLIP
bne notFlip
lda ManLastDirection
eor #%1000
sta ManLastDirection
jmp nextAptr
; it's a jump
aJump ldy animation_delay ; actually animation ID :)
lda ANIM_TABLE,y
sta animation
lda ANIM_TABLE+1,y
sta animation+1
jmp getDelay
notFlip tay
lda ManDrawY
bmi SkipFrameCopy
sta bank ; character line (and hence bank) of player position
sta SET_BANK_RAM
; Now we have the frame #, we can see if that frame has already been drawn into
; the frame buffer of the relevant bank. If it has, then we don't need to repeat
; and can save the enormous cost of frame copying...
cpy ExistingFrame ; optimize - don't draw if same frame
beq SkipFrameCopy
sty ExistingFrame + RAM_WRITE
lda #PLAYER_FRAMES
sta SET_BANK
lda FRAME_PTR_LO,y
sta frame_ptr
lda FRAME_PTR_HI,y
sta frame_ptr+1
lda COLOUR_PTR_LO,y
sta colour_ptr
lda COLOUR_PTR_HI,y
sta colour_ptr+1
ldy #LINES_PER_CHAR-1
clc
CopySpriteToBank ; 408
; The colours for the sprites are copied to the row bank's colour data. The frames contain
; colour *indexes*. These indexes are modified by the *base* which indicates both the
; system NTSC/PAL along with the "visual identity" (i.e., colour/race). That is used to
; lookup a colour conversion which FINALLY gives us the correct colour to use for the line.
; ethnicity * 16 + PALNTSC * 8
lda #PLAYER_FRAMES
sta SET_BANK
lda (colour_ptr),y
adc ethnicity ; colour base
tax
lda (frame_ptr),y
pha
lda bank
sta SET_BANK_RAM
lda EthnicityColourPalette,x
sta PLAYER0_COLOUR+RAM_WRITE,y
pla
sta PLAYER0_SHAPE+RAM_WRITE,y
dey
bpl CopySpriteToBank
skipOffscreen
SkipFrameCopy rts
;---------------------------------------------------------------------------
; DEFINE_SUBROUTINE DrawFullScreenMain ;=2484[-89]
; Check the screen for all those characters that need to be redrawn
; Just copies the mxn grid from the board to a DrawFlags array. If the entry in
; the drawflags array is different to the ScreenBuffer array entry, then the
; screenbuffer will need redrawing.
; @59✅
CopyRow2
; IF MULTI_BANK_BOARD = YES
; lda BDF_BoardBank ; 3
; ELSE
lda #BANK_BOARD ; 2 saves 5*8 = 40 cyles
; ENDIF
sta SET_BANK_RAM ; 3
lax (BDF_BoardAddress),y ; 5
txs ; 2
lax (BDF_BoardAddress2),y ; 5 = 17✅
lda #BANK_DRAW_BUFFERS ; 2
sta SET_BANK_RAM ; 3
lda CharReplacement,x ; 4
sta (BDF_DrawFlagAddress2),y ; 6
tsx ; 2
lda CharReplacement,x ; 4
sta (BDF_DrawFlagAddress),y ; 6 = 27 @44✅
dey ; 2
bpl CopyRow2 ; 2/3 @48 (-1)
CHECKPAGEX CopyRow2, "CopyRow2 in BANK_FIXED"
; cost = 5 (rows) x 48 - 1 = 239
; @ (59) + 239 = @298✅
lax DHS_Line ; 3
beq .exitCopy ; 2/3= 5/6
ldy #BANK_DrawScreenRowPreparation ; 2
sty SET_BANK ; 3
jmp DrawScreenRowPreparation ; 3 = 8
; @298+8+5 = @311✅
; total: (244[-5]+5)*8 + 60[-7]*7 + 1 + 11 = 2424[-89]
CHECKPAGEX CopyRow2, "CopyRow2 in BANK_FIXED.asm"
.exitCopy ldx DHS_Stack ; 3
txs ; 2
; fall through