~hangman8086-devs/hangman8086/trunk

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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;      __   __  _______  __    _  _______  __   __  _______  __    _       ;;
;;     |  | |  ||   _   ||  |  | ||       ||  |_|  ||   _   ||  |  | |      ;;
;;     |  |_|  ||  |_|  ||   |_| ||    ___||       ||  |_|  ||   |_| |      ;;
;;     |       ||       ||       ||   | __ |       ||       ||       |      ;;
;;     |       ||       ||  _    ||   ||  ||       ||       ||  _    |      ;;
;;     |   _   ||   _   || | |   ||   |_| || ||_|| ||   _   || | |   |      ;;
;;     |__| |__||__| |__||_|  |__||_______||_|   |_||__| |__||_|  |__|      ;;
;;                                                                          ;;
;;                                                                          ;;
;;  HANGMAN - An implementation of the Hang Man game in assembly (Emu8086)  ;;
;;                                                                          ;;
;;  Copyright (C) 2011  Fabien LOISON                                       ;;
;;  Copyright (C) 2011  Mathilde BOUTIGNY                                   ;;
;;  Copyright (C) 2011  Vincent PEYROUSE                                    ;;
;;  Copyright (C) 2011  Germain CARRÉ                                       ;;
;;  Copyright (C) 2011  Matthis FRENAY                                      ;;
;;                                                                          ;;
;;  HangMan 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.                                     ;;
;;                                                                          ;;
;;  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.                            ;;
;;                                                                          ;;
;;  You should have received a copy of the GNU General Public License       ;;
;;  along with this program.  If not, see <http://www.gnu.org/licenses/>.   ;;
;;                                                                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;
;; Contains the game functions.
;;
;; Index:
;;     _play(WORD)          -- Play to hangman.
;;     _game_init()         -- Initializes the game.
;;     _print_gibbet()      -- Prints the gibbet with remaining lives.
;;     _print_gword()       -- Prints the guessed word (e.g. H _ _ _ _ _ N).
;;     _print_tried_letters -- Prints the letters that the player have already
;;                             tried (e.g. A U I O W).
;;     _print_score()       -- Print the score (in competition mode).
;;     _game_anima()        -- Displays an animation when the player loose
;;                             or win.
;;



GAME_STATUS_LOOSE equ 0
GAME_STATUS_WIN   equ 1
GAME_STATUS_ABORT equ 2

SCORE  dw 0
PLAYER dw "UNNAMED "


;============================================================ _play(WORD) ====
;; Play to hangman.

;; Usage:
;; mov WORD, offset <word>
;; mov PLAYER, offset <playername>
;; call _play

;; Function args:
WORD   dw 0 ;The adress of the word to guess.

;; Returns:
GAME_STATUS db 0 ;The game status (GAME_STATUS_LOOSE, GAME_STATUS_WIN,
                 ;GAME_STATUS_ABORT).


_play:

;Backup registers
push ax
push bx
push cx
push dx

call _draw_ui
mov HELP_STR, offset game_help
call _print_help
call _game_init

mov GAME_STATUS, GAME_STATUS_LOOSE

play_main_loop:
    call _clear_working
    call _print_gword
    call _print_tried_letters
    call _print_gibbet
    call _print_score

    ;Check if the play win
    ;For checking we search underscores in play_gword... It is not very
    ;pretty but it works...
    play_check_win:
    mov cl, play_word_len
    mov bx, offset play_gword
    play_check_win_loop:
        cmp [bx], '_'
        je  play_check_win_end ;not won yet
        inc bx
        dec cl
        cmp cl, 0
        jne play_check_win_loop
        ;The player win !
        mov GAME_STATUS, GAME_STATUS_WIN
        jmp play_eog
    play_check_win_end:

    ;Get a letter
    call _input_letter

    ;Check fo special keys
    cmp LETTER, KB_ENTER ;skip Enter
    je  play_main_loop
    cmp LETTER, KB_BKSP  ;skip Backspace
    je  play_main_loop
    cmp LETTER, KB_ESC   ;stop with Escape
    je  play_abort

    ;Check if the player have already tried this letter
    mov cl, play_tried_len
    mov bx, offset play_tried_letters
    mov al, LETTER
    play_ckeck_tried:
        cmp [bx], al
        je play_main_loop ;Letter already in the list -> play_main_loop
        inc bx
        dec cl
        cmp cl, 0
        jne play_ckeck_tried

    ;The letter is not in the list (play_tried_letters), so we add it
    mov cl, play_tried_len
    mov bx, offset play_tried_letters
    mov al, LETTER
    play_add_letter:
        cmp [bx], ' ' ;Search a space
        je play_add_letter_add
        inc bx
        dec cl
        cmp cl, 0
        jne play_add_letter
        jmp play_add_letter_end ;Something is wrong... No more place !
        play_add_letter_add:
            mov [bx], al
        play_add_letter_end:

    ;Check if the letter is in the word
    mov cl, play_word_len
    sub cl, 2
    mov bx, offset play_word
    inc bx
    mov al, LETTER
    play_check_word:
        cmp [bx], al
        je play_check_word_ok
        inc bx
        dec cl
        cmp cl, 0
        jne play_check_word
        ;The letter is not in the word
        dec play_lives
        mov SOUND, offset SND_GAME_BAD_LTTR
        call _play_sound
        jmp play_check_word_end
        play_check_word_ok:
        mov SOUND, offset SND_GAME_GOOD_LTTR
        call _play_sound
        play_check_word_end:

    ;Check the lives
    cmp play_lives, 0
    je  play_eog ;Hanged x_x

    jmp play_main_loop

play_eog:

call _game_anima
jmp play_end

play_abort:
mov GAME_STATUS, GAME_STATUS_ABORT

play_end:

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret


;_play vars
play_word          db  "------------------------------"
play_word_len      db  0
play_word_max_len  equ 30

play_gword         db  "------------------------------"
play_tried_letters db  "--------------------------"
play_tried_len     equ 26

play_lives         db  0

;Help
game_help  db 0xDA,"A-Z",0xBF," Try a letter                                 "
           db "         ",0xDA,"Esc",0xBF," End the game$"



;=========================================================== _game_init() ====
;; Initializes the game.

;; NOTE: Called by the _play() function.

;; Usage:
;; call _game_init


_game_init:

;Backup registers
push ax
push bx
push cx
push dx

;Put the length of WORD in play_word_len
mov ax, WORD
mov STRLEN_STR, ax
call _strlen
mov al, STRLEN_LEN
mov play_word_len, al

;Put the WORD in play_word
mov ax, WORD
mov MEMCPY_SRC, ax
mov MEMCPY_DEST, offset play_word
mov al, STRLEN_LEN
mov MEMCPY_LEN, al
call _memcpy

;Fill play_tried_letters with spaces
mov bx, offset play_tried_letters
mov cl, play_tried_len

game_init_sploop:
    mov [bx], ' '
    inc bx
    dec cl
    cmp cl, 0
    jne game_init_sploop

;Init the play_lives to 10 (with gibbet) or 6 (without gibbet)
cmp OPTION_GIBBET, OPTION_GIBBET_ON
je  game_init_lives_gibbet_on
mov play_lives, 6
jmp game_init_lives_gibbet_end
game_init_lives_gibbet_on:
mov play_lives, 10
game_init_lives_gibbet_end:

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret



;======================================================== _print_gibbet() ====
;; Prints the gibbet with remaining lives.

;; Usage:
;; call _print_gibbet


_print_gibbet:

;Backup registers
push ax
push bx
push cx
push dx

;Calculate the address of the gibbet that fit with the remaining lives
mov ah, 0
mov al, GIBBET_WIDTH
mov bh, 0
mov bl, GIBBET_HEIGHT
mul bl

mov bx, 10
sub bl, play_lives
mul bl

mov bx, offset HANGMAN_LIVES_10
add bx, ax

;Print the gibbet
mov cl, GIBBET_HEIGHT
mov ah, 0x09
mov dx, bx
mov bx, GIBBET_WIDTH
mov POS_X, COLS - GIBBET_WIDTH - 2
mov POS_Y, (ROWS - GIBBET_HEIGHT) / 2 + (header_height - 1) / 2
print_gibbet_loop:
    call _move_cursor
    int 0x21 ;Print
    add dx, bx
    inc POS_Y
    dec cl
    cmp cl, 0
    jne print_gibbet_loop

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret



;========================================================= _print_gword() ====
;; Prints the guessed word (e.g. H _ _ _ _ _ N).

;; Usage:
;; call _print_gword


_print_gword:

;Backup registers
push ax
push bx
push cx
push dx

;Copy the word in play_gword
mov ax, WORD
mov MEMCPY_SRC, ax
mov MEMCPY_DEST, offset play_gword
mov al, STRLEN_LEN
mov MEMCPY_LEN, al
call _memcpy

;Make the string
mov cl, play_word_len
sub cl, 2
mov bx, offset play_gword
inc bx

print_gword_mkloop:
    mov al, [bx]
    mov ch, play_tried_len
    push bx
    mov bx, offset play_tried_letters
    print_gword_mkloop1:
        mov ah, [bx]
        cmp ah, al
        je print_gword_lil
        dec ch
        inc bx
        cmp ch, 0
        jne print_gword_mkloop1

    print_gword_lnil: ;Letter Not In List
        pop bx
        mov [bx], '_'
        jmp print_gword_mkloopend

    print_gword_lil: ;Letter In List
        pop bx

    print_gword_mkloopend:
        dec cl
        inc bx
        cmp cl, 0
        jne print_gword_mkloop

;Print the word
mov POS_Y, ROWS / 2 + (header_height - 1) - 5
mov POS_X, COLS / 2 - GIBBET_WIDTH + 3
mov al, play_word_len
sub POS_X, al
mov bx, offset play_gword
mov cl, play_word_len
mov ah, 0x02
print_gword_prnloop:
    call _move_cursor
    mov dl, [bx]
    int 0x21 ;print
    inc bx
    add POS_X, 2
    dec cl
    cmp cl, 0
    jne print_gword_prnloop

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret



;================================================= _print_tried_letters() ====
;; Print the letters that the player have already tried (e.g. A U I O W).

;; Usage:
;; call _print_tried_letters


_print_tried_letters:

;Backup registers
push ax
push bx
push cx
push dx

;Calculate the length of the string
mov cl, 0
mov bx, offset play_tried_letters
prn_tried_strlen:
    cmp [bx], ' '
    je  prn_tried_strlen_end
    inc bx
    inc cl
    jmp prn_tried_strlen
prn_tried_strlen_end:

;Calculate the cursor position
mov POS_Y, ROWS / 2 + (header_height - 1) - 2
mov POS_X, COLS / 2 - GIBBET_WIDTH + 3
sub POS_X, cl

;Print letters
cmp cl, 0
je  prn_tried_end
mov bx, offset play_tried_letters
mov ah, 0x02

prnletters_loop:
    call _move_cursor
    mov dl, [bx]
    int 0x21 ;print
    inc bx
    add POS_X, 2
    dec cl
    cmp cl, 0
    jne prnletters_loop

prn_tried_end:

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret



;========================================================= _print_score() ====
;; Print the score (in competition mode).

;; Usage:
;; call _print_tried_letters


_print_score:

;Backup registers
push ax
push bx
push cx
push dx

;Check if we are in competition mode
cmp MODE, MODE_COMPETITION
jnz prn_score_end

;Set the scorebar
mov ah, 0x07
mov al, 0         ; Clear
mov bh, COLOR_SCORE
mov ch, header_height + 1  ;y1
mov cl, 0                  ;x1
mov dh, header_height + 1  ;y2
mov dl, COLS               ;x2
int 0x10

;Paste the player name
mov MEMCPY_SRC, offset PLAYER
mov MEMCPY_DEST, offset prn_score_str
add MEMCPY_DEST, 2
mov MEMCPY_LEN, 8
call _memcpy

;Convert the score into string and paste it
mov ax, SCORE
mov I2S_INT, ax
call _inttostr
mov MEMCPY_SRC, offset I2S_STR
add MEMCPY_DEST, 11
mov MEMCPY_LEN, 4
call _memcpy

;Print the string
mov POS_X, 0
mov POS_Y, header_height + 1
call _move_cursor
mov ah, 0x09
mov dx, offset prn_score_str
int 0x21

prn_score_end:

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret


;Data
prn_score_str db " ",0xC0,"12345678",0xD9," ",0xC0,"1234",0xD9,"$"



;========================================================== _game_anima() ====
;; Displays an animation when the player loose or win.

;; Usage:
;; call _game_anima


_game_anima:

;Backup registers
push ax
push bx
push cx
push dx

;Play a sound
cmp GAME_STATUS, GAME_STATUS_WIN
je  game_anima_sndwin
mov SOUND, offset SND_GAME_DIE
jmp game_anima_sndend
game_anima_sndwin:
mov SOUND, offset SND_GAME_GG
game_anima_sndend:
call _play_sound

;Draw the ui
call _draw_ui

;Print the help message
mov HELP_STR, offset game_anima_help
call _print_help

;Flush the input buffer
mov ah, 0x0C
mov al, 0
int 0x21

;Print the word
mov cl, play_word_len
mov bx, offset play_word
mov POS_X, COLS/2
sub POS_X, cl
mov POS_Y, header_height + GIBBET_HEIGHT + 5
mov ah, 0x02
game_anima_pnrloop:
    call _move_cursor
    mov dl, [bx]
    int 0x21 ;print
    inc bx
    add POS_X, 2
    dec cl
    cmp cl, 0
    jne game_anima_pnrloop

;Loop until the player press any key
game_anima_loop0:
mov ch, 4
cmp GAME_STATUS, GAME_STATUS_WIN
je  game_anima_win
mov dx, offset HANGMAN_GAMEOVER_00
jmp game_anima_loop1
game_anima_win:
mov dx, offset HANGMAN_GOODGAME_00
game_anima_loop1:
    ;Check for keystroke
    mov ah, 0x01
    int 0x16
    jnz game_anima_end

    ;Print the animation (step 00)
    mov cl, GIBBET_HEIGHT
    mov ah, 0x09
    mov POS_X, (COLS - GIBBET_WIDTH) / 2
    mov POS_Y, header_height + 3
    game_anima_prnloop00:
        call _move_cursor
        int 0x21 ;Print
        inc POS_Y
        dec cl
        add dx, GIBBET_WIDTH
        cmp cl, 0
        jne game_anima_prnloop00

    ;Sleep
    push cx
    mov ah, 0x86
    mov cx, 3
    int 0x15
    pop cx

    dec ch
    cmp ch, 0
    je  game_anima_loop0

    jmp game_anima_loop1

game_anima_end:

;Check the char
mov ah, 0x00
int 0x16
cmp al, KB_ESC
jne game_anima_chrend
mov GAME_STATUS, GAME_STATUS_ABORT

game_anima_chrend:

;Restore registers
pop dx
pop cx
pop bx
pop ax

ret


;Help
game_anima_help  db "Press any key to continue                          "
                 db "         ",0xDA,"Esc",0xBF," End the game$"