-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCode.asm
3069 lines (2666 loc) · 111 KB
/
Code.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
; Griever's Stuff
; -=#Battle City - Back From Source#=-
INCLUDE RAM.asm; Описание всех переменных вынесено в отдельный файл.
INCLUDE REGS.asm; Регистры вынесены в отдельный файл.
; ═══════════════════════════════════════════════════════════════════════════
; Заголовок формата iNES:
.BYTE 'NES',$1A ;String "NES^Z" used to recognize .NES files
.BYTE 2 ;Number of 16kB ROM banks.
.BYTE 1 ;Number of 8kB VROM banks.
DSB 10,0
; ═══════════════════════════════════════════════════════════════════════════
$ = $8000
INCLUDE Level.asm; В верхнем окне будут уровни.
PAD $C000; в нижнем окне - код.
; ═══════════════════════════════════════════════════════════════════════════
; Segment type: Pure code
StaffString: .BYTE 'RYOUITI OOKUBO TAKEFUMI HYOUDOUJUNKO OZAWA '
; DATA XREF: StaffStr_Store:-r
; StaffStr_Check+5r
; ───────────────────────────────────────────────────────────────────────────
RESET: ; DATA XREF: ROM:FFFCo ROM:FFFEo
SEI
LDA #00010000b
STA PPU_CTRL_REG1 ; Бэкграунду второй знакогенератор
CLD
LDX #2
Wait: ; CODE XREF: ROM:C07Cj ROM:C084j
LDA PPU_STATUS ; PPU Status Register (R)
BPL Wait
LDA #00000110b
STA PPU_CTRL_REG2 ; PPU Control Register #2 (W)
DEX
BNE Wait
LDX #$7F ; '' ; Вершина стека
TXS
JSR Reset_ScreenStuff
LDA #0
STA Scroll_Byte
STA PPU_REG1_Stts
JSR Set_PPU
BEGIN: ; CODE XREF: ROM:Skip_RecordShowj
JSR Draw_TitleScreen
LDA #0
STA Construction_Flag ; Пока в Construction не заходили
; START OF FUNCTION CHUNK FOR BonusLevel_ButtonCheck
New_Scroll: ; CODE XREF: BonusLevel_ButtonCheck-372j
JSR Null_Upper_NT
JSR Scroll_TitleScrn ; Убираем из верхней (0(1)) тайловой карты уровень и
; скроллим на титульник в нижней (2(3))тайловой карте.
Title_Loaded: ; CODE XREF: ROM:C156j
; BonusLevel_ButtonCheck+2Bj
; Scroll_TitleScrn+1Aj
JSR Title_Screen_Loop
JSR Load_DemoLevel
JSR BonusLevel_ButtonCheck ; Рекурсия.
JMP New_Scroll ; После окончания бонус уровня, заново скроллируем титульник.
; END OF FUNCTION CHUNK FOR BonusLevel_ButtonCheck
; ───────────────────────────────────────────────────────────────────────────
Construction: ; CODE XREF: ROM:CA82j
LDA Construction_Flag ; Выставляется, если зашли в Construction
BNE Skip_LoadFrame ; Если уже заходили в Construction, рамка уже отрисована
JSR Screen_Off
JSR Make_GrayFrame
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
Skip_LoadFrame: ; CODE XREF: ROM:C0B0j
JSR Null_Status
LDA #$10
STA Tank_X
LDA #$18
STA Tank_Y ; Начальная позиция танка на экране
LDA #$84 ; 'Д'
STA Tank_Status ; Дулом вверх
LDA #0
STA Tank_Type
STA Spr_Attrib
STA Track_Pos
STA BkgOccurence_Flag
STA byte_7B
STA TSA_BlockNumber
STA Scroll_Byte
STA PPU_REG1_Stts
STA Player_Blink_Timer ; Таймер мигания friendly fire
STA Player_Blink_Timer+1 ; Таймер мигания friendly fire
LDA Construction_Flag ; Выставляется, если зашли в Construction
BNE Construction_Loop
JSR DraW_Normal_HQ ; Если уже заходили в Construction, штаб уже отрисован
Construction_Loop: ; CODE XREF: ROM:C0E5j ROM:C14Dj
JSR NMI_Wait ; Ожидает немаскируемого прерывания
JSR Move_Tank ; Двигает танк в зависимости от нажатых кнопок
JSR Check_BorderReach ; Не дает танку выйти за границы серой рамки
LDA Frame_Counter
AND #$10
BEQ Skip_Status_Handle
JSR TanksStatus_Handle ; Обрабатывает статусы всех 8-ми танков
Skip_Status_Handle: ; CODE XREF: ROM:C0F7j
LDA Joypad1_Buttons
AND #$F0 ; 'Ё'
BNE loc_C13E
LDA Joypad1_Differ
AND #1
BEQ loc_C120
LDA BkgOccurence_Flag
BNE loc_C111
INC BkgOccurence_Flag
JMP Construct_Draw_TSA
; ───────────────────────────────────────────────────────────────────────────
loc_C111: ; CODE XREF: ROM:C10Aj
INC TSA_BlockNumber
LDA TSA_BlockNumber
CMP #$E
BNE Construct_Draw_TSA
LDA #0
STA TSA_BlockNumber
JMP Construct_Draw_TSA
; ───────────────────────────────────────────────────────────────────────────
loc_C120: ; CODE XREF: ROM:C106j
LDA Joypad1_Differ
AND #2
BEQ loc_C13E
LDA BkgOccurence_Flag
BNE loc_C12F
INC BkgOccurence_Flag
JMP Construct_Draw_TSA
; ───────────────────────────────────────────────────────────────────────────
loc_C12F: ; CODE XREF: ROM:C128j
DEC TSA_BlockNumber
LDA TSA_BlockNumber
CMP #$FF
BNE Construct_Draw_TSA
LDA #$D ; $D - первый пустой блок
STA TSA_BlockNumber
JMP Construct_Draw_TSA
; ───────────────────────────────────────────────────────────────────────────
loc_C13E: ; CODE XREF: ROM:C100j ROM:C124j
LDA Joypad1_Buttons
AND #3 ; При нажатии А или В рисуется блок под танком
BEQ Construct_StartCheck
Construct_Draw_TSA: ; CODE XREF: ROM:C10Ej ROM:C117j
; ROM:C11Dj ROM:C12Cj ROM:C135j
; ROM:C13Bj
JSR Draw_TSA_On_Tank ; Рисует TSA блок под танком
Construct_StartCheck: ; CODE XREF: ROM:C142j
LDA Joypad1_Differ
AND #8
BNE End_Construction ; Если нажато старт, выходим
JMP Construction_Loop
; ───────────────────────────────────────────────────────────────────────────
End_Construction: ; CODE XREF: ROM:C14Bj
LDA #$20 ; ' '
STA Spr_Attrib
INC Construction_Flag ; Помечаем, что зашли в Construction
JMP Title_Loaded
; ───────────────────────────────────────────────────────────────────────────
Start_StageSelScrn: ; CODE XREF: ROM:C280j ROM:CA7Bj
JSR NMI_Wait ; Ожидает немаскируемого прерывания
JSR Sound_Stop ; Останавливаем звук, включаем каналы и т.п. (аналогично Load в NSF формате)
LDA #$1C
STA PPU_Addr_Ptr ; Запись будет в верхнюю NT
LDA #0
STA Scroll_Byte
STA PPU_REG1_Stts
STA Pause_Flag
LDA #4
STA BkgPal_Number
JSR FillNT_with_Grey ; создаёт эффект сходящихся вертикальных створок
StageSelect_Loop: ; CODE XREF: ROM:C19Bj ROM:C1A1j
; ROM:C1AEj ROM:C1B4j ROM:C1BCj
; ROM:C1C2j
;!Определяем нужен ли нам Уровень с боссом (каждый восьмой уровень)
LDA Level_Number
AND #7
BNE Skip_Make_Armour
LDA #1
sta Boss_Mode
Lda #Init_Boss_Armour
Sta Boss_Armour
jmp Draw_Stage_String
Skip_Make_Armour:
lda #0
Sta Boss_Armour
sta Boss_Mode
Draw_Stage_String:
JSR Draw_StageNumString
;! Сразу начинаем уровень - безо всяких проверок на кнопки или флага начала игры.
; ───────────────────────────────────────────────────────────────────────────
Start_Level: ; CODE XREF: ROM:C177j ROM:C17Dj
Init_Boss_Armour = #10
LDA Construction_Flag ; Выставляется, если зашли в Construction
BNE Skip_Lvl_Load ; Если побывали в Construction, то
; данные уровня загружаться не будут (они уже в NT_Buffer)
; (только танки и штаб)
;! Определяем какой уровень нужно загрузить: обычный или случайный.
Get_Map_Mode:
Lda Map_Mode_Pos
BEQ Orig_Map
CMP #2
BCC Random_Map
JSR Get_Random_A ;Выбран пункт Mixed
AND #1
JMP Make_Gray_Frame
Orig_Map:
LDA #0 ;Выбран пункт Original
JMP Make_Gray_Frame
Random_Map:
LDA #1 ;Выбран пункт Random
Make_Gray_Frame:
STA Random_Level_Flag
JSR Make_GrayFrame
LDA Level_Number
JSR Load_Level; Тут будет проверен флаг случайного и если нужно, загружен пустой уровень
;!Проверяем флаг и если надо рисуем на пустом уровне лабиринт.
ldx Random_Level_Flag
Beq ++++
jsr Draw_Random_Level
++++
JSR DraW_Normal_HQ ; Рисует штаб с кирпичами
JMP +
; ───────────────────────────────────────────────────────────────────────────
Skip_Lvl_Load: ; CODE XREF: ROM:C1D2j
JSR Draw_Naked_HQ ; Даже если штаб был зарисован в Construction, он будет поверх
+:
LDA #1
STA Snd_Battle1
STA Snd_Battle2
STA Snd_Battle3 ; Проигрываем мелодию боя
; CODE XREF: ROM:C1DFj
LDA #0
STA ScrBuffer_Pos
JSR Copy_AttribToScrnBuff
JSR FillNT_with_Black ; Создаёт эффект расходящихся вертикальных створок
LDA #0
STA BkgPal_Number
JSR NMI_Wait ; Ожидает немаскируемого прерывания
JSR SetUp_LevelVARs
Battle_Engine: ; CODE XREF: ROM:C221j
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA Pause_Flag
BNE Skip_Battle_Loop ; В режиме паузы не нужно обрабатывать танки, жизни и т.п.
JSR Battle_Loop ; Основные операции с танками и пулями
Skip_Battle_Loop: ; CODE XREF: ROM:C1FEj
JSR Bonus_Draw ; Рисует или пустоту или бонус или очки за бонус
JSR Draw_All_BulletGFX ; Рисует все пули
JSR TanksStatus_Handle ; Обрабатывает статусы всех 8-ми танков
LDA Joypad1_Differ
AND #8 ; Проверка на нажатие старт
BEQ Skip_Pause_Switch
LDA #1
EOR Pause_Flag
STA Pause_Flag ; Переключаем флаг паузы на противоположный
STA Snd_Pause
Skip_Pause_Switch: ; CODE XREF: ROM:C210j
JSR Draw_Pause ; Рисует мигающую надпись, в случае если выставлена пауза
JSR LevelEnd_Check ; if ExitLevel then A=1
BEQ Battle_Engine
LDA #0
STA Seconds_Counter
STA Frame_Counter ; Останавливаем таймеры
STA Snd_Move
STA Snd_Engine ; Останавливаем звуки
LDA GameOverStr_Timer
BEQ AfterDeath_BattleRun
LDA #$FE ; '■'
STA Seconds_Counter
AfterDeath_BattleRun: ; CODE XREF: ROM:C232j ROM:C251j
JSR NMI_Wait ; Ожидает немаскируемого прерывания
JSR FreezePlayer_OnHQDestroy ; Лишает игрока подвижности, если штаб разрушен
JSR Battle_Loop ; Основные операции с танками и пулями
JSR Bonus_Draw ; Рисует или пустоту или бонус или очки за бонус
JSR TanksStatus_Handle ; Обрабатывает статусы всех 8-ми танков
JSR Draw_All_BulletGFX ; Рисует все пули
JSR Swap_Pal_Colors ; Периодическое мигание - эффект воды на 01 палитре
LDA Seconds_Counter
CMP #2 ; 2 Секунды держится неподвижная надпись GameOver c замороженным игроком
BNE AfterDeath_BattleRun
JSR Sound_Stop ; Останавливаем звук, включаем каналы и т.п. (аналогично Load в NSF формате)
JSR Draw_Pts_Screen
Check_GameOver: ; CODE XREF: ROM:C26Dj
LDA Player1_Lives
CLC
ADC Player2_Lives
BEQ Make_GameOver ; Если жизней ни у кого не осталось, геймовер
LDA HQ_Status ; 80=штаб цел, если ноль то уничтожен
CMP #$80 ; 'А'
BNE Make_GameOver ; Если штаб разрушен, геймовер
INC Level_Number ;! Увеличиваем псевдономер уровня (из 99-ти)
LDA Level_Number
Cmp #51
BCC Skip_Make_Hard
LDA #1
STA Level_Mode
Skip_Make_Hard:
LDA Level_Number
CMP #100
BCC Continue_Game
Lda #1 ;отображаем финальный экран.
STA Level_Number
LDA #0
STA Level_Mode
JSR Draw_Congrats ; Рисует большую кирпичную надпись с поздравлением
JSR Clear_NT ; Очищаем верхнюю карту тайлов (титульник будет в нижней)
JMP BEGIN
Continue_Game:
JMP Start_StageSelScrn ; Если мы вышли из уровня победителями, то переходим к следующему уровню
; ───────────────────────────────────────────────────────────────────────────
Make_GameOver:
LDA #0
STA Boss_Mode ; CODE XREF: ROM:C278j ROM:C27Ej
JSR Draw_Brick_GameOver ; Рисует большую кирпичную надпись GameOver
;! Если произошел геймовер, то откатываемся на 5 уровней назад, предварительно проверив сам номер уровня.
Lda Level_Number
CMP #6
BCC +; Если номер уровня меньше 6, то отнимать 5 уровней нельзя.
SEC
SBC #5
STA Level_Number
+
JSR Update_HiScore ; На выходе A = $FF, значит есть рекорд
TYA
BEQ Skip_RecordShow
JSR Draw_Record_HiScore ; Рисует большую кирпичную надпись с рекордом
JSR Clear_NT ; Очищаем верхнюю карту тайлов (титульник будет в нижней)
Skip_RecordShow: ; CODE XREF: ROM:C28Aj
JMP BEGIN
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
Clear_NT: ; CODE XREF: ROM:C28Fp
JSR Screen_Off
JSR Null_NT_Buffer
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
RTS
; End of function Clear_NT
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Лишает игрока подвижности, если штаб разрушен
FreezePlayer_OnHQDestroy: ; CODE XREF: ROM:C23Bp
LDA HQ_Status ; 80=штаб цел, если ноль то уничтожен
CMP #$80 ; 'А'
BEQ +
LDA #0
STA Joypad1_Buttons
STA Joypad2_Buttons
STA Joypad1_Differ
STA Joypad2_Differ
+: ; CODE XREF: FreezePlayer_OnHQDestroy+4j
RTS
; End of function FreezePlayer_OnHQDestroy
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
Null_both_HiScore: ; CODE XREF: ROM:CA78p
LDX #HiScore_1P_String
JSR Null_8Bytes_String
LDX #HiScore_2P_String
JSR Null_8Bytes_String
; End of function Null_both_HiScore
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
Init_Level_VARs: ; CODE XREF: Load_DemoLevel+8p
LDA #0
STA Player_Type ; Вид танка игрока
STA Player_Type+1 ; Вид танка игрока
LDA #0
STA AddLife_Flag ; <>0 - игрок получал дополнительную жизнь
STA AddLife_Flag+1 ; <>0 - игрок получал дополнительную жизнь
STA EnterGame_Flag ; Если 0, то можно выбрать уровень
LDA #3 ; Начальное количество жизней
STA Player1_Lives
STA Player2_Lives
STA EnemyRespawn_PlaceIndex
LDA CursorPos
BNE +
LDA #0 ; Если 2 игрока нет, обнуляем его жизни
STA Player2_Lives
+: ; CODE XREF: Init_Level_VARs+1Aj
LDA #0 ; Game Over будет отображаться
STA Level_Mode
RTS
; End of function Init_Level_VARs
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Основные операции с танками и пулями
Battle_Loop: ; CODE XREF: ROM:C200p ROM:C23Ep
; BonusLevel_ButtonCheck+Cp
JSR Ice_Detect ; Обрабатывает игрока, если тот на льду
JSR Ice_Move ; Выполняет скольжение, если танк двигается на льду
JSR Motion_Handle ; Замораживает врагов, если нужно (обработка движения)
JSR HideHiBit_Under_Tank
JSR AllBulletsStatus_Handle ; Обрабатывает статусы всех пуль
JSR HQ_Handle ; Обрабатывает статус и броню штаба
JSR Invisible_Timer_Handle ; Рисует силовое поле, если нужно
JSR Make_Player_Shot ; Делает выстрел игрока, если нажата кнопка
JSR Make_Enemy_Shot ; Производит выстрел, используя случайные числа
JSR Respawn_Handle
JSR Bullet_Fly_Handle ; Обрабатывает полет пули (столкновение и т.п.)
JSR BulletToBullet_Impact_Handle ; Обрабатывает столкновение двух пуль, если оно есть
JSR BulletToTank_Impact_Handle ; Обрабатывает столкновение пули с танком
JSR Bonus_Handle ; Обрабатывает взятие бонуса, если таковое есть
JSR GameOver_Str_Move_Handle ; Выводит надпись Game Over если нужно
JSR Play_Snd_Move ; Играет и гасит звук движения когда нужно
JSR Draw_Player_Lives ; Рисует IP/IIP и число жизней в правом углу
JSR Swap_Pal_Colors ; Периодическое мигание - эффект воды на 01 палитре
RTS
; End of function Battle_Loop
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Периодическое мигание - эффект воды на 01 палитре
Swap_Pal_Colors: ; CODE XREF: ROM:C24Ap Battle_Loop+33p
LDA Frame_Counter
AND #$3F ; '?'
BEQ switch
CMP #$20 ; ' '
BNE exit
LDA #1
STA BkgPal_Number
RTS
; ───────────────────────────────────────────────────────────────────────────
switch: ; CODE XREF: Swap_Pal_Colors+4j
LDA #2
STA BkgPal_Number
exit: ; CODE XREF: Swap_Pal_Colors+8j
RTS
; End of function Swap_Pal_Colors
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
SetUp_LevelVARs: ; CODE XREF: ROM:C1F6p
; Load_DemoLevel+5Ap
JSR Hide_All_Bullets ; Уводим с экраны все пули
JSR Null_Status
LDA #$F0 ; 'Ё'
STA GameOverStr_Y ; Уводим за экран надпись
LDA #0
STA GameOverStr_Timer
LDA Player1_Lives ; Если жизней нет,
; больше не респаунимся
BEQ +
LDX #0
JSR Make_Respawn
+: ; CODE XREF: SetUp_LevelVARs+12j
LDA Player2_Lives
BEQ Set_VARs
LDX #1
JSR Make_Respawn
Set_VARs:
LDA Boss_Mode;!
BEQ Skip_Boss_Mode
LDA Level_Number
CMP #80;! После 80 уровня два босса
BCC Low_Levels
LDA #2
JMP Save_Enemy_Counter
Low_Levels:
LDA #1
JMP Save_Enemy_Counter;! босс будет один, а после 80-го уровня их станет два.
Skip_Boss_Mode:
LDA #20 ;20 врагов в каждом уровне
Save_Enemy_Counter:
STA Enemy_Reinforce_Count ; Количество врагов в запасе
STA Enemy_Counter ; Количество врагов на экране и в запасе
LDA #0
STA Enemy_TypeNumber
STA Seconds_Counter
STA Construction_Flag ; Выставляется, если зашли в Construction
STA HQArmour_Timer ; Таймер брони вокруг штаба
STA Player_Blink_Timer ; Таймер мигания friendly fire
STA Player_Blink_Timer+1 ; Таймер мигания friendly fire
STA Invisible_Timer ; Силовое поле вокруг игрока после рождения
STA byte_8A
STA Respawn_Timer ; Время до следующего респауна
STA Bonus_X
STA EnemyFreeze_Timer
STA EnemyRespawn_PlaceIndex ; Начинаем респауниться слева
JSR Null_KilledEnms_Count ; Обнуляет массив счётчиков убитых врагов
JSR Draw_Reinforcemets
JSR NMI_Wait ; Ожидает немаскируемого прерывания
JSR Draw_IP
JSR Draw_LevelFlag
LDA Boss_Mode
BEQ Skip_Boss_Mode2
JSR Get_Random_A ; в режиме босса записываем единицу в один из типов врагов
AND #3
TAY
LDA #1
STA Enemy_Count,Y
JMP Init_HQ_Stat
Skip_Boss_Mode2:
JSR Load_Enemy_Count
Init_HQ_Stat:
LDA #$80 ; 'А'
STA HQ_Status ; 80=штаб цел, если ноль то уничтожен
LDA #1
STA Snd_Engine
STA EnterGame_Flag ; Если 0, то можно выбрать уровень
LDA Level_Mode
CMP #1
BNE ++
LDA #35
JMP Respawn_Delay_Calc
; ───────────────────────────────────────────────────────────────────────────
++: ; CODE XREF: SetUp_LevelVARs+64j
LDA Level_Number
Respawn_Delay_Calc: ; CODE XREF: SetUp_LevelVARs+68j
CMP #43 ;! На уровнях выше 42, оставляем время на респаун минимальным
BCC Level_Small
LDA #42
Level_Small:
ASL A
ASL A
STA Temp
LDA #190
SEC
SBC Temp
STA Respawn_Delay ; Задержка между респаунами врагов
LDA CursorPos
BEQ +++
LDA Respawn_Delay ; Задержка между респаунами врагов
SEC
SBC #20
STA Respawn_Delay ; Задержка между респаунами во фреймах может быть вычислена по формуле:
; 190 - (№уровня)*4 - (количество_игроков - 1)*20
+++: ; CODE XREF: SetUp_LevelVARs+7Aj
RTS
; End of function SetUp_LevelVARs
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
Load_DemoLevel: ; CODE XREF: BonusLevel_ButtonCheck-378p
LDA #1
STA Pause_Flag
LDA #0
STA BkgPal_Number
JSR Init_Level_VARs
LDA #3
STA Player2_Lives ; Вне зависимости от выбора игрока,
; появится второй танк.
LDA #0
STA Scroll_Byte ; Таким образом на экране будет содержимое 0(1)
; тайловой карты. Во 2(3) всегда находится титульник,
; что позволяет не загружать его каждый раз, когда
; нужно вернуться (в этом случае очищаются 0(1)
; тайловые карты и происходит скролл на 2(3), который
; также заметен глазу игрока)
STA PPU_REG1_Stts
STA Seconds_Counter
STA Frame_Counter
JSR Make_GrayFrame
LDA #$FF
STA Level_Number
JSR Load_Level
LDA #1
STA Level_Number ; В правом углу во время бонус уровня указан
; именно 30-й номер уровня, хотя по
; содержимому это и не он
LDA #2
STA Level_Mode
JSR Screen_Off
LDX #$1A
STX Block_X
LDY #$46 ; 'F'
STY Block_Y
LDA #>aBattle ; "BATTLE\xFF"
STA HighStrPtr_Byte
LDA #<aBattle ; "BATTLE\xFF"
STA LowStrPtr_Byte ; Загрузка указателя для "Кирпичного" слова 'BATTLE'
;
JSR Draw_BrickStr
LDX #$3C ; '<'
STX Block_X
LDY #$78 ; 'x'
STY Block_Y ;
;
LDA #>aCity ; "CITY\xFF"
STA HighStrPtr_Byte
LDA #<aCity ; "CITY\xFF"
STA LowStrPtr_Byte ; Загрузка указателя для "Кирпичного" слова 'CITY'
;
JSR Draw_BrickStr
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
JSR SetUp_LevelVARs
JSR DraW_Normal_HQ ; Рисует штаб с кирпичами
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA #5
STA TanksOnScreen ; Максимальное количество всех танков на экране
RTS
; End of function Load_DemoLevel
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
BonusLevel_ButtonCheck: ; CODE XREF: BonusLevel_ButtonCheck-375p
; BonusLevel_ButtonCheck+1Bj
; FUNCTION CHUNK AT C09C SIZE 00000012 BYTES
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA Joypad1_Differ
AND #1100b ; проверка на select(4) или start(8)
; во время скроллинга титульника или
; бонус уровня.
BNE Button_Pressed
DemoLevel_Loop: ; Управление танками игроков во время демо уровня
JSR Demo_AI
JSR Battle_Loop ; Основные операции с танками и пулями
JSR Bonus_Draw ; Рисует или пустоту или бонус или очки за бонус
JSR TanksStatus_Handle ; Обрабатывает статусы всех 8-ми танков
JSR Draw_All_BulletGFX ; Рисует все пули
JSR LevelEnd_Check ; if ExitLevel then A=1
BEQ BonusLevel_ButtonCheck
End_Demo:
LDA #0
STA ScrBuffer_Pos
RTS
; ───────────────────────────────────────────────────────────────────────────
Button_Pressed: ; CODE XREF: BonusLevel_ButtonCheck+7j
PLA
PLA ; Убираем из стека точку возврата
; (по RTS всё равно выходить не будем),
; но процедура в конце вызывает себя
; рекурсивно - и стек стал бы
; неограниченно заполняться
LDA #0
STA ScrBuffer_Pos
JSR Null_Upper_NT
JMP Title_Loaded
; End of function BonusLevel_ButtonCheck
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Рисует большую кирпичную надпись с рекордом
Draw_Record_HiScore: ; CODE XREF: ROM:C28Cp
JSR Screen_Off
LDA #$1C
STA PPU_Addr_Ptr
LDA #0
STA Scroll_Byte
STA PPU_REG1_Stts
JSR Null_NT_Buffer
LDX #$10
STX Block_X
LDY #$32 ; '2'
STY Block_Y
LDA #>aHiscore ; Выводится в виде кирпичной надписи, если рекорд
STA HighStrPtr_Byte
LDA #<aHiscore ; Выводится в виде кирпичной надписи, если рекорд
STA LowStrPtr_Byte
JSR Draw_BrickStr
JSR Draw_RecordDigit ; Выводит на экран цифру рекорда
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
LDA #0
STA Seconds_Counter
LDA #1
STA Snd_RecordPts1
STA Snd_RecordPts2
STA Snd_RecordPts3
-: ; CODE XREF: Draw_Record_HiScore+4Aj
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA Frame_Counter
AND #3
CLC
ADC #5
STA BkgPal_Number ; Мигание надписи
LDA Snd_RecordPts1
BNE - ; Ждём, пока не закончит играть мелодия рекорда
LDA #0
STA BkgPal_Number
RTS
; End of function Draw_Record_HiScore
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
Draw_RespawnPic: ; CODE XREF: Draw_Drop:-p Draw_Drop+Fp
; Draw_Drop+12p Draw_Drop+15p
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA #3
STA TSA_Pal
LDA #3
SEC
SBC Counter
BPL +
EOR #$FF
CLC
ADC #1
+: ; CODE XREF: Draw_RespawnPic+Cj
STA Temp
LDA #3
SEC
SBC Temp
ASL A
ASL A
CLC
ADC #$A1 ; 'б' ; начало в Pattern Table графики респауна
STA Spr_TileIndex
LDX Block_X
LDY Block_Y
JSR Draw_WholeSpr ; Cбрасывает в спрайтовый буффер спрайт 16х16. (в Х, Y - координаты)
RTS
; End of function Draw_RespawnPic
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Рисует большую кирпичную надпись GameOver
Draw_Brick_GameOver: ; CODE XREF: ROM:Make_GameOverp
JSR Screen_Off
LDA #$1C
STA PPU_Addr_Ptr
LDA #0
STA Scroll_Byte
STA PPU_REG1_Stts
JSR Null_NT_Buffer
LDX #$3C ; '<'
STX Block_X
LDY #$46
STY Block_Y
LDA #>aGame ; Выводится в виде кирпичной надписи на весь экран
STA HighStrPtr_Byte
LDA #<aGame ; Выводится в виде кирпичной надписи на весь экран
STA LowStrPtr_Byte
JSR Draw_BrickStr
LDX #$3C ; '<'
STX Block_X
LDY #$78 ; 'x'
STY Block_Y
LDA #>aOver ; "OVER\xFF"
STA HighStrPtr_Byte
LDA #<aOver ; "OVER\xFF"
STA LowStrPtr_Byte
JSR Draw_BrickStr
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
LDA #0
STA Seconds_Counter
LDA #1
STA Snd_GameOver1
STA Snd_GameOver2
STA Snd_GameOver3
Next_Frame: ; CODE XREF: Draw_Brick_GameOver+57j
JSR NMI_Wait ; Ожидает немаскируемого прерывания
LDA Joypad1_Differ
AND #$C
BNE End_Draw_Brick_GameOver ; Если нажато Select или Start, выходим
LDA Snd_GameOver1
BNE Next_Frame ; Если мелодия закончила играть, выходим
End_Draw_Brick_GameOver: ; CODE XREF: Draw_Brick_GameOver+52j
JSR Screen_Off
JSR Null_NT_Buffer
JSR Store_NT_Buffer_InVRAM ; Сбрасывает на экран содержимое NT_Buffer
JSR Set_PPU
JSR Sound_Stop ; Останавливаем звук, включаем каналы и т.п. (аналогично Load в NSF формате)
RTS
; End of function Draw_Brick_GameOver
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Управление танками игроков во время демо уровня
Demo_AI: ; CODE XREF: BonusLevel_ButtonCheck:DemoLevel_Loopp
LDA #1
STA Counter ; Обрабатываем двух игроков
-: ; CODE XREF: Demo_AI+7Dj
LDX Counter
LDA Bonus_X
BEQ NoBonus ; Bonus_X=0 - бонус выведен за экран
LDA BonusPts_TimeCounter
BNE NoBonus ; Если таймер !=0, бонус взят
; и отображаются очки за него
; Если бонус на экране, в первую очередь забираем его
Take_Bonus:
LDA Bonus_X
STA AI_X_Aim
LDA Bonus_Y
STA AI_Y_Aim
JSR Load_AI_Status
JMP Load_Direction_DemoAI ; 4 направления
; ───────────────────────────────────────────────────────────────────────────
NoBonus: ; CODE XREF: Demo_AI+8j Demo_AI+Cj
LDA Tank_Status+2,X ; Либо бонуса нет,
; либо он уже взят
; Далее производятся проверки танков врагов на жизнеспособность,
; и если они живы, происходит перенацеливание на них
BPL + ; Если <$80, враг умирает
CMP #$E0 ; 'р'
BCS + ; A>$E0 (если больше,
; враг зарождается)
LDA Tank_X+2,X
STA AI_X_Aim
LDA Tank_Y+2,X
STA AI_Y_Aim
JSR Load_AI_Status
JMP Load_Direction_DemoAI ; 4 направления
; ───────────────────────────────────────────────────────────────────────────
+: ; CODE XREF: Demo_AI+1Ej Demo_AI+22j
LDA Tank_Status+4,X
BPL ++ ; Если <$80, враг умирает
CMP #$E0 ; 'р'
BCS ++ ; A>$E0 (если больше,
; враг зарождается)
LDA Tank_X+4,X
STA AI_X_Aim
LDA Tank_Y+4,X
STA AI_Y_Aim
JSR Load_AI_Status
JMP Load_Direction_DemoAI ; 4 направления
; ───────────────────────────────────────────────────────────────────────────
++: ; CODE XREF: Demo_AI+34j Demo_AI+38j
LDA Tank_Status+3,X
BPL EnemiesNotActing ; Если <$80, враг умирает
CMP #$E0 ; 'р'
BCS EnemiesNotActing ; A>$E0 (если больше,
; враг зарождается)
LDA Tank_X+3,X
STA AI_X_Aim
LDA Tank_Y+3,X
STA AI_Y_Aim
JSR Load_AI_Status
JMP Load_Direction_DemoAI ; 4 направления
; ───────────────────────────────────────────────────────────────────────────
EnemiesNotActing: ; CODE XREF: Demo_AI+4Aj Demo_AI+4Ej
LDA #0 ; Если танков нет, ничего не делаем
JMP SaveButton_DemoAI
; ───────────────────────────────────────────────────────────────────────────
Load_Direction_DemoAI: ; CODE XREF: Demo_AI+19j Demo_AI+2Fj
; Demo_AI+45j Demo_AI+5Bj
AND #3 ; 4 направления
TAY
LDA Tank_Direction,Y ; Направление танков в демо-уровне (в формате порта джойстика)
SaveButton_DemoAI: ; CODE XREF: Demo_AI+60j
LDX Counter
STA Joypad1_Buttons,X
STA Joypad1_Differ,X
LDA Tank_Y,X
CMP #$C8 ; '╚'
BCC Next_Demo_AI
LDA Joypad1_Differ,X
AND #$F0 ; 'Ё'
STA Joypad1_Differ,X
Next_Demo_AI: ; CODE XREF: Demo_AI+73j
DEC Counter
BPL -
RTS
; End of function Demo_AI
; ───────────────────────────────────────────────────────────────────────────
Tank_Direction: .BYTE $13,$43,$23,$83 ; DATA XREF: Demo_AI+66r
; Направление танков в демо-уровне (в формате порта джойстика)
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Рисует TSA блок под танком
Draw_TSA_On_Tank: ; CODE XREF: ROM:Construct_Draw_TSAp
LDA TSA_BlockNumber
AND #$F
LDX Tank_X
LDY Tank_Y
JSR Draw_TSABlock
RTS
; End of function Draw_TSA_On_Tank
; ███████████████ S U B R O U T I N E ███████████████████████████████████████
; Двигает танк в зависимости от нажатых кнопок
Move_Tank: ; CODE XREF: ROM:C0EDp
LDA Joypad1_Buttons
AND #$F0 ; 'Ё' ; Проверка на нажатые клавиши управления
BEQ ArrowNotPressed
INC byte_7B