-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtype_invaders.asm
More file actions
1390 lines (1217 loc) · 30.6 KB
/
Copy pathtype_invaders.asm
File metadata and controls
1390 lines (1217 loc) · 30.6 KB
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
name "TypingInvaders"
org 100h
jmp start_program
; --- DATA SECTION ---
; This section stores all global variables and constants used by the game.
; FILE I/O
; Variables for handling the high score file.
filename db "HISCORE.TXT", 0 ; Name of the file to store scores
file_handle dw 0 ; Buffer to store the file handle after opening
; Default leaderboard values if the file doesn't exist.
default_data db "CPU 00000", "CPU 00000", "CPU 00000"
lb_buffer db 30 dup(' ') ; Buffer to read/write the top 3 scores (27 bytes + padding)
temp_entry db " " ; Temporary buffer to construct a new score entry
; PLAYER DATA
; Variables related to the player's current state and input.
current_name db " ", 0 ; Buffer for the player's 3-letter name
char_x db 40 ; X-position (column) of the falling letter
char_y db 2 ; Y-position (row) of the falling letter
current_char db 'A' ; The ASCII character currently falling
current_color db 0Eh ; Color attribute of the falling letter (Yellow default)
; STATS
; Game statistics and configuration.
score dw 0 ; Current player score
lives db 3 ; Number of lives remaining
fall_speed dw 15 ; Speed of falling letters (lower = faster)
tick_count dw 0 ; Counter to control game timing
game_active db 1 ; Flag: 1 = Game running, 0 = Game Over
has_nuke db 1 ; Flag: 1 = Player has a screen-clearing nuke
level db 1 ; Current difficulty level
ground_color db 02h ; Color of the ground line
; MECHANICS
; Variables for game mechanics and bonuses.
floor_y db 24 ; Y-position of the ground (game over line)
streak dw 0 ; Consecutive correct hits
is_combo db 0 ; Flag: 1 = Combo active (double points)
has_shield db 0 ; Flag: 1 = Shield active (protects from one hit)
is_armored db 0 ; Flag: 1 = Current enemy takes 2 hits
freeze_timer dw 0 ; Timer for the "Freeze" power-up effect
; UI MESSAGES
; Strings used for displaying text on the screen.
msg_title db "=== TYPING INVADERS v28 ===$"
msg_instr db "Type letters! L for Top 3 Ranks.$"
msg_start db "Press ENTER to Start$"
msg_enter_name db "ENTER NAME (3 CHARS): $"
msg_leader db "=== TOP 3 LEADERBOARD ===$"
msg_rank1 db "1. $"
msg_rank2 db "2. $"
msg_rank3 db "3. $"
msg_back db "Press ESC to Return$"
msg_gameover db "GAME OVER! Final Score: $"
msg_newrec db " YOU MADE THE LEADERBOARD!$"
msg_restart db " Press R to Restart or ESC to Exit.$"
msg_paused db "PAUSED$"
msg_clear db " $"
newline db 13, 10, "$"
; VRAM STRINGS
; Strings written directly to Video Memory (0B800h).
v_score db "SCORE:", 0
v_best db "BEST:", 0
v_lvl db "LVL:", 0
v_lives db "LIVES:", 0
v_nuke db "[NUKE] ", 0
v_shield db "[SHIELD]", 0
v_freeze db "[FREEZE]", 0
v_combo db "COMBO 2x", 0
v_blank db " ", 0
initial_tick dw 0
; MATRIX RAIN DATA
; Used for the intro animation effect.
matrix_cols db 80 dup(0) ; Array tracking rain drop position for each column (0=inactive)
rnd_seed dw 1234h ; Seed for the pseudo-random number generator
; --- CODE SECTION ---
start_program:
; Main entry point. Initializes system and launches the menu.
call check_and_repair_file ; Ensure high score file exists
call load_leaderboard ; Load high scores into memory
call matrix_intro ; Play the "Matrix" intro animation
jmp main_menu_init ; Jump to the main menu
; 1. MENU
; Handles drawing the menu and waiting for user input.
main_menu_init:
mov ax, 0003h ; Set Video Mode 03h (80x25 Text Mode, Clears Screen)
int 10h
mov ah, 01h ; Hide the text cursor
mov ch, 20h
int 10h
draw_menu:
mov bh, 0 ; Ensure we are writing to Video Page 0
; Draw Title
mov ah, 02h ; Set Cursor Position
mov dh, 6 ; Row
mov dl, 28 ; Column
int 10h
mov dx, offset msg_title ; Print String
mov ah, 09h
int 21h
; Draw Instructions
mov ah, 02h
mov dh, 8
mov dl, 24
int 10h
mov dx, offset msg_instr
mov ah, 09h
int 21h
; Draw Start Prompt
mov ah, 02h
mov dh, 14
mov dl, 30
int 10h
mov dx, offset msg_start
mov ah, 09h
int 21h
wait_start_key:
; Wait for key press in the menu.
mov ah, 00h
int 16h
cmp al, 13 ; Check for ENTER key (ASCII 13)
je get_name_screen
cmp al, 'l' ; Check for 'L' (Leaderboard)
je show_leaderboard
cmp al, 'L'
je show_leaderboard
cmp al, 27 ; Check for ESC (Exit)
je exit_game
jmp wait_start_key
get_name_screen:
; Screen to input player initials.
mov ax, 0003h ; Clear screen
int 10h
mov ah, 02h ; Position cursor
mov dh, 10
mov dl, 25
int 10h
mov dx, offset msg_enter_name
mov ah, 09h
int 21h
; Position cursor for input
mov ah, 02h
mov dh, 10
mov dl, 48
int 10h
; Loop to get 3 characters
mov cx, 3
mov di, offset current_name
name_input_loop:
mov ah, 01h ; Get char from stdin with echo
int 21h
mov [di], al ; Store char in buffer
inc di
loop name_input_loop
jmp start_game_init
show_leaderboard:
; Displays the Top 3 scores from the buffer.
mov ax, 0003h
int 10h
mov bh, 0
; Display Header
mov ah, 02h
mov dh, 5
mov dl, 28
int 10h
mov dx, offset msg_leader
mov ah, 09h
int 21h
; -- PRINT RANK 1 --
mov ah, 02h
mov dh, 8
mov dl, 30
int 10h
mov dx, offset msg_rank1
mov ah, 09h
int 21h
mov si, offset lb_buffer ; Point to start of buffer
call print_entry_9bytes ; Print first entry
; -- PRINT RANK 2 --
mov ah, 02h
mov dh, 10
mov dl, 30
int 10h
mov dx, offset msg_rank2
mov ah, 09h
int 21h
mov si, offset lb_buffer
add si, 9 ; Move pointer 9 bytes forward
call print_entry_9bytes
; -- PRINT RANK 3 --
mov ah, 02h
mov dh, 12
mov dl, 30
int 10h
mov dx, offset msg_rank3
mov ah, 09h
int 21h
mov si, offset lb_buffer
add si, 18 ; Move pointer 18 bytes forward
call print_entry_9bytes
; Back prompt
mov ah, 02h
mov dh, 16
mov dl, 30
int 10h
mov dx, offset msg_back
mov ah, 09h
int 21h
wait_lead_key:
mov ah, 00h
int 16h
cmp al, 27 ; ESC
je main_menu_init
jmp wait_lead_key
start_game_init:
; Initialize all game variables for a new run.
mov ax, 0003h
int 10h
mov [score], 0
mov [lives], 3
mov [fall_speed], 15
mov [game_active], 1
mov [has_nuke], 1
mov [level], 1
mov [ground_color], 02h
mov [floor_y], 24
mov [streak], 0
mov [is_combo], 0
mov [has_shield], 0
mov [freeze_timer], 0
mov [is_armored], 0
call draw_ground
call draw_static_ui_vram
call spawn_new_letter
game_loop:
; The core game loop.
call update_ui_vram ; Draw UI elements
mov ah, 01h ; Check if key is pressed (non-blocking)
int 16h
jz no_key_press ; If no key, skip to physics
mov ah, 00h ; Get the key
int 16h
; Global Keys
cmp al, 27 ; ESC -> Main Menu
je main_menu_init
cmp al, 32 ; SPACE -> Pause
je toggle_pause
cmp al, 9 ; TAB -> Use Nuke
je trigger_nuke
; Input matching logic
push ax
and al, 11011111b ; Convert to Upper Case (mask bit 5)
cmp al, [current_char] ; Compare with enemy letter
je correct_key
; Incorrect Key
mov [streak], 0 ; Reset streak
mov [is_combo], 0
jmp ignore_key_pop
correct_key:
pop ax
call letter_caught ; Handle successful hit
jmp no_key_press
ignore_key_pop:
pop ax
jmp no_key_press
no_key_press:
; Delay loop for timing control
mov cx, 0
mov dx, 02000h
mov ah, 86h
int 15h
; Check freeze timer
cmp [freeze_timer], 0
jle update_physics
dec [freeze_timer]
jmp game_loop ; Skip physics if frozen
update_physics:
; Controls how often the letter moves down.
inc [tick_count]
mov ax, [tick_count]
cmp ax, [fall_speed]
jl game_loop ; Not time to move yet
mov [tick_count], 0
call move_letter_down ; Move letter
cmp [game_active], 0 ; Check if game ended
je game_over_screen
jmp game_loop
trigger_nuke:
; Uses the screen-clearing bomb if available.
cmp [has_nuke], 1
jne no_key_press
mov [has_nuke], 0
; Flash Screen White
mov ax, 0600h
mov bh, 70h
mov cx, 0000h
mov dx, 184Fh
int 10h
; Delay
mov cx, 0
mov dx, 04000h
mov ah, 86h
int 15h
; Reset Screen
mov ax, 0600h
mov bh, 07h
mov cx, 0000h
mov dx, 184Fh
int 10h
call draw_ground
call draw_static_ui_vram
call spawn_new_letter
jmp game_loop
toggle_pause:
; Pauses the game loop until space is pressed again.
mov ah, 02h
mov dh, 12
mov dl, 35
int 10h
mov dx, offset msg_paused
mov ah, 09h
int 21h
pause_wait:
mov ah, 00h
int 16h
cmp al, 32 ; Check for SPACE
je clear_pause_msg
jmp pause_wait
clear_pause_msg:
; Restore screen after pause
mov ah, 02h
mov dh, 12
mov dl, 35
int 10h
mov dx, offset msg_clear
mov ah, 09h
int 21h
call draw_char
call draw_static_ui_vram
jmp game_loop
; --- LEADERBOARD LOGIC (TOP 3 SORTING) ---
check_and_repair_file proc
; Ensures the high score file exists. If not, creates it.
mov ah, 3Dh
mov al, 0
mov dx, offset filename
int 21h
jc create_new_file ; If open fails (Carry Flag set), create file
; Check file size/integrity
mov [file_handle], ax
mov ah, 3Fh
mov bx, [file_handle]
mov cx, 27
mov dx, offset lb_buffer
int 21h
push ax ; Save bytes read count
mov ah, 3Eh ; Close file
mov bx, [file_handle]
int 21h
pop ax
cmp ax, 27 ; If bytes read < 27, file is corrupt
jl create_new_file
ret
create_new_file:
; Creates a new file with default data.
mov ah, 3Ch
mov cx, 0
mov dx, offset filename
int 21h
mov [file_handle], ax
; Write default scores
mov ah, 40h
mov bx, [file_handle]
mov cx, 27
mov dx, offset default_data
int 21h
mov ah, 3Eh ; Close file
mov bx, [file_handle]
int 21h
ret
check_and_repair_file endp
load_leaderboard proc
; Reads the file content into lb_buffer.
mov ah, 3Dh
mov al, 0
mov dx, offset filename
int 21h
mov [file_handle], ax
mov ah, 3Fh
mov bx, [file_handle]
mov cx, 27
mov dx, offset lb_buffer
int 21h
mov ah, 3Eh
mov bx, [file_handle]
int 21h
ret
load_leaderboard endp
update_leaderboard proc
; Handles sorting and saving new high scores.
push ds
pop es ; Make ES point to Data Segment (required for string operations)
; 1. Prepare current entry string (Name + Score) in temp_entry
mov si, offset temp_entry
mov di, offset current_name
; Copy Name
mov al, [di]
mov [si], al
mov al, [di+1]
mov [si+1], al
mov al, [di+2]
mov [si+2], al
mov byte ptr [si+3], ' '
; Convert Score to String and append
mov ax, [score]
add si, 4
call int_to_string_5
; 2. Comparison Logic (Bubble Sort Insertion)
; Check against Rank 1
mov si, offset lb_buffer
add si, 4 ; Point to score part
call string_to_int ; Convert stored score string to integer in AX
cmp [score], ax
jg insert_rank_1 ; If current > rank 1, insert
; Check against Rank 2
mov si, offset lb_buffer
add si, 13 ; Offset for Rank 2 score
call string_to_int
cmp [score], ax
jg insert_rank_2
; Check against Rank 3
mov si, offset lb_buffer
add si, 22 ; Offset for Rank 3 score
call string_to_int
cmp [score], ax
jg insert_rank_3
jmp save_lb_to_file ; If no high score, save anyway to be safe
insert_rank_1:
call copy_entry_2_to_3 ; Shift 2 -> 3
call copy_entry_1_to_2 ; Shift 1 -> 2
mov di, offset lb_buffer
call write_temp_to_di ; Insert new score at 1
jmp save_lb_to_file
insert_rank_2:
call copy_entry_2_to_3 ; Shift 2 -> 3
mov di, offset lb_buffer
add di, 9
call write_temp_to_di ; Insert new score at 2
jmp save_lb_to_file
insert_rank_3:
mov di, offset lb_buffer
add di, 18
call write_temp_to_di ; Insert new score at 3
jmp save_lb_to_file
save_lb_to_file:
; Writes the modified buffer back to disk.
mov ah, 3Ch
mov cx, 0
mov dx, offset filename
int 21h
mov [file_handle], ax
mov ah, 40h
mov bx, [file_handle]
mov cx, 27
mov dx, offset lb_buffer
int 21h
mov ah, 3Eh
mov bx, [file_handle]
int 21h
ret
update_leaderboard endp
; MEMORY HELPERS
; Low-level buffer manipulation routines.
copy_entry_2_to_3 proc
mov si, offset lb_buffer
add si, 9 ; Source: Rank 2
mov di, offset lb_buffer
add di, 18 ; Dest: Rank 3
mov cx, 9
rep movsb
ret
copy_entry_2_to_3 endp
matrix_intro proc
; "Digital Rain" intro effect.
; Set Text Mode (Clear Screen)
mov ax, 0003h
int 10h
; Hide Cursor
mov ah, 01h
mov cx, 2607h
int 10h
matrix_loop:
; 1. Check for Key Press (Exit loop if pressed)
mov ah, 01h
int 16h
jnz matrix_exit_cleanup
; 2. Randomly spawn new drops
call get_random
and ax, 7Fh ; Keep result 0-127
cmp ax, 80
jge skip_spawn ; If > 79, ignore (screen width is 80)
mov si, ax
cmp byte ptr [matrix_cols + si], 0
jne skip_spawn ; If column busy, ignore
mov byte ptr [matrix_cols + si], 1 ; Start drop at row 1
skip_spawn:
; 3. Update all 80 columns
mov cx, 80
mov si, 0
mov ax, 0B800h ; Point ES to Video Memory
mov es, ax
col_loop:
mov al, [matrix_cols + si] ; Get Y position for this column
cmp al, 0
je next_col ; If 0, inactive
; --- ERASE TAIL (Y - 15) ---
cmp al, 15
jl draw_head
push ax
sub al, 15 ; Calculate tail end position
call get_mat_offset ; DI = VRAM offset
mov word ptr es:[di], 0720h ; Draw Black Space (erase)
pop ax
draw_head:
; --- DRAW HEAD (White Character) ---
cmp al, 25
jge reset_col ; If off screen bottom, reset column
call get_mat_offset ; DI = current Y offset
push ax
call get_random ; Get random char
and al, 01111111b ; ASCII range mask
add al, 33 ; Ensure readable char
mov ah, 0Fh ; White color (Head)
mov es:[di], ax ; Write char to video memory
pop ax
; --- DRAW TRAIL (Green Character) ---
dec al ; Go to previous row (Y-1)
cmp al, 0
jl update_y ; If off top of screen, skip
call get_mat_offset
; Keep the character that is already there, just change color
mov bl, es:[di] ; Read char
mov bh, 02h ; Dark Green color
mov es:[di], bx ; Write back
update_y:
; Increment Y position in array
inc byte ptr [matrix_cols + si]
jmp next_col
reset_col:
mov byte ptr [matrix_cols + si], 0
next_col:
inc si
loop col_loop
; 4. Delay (Control Speed)
mov cx, 0
mov dx, 4000h ; Speed control
mov ah, 86h
int 15h
jmp matrix_loop
matrix_exit_cleanup:
; Consume the key press to clear buffer
mov ah, 00h
int 16h
ret
; Helper: Calculates VRAM offset for Matrix
get_mat_offset:
push ax
push bx
mov bl, 160 ; 80 columns * 2 bytes/char
mul bl
mov di, ax ; Row offset
mov ax, si
shl ax, 1 ; Column offset (X * 2)
add di, ax ; Total offset
pop bx
pop ax
ret
; Helper: Simple Pseudo-Random Generator (Linear Congruential)
get_random:
push dx
mov ax, [rnd_seed]
mov dx, 351
mul dx
add ax, 45
mov [rnd_seed], ax
pop dx
ret
matrix_intro endp
copy_entry_1_to_2 proc
mov si, offset lb_buffer
; Source: Rank 1 (0)
mov di, offset lb_buffer
add di, 9 ; Dest: Rank 2
mov cx, 9
rep movsb
ret
copy_entry_1_to_2 endp
write_temp_to_di proc
; Copies the constructed score string to the destination in buffer.
mov si, offset temp_entry
mov cx, 9
rep movsb
ret
write_temp_to_di endp
print_entry_9bytes proc
; Prints 9 characters starting at SI to screen.
mov cx, 9
print_9_loop:
mov dl, [si]
mov ah, 02h
int 21h
inc si
loop print_9_loop
ret
print_entry_9bytes endp
string_to_int proc
; Converts a 5-digit ASCII string at SI into an integer in AX.
mov cx, 5
mov ax, 0
mov bx, 0
sti_loop:
mov bl, [si]
sub bl, '0' ; ASCII to digit
mov dx, 10
mul dx ; Multiply current total by 10
add ax, bx ; Add new digit
inc si
loop sti_loop
ret
string_to_int endp
int_to_string_5 proc
; Converts integer in AX to 5-digit ASCII string at SI (backwards).
add si, 4
mov cx, 5
mov bx, 10
its_loop:
mov dx, 0
div bx ; Divide by 10
add dl, '0' ; Remainder + '0' = ASCII digit
mov [si], dl
dec si
loop its_loop
ret
int_to_string_5 endp
; --- GAME LOGIC ---
letter_caught proc
; Called when player types correct letter.
cmp [is_armored], 1 ; Armored enemies need 2 hits
jne normal_hit
mov [is_armored], 0 ; Remove armor
mov [current_color], 0Eh
call sound_clank
call draw_char
inc [score]
inc [streak]
cmp [streak], 5 ; Combo threshold
jl armor_ret
mov [is_combo], 1
armor_ret:
ret
normal_hit:
call sound_beep
cmp [current_color], 02h ; Check for Toxic (Green) enemy
je caught_toxic
; Draw Explosion
mov ax, 0B800h
mov es, ax
call get_video_offset
mov al, '*'
mov ah, 0Ch
mov es:[di], ax
mov cx, 0
mov dx, 04000h
mov ah, 86h
int 15h
call erase_char
; Apply power-up logic based on color
cmp [current_color], 03h ; Freeze
jne check_shield_hit
mov [freeze_timer], 60
call sound_beep
jmp regular_score
check_shield_hit:
cmp [current_color], 0Fh ; Shield
jne check_streak
mov [has_shield], 1
call sound_beep
jmp regular_score
check_streak:
inc [streak]
cmp [streak], 5
jl check_healer
mov [is_combo], 1
check_healer:
cmp [current_color], 0Ch ; Healer (Red)
jne check_ice
cmp [lives], 3
jge regular_score
inc [lives]
call sound_beep
jmp regular_score
check_ice:
cmp [current_color], 0Bh ; Ice (Slows game)
jne regular_score
mov [fall_speed], 15
call sound_beep
; Flash Screen Blue
mov ax, 0600h
mov bh, 30h
mov cx, 0000h
mov dx, 184Fh
int 10h
mov cx, 0
mov dx, 02000h
mov ah, 86h
int 15h
mov ax, 0600h
mov bh, 07h
mov cx, 0000h
mov dx, 184Fh
int 10h
call draw_ground
call draw_static_ui_vram
regular_score:
inc [score]
cmp [is_combo], 1
jne no_bonus
inc [score] ; Double points for combo
no_bonus:
call sound_beep
jmp update_stats
caught_toxic:
; Toxic enemies hurt you if you catch them!
cmp [has_shield], 1
jne toxic_damage
mov [has_shield], 0 ; Shield absorbs hit
call sound_beep_bad
mov [streak], 0
mov [is_combo], 0
call erase_char
call spawn_new_letter
ret
toxic_damage:
call screen_shake_damage
call sound_beep_bad
dec [lives]
mov [streak], 0
mov [is_combo], 0
cmp [lives], 0
je game_over_jump
call erase_char
call spawn_new_letter
ret
game_over_jump:
mov [game_active], 0
ret
update_stats:
; Handles Level Up logic based on score thresholds.
mov ax, [score]
check_speed:
cmp [score], 40
jge try_lvl_5
cmp [score], 30
jge try_lvl_4
cmp [score], 20
jge try_lvl_3
cmp [score], 10
jge try_lvl_2
jmp finish_caught
try_lvl_2:
cmp [level], 1
jne finish_caught
mov [level], 2
mov [fall_speed], 10 ; Increase speed
mov [ground_color], 04h ; Change floor color
call apply_level_change
jmp finish_caught
try_lvl_3:
cmp [level], 2
jne finish_caught
mov [level], 3
mov [fall_speed], 6
mov [ground_color], 03h
call apply_level_change
jmp finish_caught
try_lvl_4:
cmp [level], 3
jne finish_caught
mov [level], 4
mov [fall_speed], 3
mov [ground_color], 05h
call apply_level_change
jmp finish_caught
try_lvl_5:
cmp [level], 4
jne finish_caught
mov [level], 5
mov [fall_speed], 2
mov [ground_color], 06h
call apply_level_change
jmp finish_caught
finish_caught:
call spawn_new_letter
ret
letter_caught endp
apply_level_change proc
; Visual effect for leveling up.
call sound_beep
mov ax, 0600h
mov bh, 07h
mov cx, 0000h
mov dx, 184Fh
int 10h
cmp [floor_y], 15
jle redraw_floor
dec [floor_y] ; Move floor up (increases difficulty)
redraw_floor:
call draw_ground
call draw_static_ui_vram
cmp [lives], 3
jge no_heal_lvl
inc [lives] ; Heal on level up
no_heal_lvl:
ret
apply_level_change endp
move_letter_down proc
; Handles physics update for the falling letter.
call erase_char
; Wind Effect (Randomly move X)
push ax
push dx
mov ah, 2Ch ; Get system time
int 21h
test dl, 1
jz no_wind
test dl, 2
jz wind_left
wind_right:
cmp [char_x], 78
jge no_wind
inc [char_x]
jmp no_wind
wind_left:
cmp [char_x], 1
jle no_wind
dec [char_x]
no_wind:
pop dx
pop ax
inc [char_y] ; Move down
mov al, [floor_y]
cmp [char_y], al
jge hit_floor
call draw_char
ret
hit_floor:
; Letter hit the ground logic.
cmp [current_color], 02h ; Toxic enemies hitting floor is safe
je safe_despawn
cmp [has_shield], 1
jne floor_damage
mov [has_shield], 0
call sound_beep_bad
mov [streak], 0
mov [is_combo], 0
jmp safe_despawn
floor_damage:
call screen_shake_damage
call sound_beep_bad
dec [lives]
mov [streak], 0
mov [is_combo], 0