-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwordlos.asm
813 lines (670 loc) · 22.5 KB
/
wordlos.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
%define SCORE_POSITION 2620
%define SCORE_VALUE_POSITION 2634
%define KEYBOARD_ROW_POSITION1 2772 + 160 + 160
%define KEYBOARD_ROW_POSITION2 KEYBOARD_ROW_POSITION1 + 322
%define KEYBOARD_ROW_POSITION3 KEYBOARD_ROW_POSITION2 + 326
%define MESSAGE_POSITION 432
%define MESSAGE_COLOR_ERROR 0x04
%define MESSAGE_COLOR_SUCCESS 0x02
%define STATE_COLOR_EMPTY 0x78
%define STATE_COLOR_NOTINWORD 0x87
%define STATE_COLOR_INWORD 0xE7
%define STATE_COLOR_CORRECT 0x2F
%define KEYBOARD_COLOR_EMPTY 0x0F
%define KEYBOARD_COLOR_NOTINWORD 0x08
%define KEYBOARD_COLOR_INWORD 0x0E
%define KEYBOARD_COLOR_CORRECT 0x02
org 0x0100
; Set 80-25 text mode
mov ax, 0x0002
int 0x10
; disable blinking chars (so we get all 16 background colors)
mov ax, 0x1003
mov bx, 0
int 10h
mov ax, 0xb800 ; Segment for the video data
mov es, ax
cld
;;; GAME FLOW
start:
; Game title
mov ah, 0x0F
mov bp, c_title_string
mov cx, 72
call print_string
start_game:
; 1) reset board
mov bp, game_words
mov cx, 30 ; 6 words with 5 characters
_reset_board:
mov byte [bp], ' '
inc bp
loop _reset_board
; 2) reset letter status
mov bp, game_words_state
mov cx, 30 ; 6 words with 5 characters
_reset_board_state:
mov byte [bp], STATE_COLOR_EMPTY
inc bp
loop _reset_board_state
; 3) reset state
mov al, 0
mov byte [game_state_letter], al
mov byte [game_state_word], al
; 4) reset keyboard states
mov bp, game_keyboard_state
mov cx, 26
_reset_keyboard:
mov byte [bp], KEYBOARD_COLOR_EMPTY
inc bp
loop _reset_keyboard
; 5) randomize a word from the list
mov ah, 0x00 ; BIOS service to get system time
int 0x1a ; AX contains the value
mov bx, word [common_count] ; get the amount of words
mov ax, dx ; Copies the time fetched by interruption
xor dx, dx ; Resets DX because DIV will use DXAX
div bx ; AX = (DXAX) / bx ; DX = remainder
mov ax, dx ; moves the current word index to AX
mov bx, 5
mul bx
add ax, common_word_list
mov [game_selected_word], ax
; 6) copy selected word to the temp variable
main_loop:
call draw_board
call draw_keyboard
; clear message
mov bp, c_message_empty
mov ah, 0x08
mov cx, MESSAGE_POSITION
call print_string
; print score
mov ah, 0x08
mov bp, c_game_score
mov cx, SCORE_POSITION
call print_string
mov ax, [game_score]
mov di, SCORE_VALUE_POSITION
mov byte [general_value], 0x0F
call print_number
; Setting the cursor to the right position
mov cx, [game_state_letter] ; get current state (word:letter)
mov al, 4
mul cl
add al, 31
mov dl, al ; set current column
mov al, 2
mul ch
add al, 4
mov dh, al ; set current line
mov ah, 02h ;Set cursor position function
mov bh, 0 ;Page number
int 10h ;Interrupt call
check_input:
mov ah, 0 ; get keystroke
int 0x16 ; bios service to get input
cmp al, 0x08 ; 0x08 - backspace
je del_letter
cmp al, 0x0d ; 0x0d - Enter
je confirm_word ; for now, just loop
cmp al, 0x1b ; escape key
je exit
; Check if it's within the character range and check case
; A-Z: 0x41-0x5A
; a-z: 0x61-0x7A
cmp al, 0x41
jl check_input ; less than `A`
cmp al, 0x7a
jg check_input ; greater than `z`
cmp al, 0x61
jge add_letter ; it means it's already in range a-z
cmp al, 0x5a
jle lower_add_letter ; it's within A-Z, needs lower case
jmp check_input
lower_add_letter:
add al, 0x20 ; makes it lower case
add_letter:
mov cl, byte [game_state_letter]
cmp cl, 5
je main_loop
push ax
mov ax, [game_state_letter] ; copies the letter and the word
mov byte [game_w], ah
mov byte [game_l], al
xor ax, ax ; resetting AX
mov al, 5 ; 5 letter per word
mov bl, byte [game_w] ; get current word
mul bl ; multiply by the amount of words
add al, byte [game_l] ; adding the current letter
mov bx, game_words ; getting pointer to word list
add ax, bx ; adding pointer to offset
mov bp, ax ; setting to bp
pop ax
mov byte [bp], al
mov al, byte [game_l]
inc al
mov ah, byte [game_w]
mov byte [game_state_letter], al
mov byte [game_state_word], ah
jmp main_loop
del_letter:
mov al, byte [game_state_letter]
cmp al, 0 ; if it's already the first letter, skip
je main_loop
mov ax, [game_state_letter]
mov byte [game_w], ah
mov byte [game_l], al
xor ax, ax ; resetting AX
mov al, 5 ; 5 letter per word
mov bl, byte [game_w] ; get current word
mul bl ; multiply by the amount of words
add al, byte [game_l] ; adding the current letter
mov bx, game_words ; getting pointer to word list
add ax, bx ; adding pointer to offset
dec ax
mov bp, ax ; setting to bp
mov byte [bp], 0x20 ; setting space, "empty letter"
mov al, byte [game_state_letter]
dec al ; go back to the previous position
mov byte [game_state_letter], al
jmp main_loop
confirm_word:
mov al, byte [game_state_letter]
cmp al, 5 ; comparing if it's in the last letter
jne check_input
; 1) compare if it's in the word list
call check_valid_word
cmp ah, 0 ; if ah == 0, then word is valid
jne error_not_in_dictionary
; 2) compare with the selected word and set state
call update_word_state
cmp ah, 1 ; if ah == 1, then player found word
je win_word
; 4) check current game status
mov al, byte [game_state_word]
cmp al, 5 ; comparing if it's in the last word
je lost_word
; 3) increment word
mov al, byte [game_state_word]
inc al
mov byte [game_state_word], al
mov byte [game_state_letter], 0
jmp main_loop
error_not_in_dictionary:
mov bp, c_message_invalid
mov ah, MESSAGE_COLOR_ERROR
call message_state
jmp main_loop
win_word:
call draw_board
call draw_keyboard
; add score
xor ah, ah
mov al, byte [game_state_word] ; get current word level
shl ax, 1
add ax, c_score_board
mov bx, ax ; get address of current score info
mov ax, [game_score]
add ax, [bx]
mov [game_score], ax
; print score
mov di, SCORE_VALUE_POSITION
mov byte [general_value], 0x0F
call print_number
; show current score message
xor ah, ah
mov al, byte [game_state_word] ; get current word level
mov bx, 24 ; 24 chars/bytes per message
mul bx ; multiply the amount of chars by the current level to get right message
add ax, c_message_win ; add the address of the messages
mov bp, ax
mov ah, MESSAGE_COLOR_SUCCESS
call message_state
jmp start_game
lost_word:
call draw_board
call draw_keyboard
mov bp, [game_selected_word]
mov ah, MESSAGE_COLOR_SUCCESS
mov cx, MESSAGE_POSITION + 36
mov bx, 5
call print_string_fixed
mov bp, c_message_lost
mov ah, MESSAGE_COLOR_ERROR
call message_state
jmp start_game
exit:
int 0x20 ; exit
;;; GAME FUNCTIONS
;
; Message state
; This will show a message, then wait for input
; Params: BP - string addr
; AH - message color
;
message_state:
; 1) print message
mov cx, MESSAGE_POSITION
call print_string
; 2) wait for input
mov ah, 0 ; get keystroke
int 0x16 ; bios service to get input
ret
;
; Draws the keyboard with the current state for every letter
;
draw_keyboard:
mov ah, 0
mov al, 10
mov bx, KEYBOARD_ROW_POSITION1
call draw_keyboard_row
mov ah, 10
mov al, 19
mov bx, KEYBOARD_ROW_POSITION2
call draw_keyboard_row
mov ah, 19
mov al, 26
mov bx, KEYBOARD_ROW_POSITION3
call draw_keyboard_row
ret
;
; Draws one row of the keyboard
; Params: AH - range start
; AL - range end
; BX - position
draw_keyboard_row:
mov di, bx ; set the screen position
mov cx, ax ; copy range to CX to do the operations
sub cl, ch ; CL contains the size of the range
xor ch, ch ; now CX should the loop value
mov al, ah ; bring the range start AX
xor ah, ah
mov bp, c_keyboard_rows ; get the address of the string
add bp, ax ; add the char offset
mov bx, game_keyboard_state ; keyboard state
add bx, ax
_dkr_print:
mov ah, byte [bx]
mov al, byte [bp]
stosw
inc bp
inc bx
; add some spaces
mov al, ' '
stosw
mov al, ' '
stosw
loop _dkr_print
ret
; Draws the board with the current game state
; go word by word and print the data
;
draw_board:
mov cx, 6 ; 6 words
_print_word:
call print_word
loop _print_word
ret
;
; Print one word
; Params: cx - current word
;
print_word:
mov bx, cx ; save current word
push cx
mov cx, 5 ; 5 letters
_print_letter:
call print_letter
loop _print_letter
pop cx
ret
;
; Prints one letter
; Params: cx - current letter
; bx - current word
;
print_letter:
mov byte [game_l], cl
mov byte [game_w], bl
push cx ; draw_box function will change CX and BX, so we keep it
push bx
; pointer to the letter in board
; used for both letter data and state
push bx
xor ax, ax ; resetting AX
mov al, 5 ; 5 letter per word
mov bl, byte [game_w] ; get current word
dec bl ; bl -= 1
mul bl ; multiply by the amount of words
add al, byte [game_l] ; adding the current letter
dec al ; al -= 1
mov [game_letter_ptr], ax ; saving it to the pointer variable
mov bx, game_words_state ; getting pointer to the word/letters state
add ax, bx ; adding pointer to offset
mov bp, ax ; setting bp to the pointer
xor ax, ax ; resetting ax
mov ah, byte [bp] ; getting the state data
mov byte [game_letter_selected_color], ah
pop bx
push ax ; pushing the state as a color to the box function
push 0x0103 ; box dimensions
mov ax, 8
mul cx
add ax, 52
push ax
mov [game_pos], ax ; saving current column to be used later
mov ax, 160 * 2
mul bx
add ax, 160 * 2
push ax ; vertical position
add ax, [game_pos] ; adding column to line to use later
add ax, 2 ; ONE character offset, middle of the box
mov [game_pos], ax ; saving current cursor position
call draw_box
add sp, 8 ; returns the stack pointer, same as pop 4 times
; Print current letter
mov ax, [game_letter_ptr]
mov bx, game_words ; getting pointer to word list
add ax, bx ; adding pointer to offset
mov bp, ax ; setting to bp
mov ah, byte [game_letter_selected_color] ; setting the current state color
mov al, byte [bp] ; copying the character on the table to AL
sub al, 0x20
mov di, [game_pos] ; adding the cursor position offset to DI
mov [es:di], ax ; setting the current char in AX to video memory
pop bx
pop cx
ret
;
; Check if the input word is in the list of words
; Return: AH - 0 if word is valid
;
check_valid_word:
mov cx, [word_count] ; copy the amount of words
_check_valid_word_init:
; 1) get pointer to the current word
xor ax, ax ; resetting AX
mov al, 5 ; 5 letter per word
mov bl, byte [game_state_word] ; get current word
mul bl ; multiply by the amount of words
add ax, game_words ; ; adding the offset to the address
mov [general_ptr1], ax ; saving it to the pointer variable
; 2) get pointer to current word in list
mov ax, 5 ; 5 letter per word
mov bx, cx
dec bx
mul bx ; multiply by the amount of words
add ax, word_list ; adding the offset to the address
mov [general_ptr2], ax ; saving it to the pointer variable
; 3) in order to compare letter by letter, you must
push cx
mov cx, 5 ; 5 letters
_check_equal_letter:
mov ax, [general_ptr1] ; copy address of the first pointer
add ax, cx ; adding current letter offset
dec ax
mov bp, ax
xor ax, ax
mov al, byte [bp] ; get letter value
push ax ; store letter from pointer 1
mov ax, [general_ptr2] ; copy address of the second pointer
add ax, cx ; adding current letter offset
dec ax
mov bp, ax
pop ax ; restore previous letter value
mov ah, byte [bp] ; get letter value
cmp ah, al
jne _check_equal_letter_continue
loop _check_equal_letter ; loop letters
; ... if it got here, all words are the same, so it's good
pop cx
mov ah, 0
ret
_check_equal_letter_continue:
pop cx
loop _check_valid_word_init ; loop words
; ... if it got here, there are no similar words
mov ah, 1
ret
;
; Check the status letter by letter
; Return: AH: 0 if ok
; 1 if all right
;
update_word_state:
; copy the currently selected word to temp variable - we will operate on it
push cs
pop es
mov si, [game_selected_word]
lea di, [game_selected_temp_word]
mov cx, 5
rep movsb
; get access to the current word
mov ax, 5 ; 5 letter per word
mov bl, byte [game_state_word] ; get current word
mul bl ; multiply by the amount of words
add ax, game_words ; adding the offset to the address
mov [general_ptr1], ax ; saving it to the pointer variable
; copy currently entered word to temp variabel - we will operate on it
mov si, [general_ptr1]
lea di, [game_state_temp_word]
mov cx, 5
rep movsb
mov ax, 0xb800
mov es, ax
xor ax, ax
mov [general_counter], ax
; get access to the current word's state
mov ax, 5 ; 5 letter per word
mov bl, byte [game_state_word] ; get current word
mul bl ; multiply by the amount of words
add ax, game_words_state ; adding the offset to the address
mov [general_ptr2], ax ; saving it to the pointer variable
; for every letter:
mov cx, 0
; first we check the greens
_green_letter_iteration:
mov [general_value], cx
; 1) check if the same index letter is the same, then green
mov ax, [general_ptr1] ; pointer to the word
add ax, cx ; add letter offset
mov bp, ax
mov ah, byte [bp] ; copy letter to ah
push ax
lea ax, [game_selected_temp_word] ; pointer to the word
add ax, cx ; add letter offset
mov bp, ax
pop ax
mov al, byte [bp]
cmp ah, al ; check if the letters are the same
je _update_set_green
_update_green_loop:
inc cx
cmp cx, 5
jne _green_letter_iteration
; secondly we check the yellows
mov cx, 0
_yellow_letter_iteration:
mov [general_value], cx
lea bx, [game_state_temp_word]
add bx, [general_value]
mov bl, byte [bx]
cmp bl, 0
je _update_yellow_loop
mov cx, 0
_letter_in_word_iteration:
lea ax, [game_selected_temp_word] ; pointer to the entered word
add ax, cx ; add letter offset
mov bp, ax
mov al, byte [bp]
cmp bl, al ; check if the letters are the same
je _update_set_yellow
inc cx
cmp cx, 5
jne _letter_in_word_iteration
mov ax, [general_ptr2] ; pointer to the word
add ax, [general_value] ; add letter offset
mov bp, ax
mov byte [bp], STATE_COLOR_NOTINWORD
; set letter state
mov bx, [general_ptr1] ; pointer to the word
add bx, [general_value] ; add letter offset
mov ah, byte [bx] ; copy the character
mov al, KEYBOARD_COLOR_NOTINWORD
call set_letter_state
_update_yellow_loop:
mov cx, [general_value]
inc cx
cmp cx, 5
jne _yellow_letter_iteration
_return:
mov ax, [general_counter]
cmp ax, 5
je _return_win
mov ah, 0
ret
_return_win:
mov ah, 1
ret
_update_set_yellow:
; set this letter state to yellow
mov ax, [general_ptr2] ; pointer to the word
add ax, [general_value] ; add letter offset
mov bp, ax
mov byte [bp], STATE_COLOR_INWORD ; set 'letter in word' state
_skip_update_set_yellow:
; remove matched letter from the temp word storage
lea bx, [game_selected_temp_word]
add bx, cx
mov byte [bx], 0
lea bx, [game_state_temp_word]
add bx, [general_value]
mov byte [bx], 0
; set letter state
mov bx, [general_ptr1] ; pointer to the word
add bx, [general_value] ; add letter offset
mov ah, byte [bx] ; copy the character
mov al, KEYBOARD_COLOR_INWORD
call set_letter_state
jmp _update_yellow_loop
_update_set_green:
mov ax, [general_counter]
inc ax
mov [general_counter], ax
; set this letter state to green
mov ax, [general_ptr2] ; pointer to the word
add ax, cx ; add letter offset
mov bp, ax
mov byte [bp], STATE_COLOR_CORRECT ; set 'letter in right position' state
; remove matched letter from the temp word storage
lea bx, [game_selected_temp_word]
add bx, [general_value]
mov byte [bx], 0
lea bx, [game_state_temp_word]
add bx, [general_value]
mov byte [bx], 0
; set letter state
mov bx, [general_ptr1] ; pointer to the word
add bx, [general_value] ; add letter offset
mov ah, byte [bx] ; copy the character
mov al, KEYBOARD_COLOR_CORRECT
push cx
call set_letter_state
pop cx
jmp _update_green_loop
;
; Set Letter State function
; Params: AH - character
; AL - state
;
set_letter_state:
mov cx, 26
mov bp, c_keyboard_rows + 25
_find_letter_loop:
mov bl, byte [bp]
add bl, 32 ; making it lower case to test with
cmp bl, ah
je _set_letter
dec bp
loop _find_letter_loop
ret
_set_letter:
mov bp, game_keyboard_state
add bp, cx
dec bp
cmp al, KEYBOARD_COLOR_CORRECT
je _set_color
cmp al, KEYBOARD_COLOR_INWORD
je _check_if_not_green_already
cmp al, KEYBOARD_COLOR_NOTINWORD
je _check_if_empty
jmp _set_color
_check_if_not_green_already:
cmp byte [bp], KEYBOARD_COLOR_CORRECT
jne _set_color
jmp _set_letter_exit
_check_if_empty:
cmp byte [bp], KEYBOARD_COLOR_EMPTY
je _set_color
jmp _set_letter_exit
_set_color:
mov byte [bp], al
_set_letter_exit:
ret
;;; BASE LIBRARY
%include "lib.asm"
;;; GAME GLOBAL VARIABLES
game_selected_word: dw 0 ; pointer to the selected word in the list
game_selected_temp_word: times 5 db 0 ; selected word temporal storage
game_state_letter: db 0 ; current letter
game_state_word: db 0 ; current word
game_state_temp_word: times 5 db 0 ; current word temporary storage
game_words:
db " "
db " "
db " "
db " "
db " "
db " "
game_words_state:
times 30 db 0
game_keyboard_state:
times 26 db 0
game_score: dw 0 ; global game score
game_w: db 0 ; current word used in functions
game_l: db 0 ; current letter used in functions
game_pos: dw 0 ; current position used in functions
game_letter_ptr: dw 0 ; pointer for the ltter in general
game_letter_selected_color: db 0 ; ... selected state
general_ptr1: dw 0 ; just general pointer
general_ptr2: dw 0 ; just general pointer
general_value: dw 0 ; just a general-use value
general_counter: dw 0 ; just a general-use counter
;;; GAME CONSTANTS
c_title_string: db "WORDLOS",0
c_game_score: db "SCORE: ",0
; 24 chars
c_message_win:
db "WHAT A SHOT! 100 POINTS",0
db " IMPRESSIVE! 50 POINTS",0
db " INCREDIBLE! 10 POINTS",0
db " PRETTY GOOD! 5 POINTS",0
db " GOOD ENOUGH! 2 POINTS",0
db " NICE! 1 POINT",0
c_message_invalid:
db " WORD NOT IN DICTIONARY",0
c_message_lost:
db " THE WORD WAS: ",0
c_message_empty:
db " ",0
c_keyboard_rows:
db "QWERTYUIOPASDFGHJKLZXCVBNM"
c_score_board:
dw 100
dw 50
dw 10
dw 5
dw 2
dw 1
%include "words.asm"