* mikeOS 16 bit and amd64 baremetal
[mascara-docs.git] / i86 / mikeos-4.1.2 / programs / hangman.asm
blobd028d12fa543ae98e59e2c0d908ba5d8540aa92e
1 ; ------------------------------------------------------------------
2 ; Geography-based hangman game for MikeOS
4 ; At the end of this file you'll see a list of 256 cities (in
5 ; lower-case to make the game code simpler). We get one city at
6 ; random from the list and store it in a string.
8 ; Next, we create another string of the same size, but with underscore
9 ; characters instead of the real ones. We display this 'work' string to
10 ; the player, who tries to guess characters. If s/he gets a char right,
11 ; it is revealed in the work string.
13 ; If s/he gets gets a char wrong, we add it to a list of misses, and
14 ; draw more of the hanging man. Poor bloke.
15 ; ------------------------------------------------------------------
18 BITS 16
19 %INCLUDE "mikedev.inc"
20 ORG 32768
23 start:
24 call os_hide_cursor
27 ; First, reset values in case user is playing multiple games
29 mov di, real_string ; Full city name
30 mov al, 0
31 mov cx, 50
32 rep stosb
34 mov di, work_string ; String that starts as '_' characters
35 mov al, 0
36 mov cx, 50
37 rep stosb
39 mov di, tried_chars ; Chars the user has tried, but aren't in the real string
40 mov al, 0
41 mov cx, 255
42 rep stosb
44 mov byte [tried_chars_pos], 0
45 mov byte [misses], 1 ; First miss is to show the platform
48 mov ax, title_msg ; Set up the screen
49 mov bx, footer_msg
50 mov cx, 01100000b
51 call os_draw_background
53 mov ax, 0
54 mov bx, 255
55 call os_get_random ; Get a random number
57 mov bl, cl ; Store in BL
60 mov si, cities ; Skip number of lines stored in BL
61 skip_loop:
62 cmp bl, 0
63 je skip_finished
64 dec bl
65 .inner:
66 lodsb ; Find a zero to denote end of line
67 cmp al, 0
68 jne .inner
69 jmp skip_loop
72 skip_finished:
73 mov di, real_string ; Store the string from the city list
74 call os_string_copy
76 mov ax, si
77 call os_string_length
79 mov dx, ax ; DX = number of '_' characters to show
81 call add_underscores
84 cmp dx, 5 ; Give first char if it's a short string
85 ja no_hint
87 mov ax, hint_msg_1 ; Tell player about the hint
88 mov bx, hint_msg_2
89 mov cx, 0
90 mov dx, 0
91 call os_dialog_box
93 call os_hide_cursor
95 mov ax, title_msg ; Redraw screen
96 mov bx, footer_msg
97 mov cx, 01100000b
98 call os_draw_background
100 mov byte al, [real_string] ; Copy first letter over
101 mov byte [work_string], al
104 no_hint:
105 call fix_spaces ; Add spaces to working string if necessary
107 main_loop:
108 call show_tried_chars ; Update screen areas
109 call show_hangman
110 call show_main_box
112 cmp byte [misses], 11 ; See if the player has lost
113 je lost_game
115 call os_wait_for_key ; Get input
117 cmp al, KEY_ESC
118 je finish
120 mov bl, al ; Store character temporarily
122 mov cx, 0 ; Counter into string
123 mov dl, 0 ; Flag whether char was found
124 mov si, real_string
125 find_loop:
126 lodsb
127 cmp al, 0 ; End of string?
128 je done_find
129 cmp al, bl ; Find char entered in string
130 je found_char
131 inc cx ; Move on to next character
132 jmp find_loop
136 found_char:
137 inc dl ; Note that at least one char match was found
138 mov di, work_string
139 add di, cx ; Update our underscore string with char found
140 mov byte [di], bl
141 inc cx
142 jmp find_loop
145 done_find:
146 mov si, real_string ; If the strings match, the player has won!
147 mov di, work_string
148 call os_string_compare
149 jc won_game
151 cmp dl, 0 ; If char was found, skip next bit
152 jne main_loop
154 call update_tried_chars ; Otherwise add char to list of misses
156 jmp main_loop
159 won_game:
160 call show_win_msg
161 .loop:
162 call os_wait_for_key ; Wait for keypress
163 cmp al, KEY_ESC
164 je finish
165 cmp al, KEY_ENTER
166 jne .loop
167 jmp start
170 lost_game: ; After too many misses...
171 call show_lose_msg
172 .loop: ; Wait for keypress
173 call os_wait_for_key
174 cmp al, KEY_ESC
175 je finish
176 cmp al, KEY_ENTER
177 jne .loop
178 jmp start
181 finish:
182 call os_show_cursor
183 call os_clear_screen
190 add_underscores: ; Create string of underscores
191 mov di, work_string
192 mov al, '_'
193 mov cx, dx ; Size of string
194 rep stosb
199 ; Copy any spaces from the real string into the work string
201 fix_spaces:
202 mov si, real_string
203 mov di, work_string
204 .loop:
205 lodsb
206 cmp al, 0
207 je .done
208 cmp al, ' '
209 jne .no_space
210 mov byte [di], ' '
211 .no_space:
212 inc di
213 jmp .loop
214 .done:
219 ; Here we check the list of wrong chars that the player entered previously,
220 ; and see if the latest addition is already in there...
222 update_tried_chars:
223 mov si, tried_chars
224 mov al, bl
225 call os_find_char_in_string
226 cmp ax, 0
227 jne .nothing_to_add ; Skip next bit if char was already in list
229 mov si, tried_chars
230 mov ax, 0
231 mov byte al, [tried_chars_pos] ; Move into the list
232 add si, ax
233 mov byte [si], bl
234 inc byte [tried_chars_pos]
236 inc byte [misses] ; Knock up the score
237 .nothing_to_add:
241 show_main_box:
242 pusha
243 mov bl, BLACK_ON_WHITE
244 mov dh, 5
245 mov dl, 2
246 mov si, 36
247 mov di, 21
248 call os_draw_block
250 mov dh, 7
251 mov dl, 4
252 call os_move_cursor
253 mov si, help_msg_1
254 call os_print_string
256 mov dh, 8
257 mov dl, 4
258 call os_move_cursor
259 mov si, help_msg_2
260 call os_print_string
262 mov dh, 17
263 mov dl, 4
264 call os_move_cursor
265 mov si, help_msg_3
266 call os_print_string
268 mov dh, 18
269 mov dl, 4
270 call os_move_cursor
271 mov si, help_msg_4
272 call os_print_string
274 mov dh, 12
275 mov dl, 6
276 call os_move_cursor
277 mov si, work_string
278 call os_print_string
280 popa
284 show_tried_chars:
285 pusha
286 mov bl, BLACK_ON_WHITE
287 mov dh, 18
288 mov dl, 40
289 mov si, 39
290 mov di, 23
291 call os_draw_block
293 mov dh, 19
294 mov dl, 41
295 call os_move_cursor
297 mov si, tried_chars_msg
298 call os_print_string
300 mov dh, 21
301 mov dl, 41
302 call os_move_cursor
304 mov si, tried_chars
305 call os_print_string
307 popa
312 show_win_msg:
313 mov bl, WHITE_ON_GREEN
314 mov dh, 14
315 mov dl, 5
316 mov si, 30
317 mov di, 15
318 call os_draw_block
320 mov dh, 14
321 mov dl, 6
322 call os_move_cursor
324 mov si, .win_msg
325 call os_print_string
327 mov dh, 12
328 mov dl, 6
329 call os_move_cursor
330 mov si, real_string
331 call os_print_string
336 .win_msg db 'Yay! Hit enter to play again', 0
340 show_lose_msg:
341 mov bl, WHITE_ON_LIGHT_RED
342 mov dh, 14
343 mov dl, 5
344 mov si, 30
345 mov di, 15
346 call os_draw_block
348 mov dh, 14
349 mov dl, 6
350 call os_move_cursor
352 mov si, .lose_msg
353 call os_print_string
355 mov dh, 12
356 mov dl, 6
357 call os_move_cursor
358 mov si, real_string
359 call os_print_string
364 .lose_msg db 'Doh! Hit enter to play again', 0
368 ; Draw the hangman box and appropriate bits depending on the number of misses
370 show_hangman:
371 pusha
373 mov bl, BLACK_ON_WHITE
374 mov dh, 2
375 mov dl, 42
376 mov si, 35
377 mov di, 17
378 call os_draw_block
381 cmp byte [misses], 0
382 je near .0
383 cmp byte [misses], 1
384 je near .1
385 cmp byte [misses], 2
386 je near .2
387 cmp byte [misses], 3
388 je near .3
389 cmp byte [misses], 4
390 je near .4
391 cmp byte [misses], 5
392 je near .5
393 cmp byte [misses], 6
394 je near .6
395 cmp byte [misses], 7
396 je near .7
397 cmp byte [misses], 8
398 je near .8
399 cmp byte [misses], 9
400 je near .9
401 cmp byte [misses], 10
402 je near .10
403 cmp byte [misses], 11
404 je near .11
406 .11: ; Right leg
407 mov dh, 10
408 mov dl, 64
409 call os_move_cursor
410 mov si, .11_t
411 call os_print_string
413 .10: ; Left leg
414 mov dh, 10
415 mov dl, 62
416 call os_move_cursor
417 mov si, .10_t
418 call os_print_string
420 .9: ; Torso
421 mov dh, 9
422 mov dl, 63
423 call os_move_cursor
424 mov si, .9_t
425 call os_print_string
427 .8: ; Arms
428 mov dh, 8
429 mov dl, 62
430 call os_move_cursor
431 mov si, .8_t
432 call os_print_string
434 .7: ; Head
435 mov dh, 7
436 mov dl, 63
437 call os_move_cursor
438 mov si, .7_t
439 call os_print_string
441 .6: ; Rope
442 mov dh, 6
443 mov dl, 63
444 call os_move_cursor
445 mov si, .6_t
446 call os_print_string
448 .5: ; Beam
449 mov dh, 5
450 mov dl, 56
451 call os_move_cursor
452 mov si, .5_t
453 call os_print_string
455 .4: ; Support for beam
456 mov dh, 6
457 mov dl, 57
458 call os_move_cursor
459 mov si, .4_t
460 call os_print_string
462 .3: ; Pole
463 mov dh, 12
464 mov dl, 56
465 call os_move_cursor
466 mov si, .3_t
467 call os_print_string
468 mov dh, 11
469 mov dl, 56
470 call os_move_cursor
471 call os_print_string
472 mov dh, 10
473 mov dl, 56
474 call os_move_cursor
475 call os_print_string
476 mov dh, 9
477 mov dl, 56
478 call os_move_cursor
479 call os_print_string
480 mov dh, 8
481 mov dl, 56
482 call os_move_cursor
483 call os_print_string
484 mov dh, 7
485 mov dl, 56
486 call os_move_cursor
487 call os_print_string
488 mov dh, 6
489 mov dl, 56
490 call os_move_cursor
491 call os_print_string
493 .2: ; Support for pole
494 mov dh, 13
495 mov dl, 55
496 call os_move_cursor
497 mov si, .2_t
498 call os_print_string
500 .1: ; Ground
501 mov dh, 14
502 mov dl, 53
503 call os_move_cursor
504 mov si, .1_t
505 call os_print_string
509 popa
513 .1_t db '-------------', 0
514 .2_t db '/|\', 0
515 .3_t db '|', 0
516 .4_t db '/', 0
517 .5_t db '________', 0
518 .6_t db '|', 0
519 .7_t db 'O', 0
520 .8_t db '---', 0
521 .9_t db '|', 0
522 .10_t db '/', 0
523 .11_t db '\', 0
527 title_msg db 'MikeOS Hangman', 0
528 footer_msg db 'Press Esc to exit', 0
530 hint_msg_1 db 'Short word this time, so you', 0
531 hint_msg_2 db 'get the first letter for free!', 0
533 help_msg_1 db 'Can you guess the city name', 0
534 help_msg_2 db 'that fits the spaces beneath?', 0
535 help_msg_3 db 'Press keys to guess letters,', 0
536 help_msg_4 db 'but you only have 10 chances!', 0
538 real_string times 50 db 0
539 work_string times 50 db 0
541 tried_chars_msg db 'Tried characters...', 0
542 tried_chars_pos db 0
543 tried_chars times 255 db 0
545 misses db 1
549 cities:
551 db 'kabul', 0
552 db 'tirane', 0
553 db 'algiers', 0
554 db 'andorra la vella', 0
555 db 'luanda', 0
556 db 'saint johns', 0
557 db 'bueno saires', 0
558 db 'yerevan', 0
559 db 'canberra', 0
560 db 'adelaide', 0
561 db 'melbourne', 0
562 db 'vienna', 0
563 db 'baku', 0
564 db 'nassau', 0
565 db 'manama', 0
566 db 'dhaka', 0
567 db 'bridgetown', 0
568 db 'minsk', 0
569 db 'brussels', 0
570 db 'belmopan', 0
571 db 'porto novo', 0
572 db 'thimpu', 0
573 db 'sucre', 0
574 db 'sarajevo', 0
575 db 'gaborone', 0
576 db 'brasilia', 0
577 db 'bandar seri begawan', 0
578 db 'sofia', 0
579 db 'ouagadougou', 0
580 db 'bujumbura', 0
581 db 'phnom penh', 0
582 db 'yaounde', 0
583 db 'ottawa', 0
584 db 'praia', 0
585 db 'bangui', 0
586 db 'ndjamema', 0
587 db 'santiago', 0
588 db 'beijing', 0
589 db 'bogota', 0
590 db 'moroni', 0
591 db 'brazzaville', 0
592 db 'kinshasa', 0
593 db 'san jose', 0
594 db 'yamoussoukro', 0
595 db 'zagreb', 0
596 db 'havana', 0
597 db 'nicosia', 0
598 db 'prague', 0
599 db 'copenhagen', 0
600 db 'djibouti', 0
601 db 'roseau', 0
602 db 'santo domingo', 0
603 db 'dili', 0
604 db 'quito', 0
605 db 'cairo', 0
606 db 'san salvador', 0
607 db 'malabo', 0
608 db 'asmara', 0
609 db 'tallinn', 0
610 db 'addis ababa', 0
611 db 'suva', 0
612 db 'helsinki', 0
613 db 'paris', 0
614 db 'libreville', 0
615 db 'banjul', 0
616 db 'tbilisi', 0
617 db 'berlin', 0
618 db 'accra', 0
619 db 'athens', 0
620 db 'saint georges', 0
621 db 'guatemala city', 0
622 db 'conakry', 0
623 db 'bissau', 0
624 db 'georgetown', 0
625 db 'port au prince', 0
626 db 'tegucigalpa', 0
627 db 'budapest', 0
628 db 'reykjavik', 0
629 db 'new delhi', 0
630 db 'jakarta', 0
631 db 'baghdad', 0
632 db 'dublin', 0
633 db 'jerusalem', 0
634 db 'rome', 0
635 db 'kingston', 0
636 db 'tokyo', 0
637 db 'amman', 0
638 db 'astana', 0
639 db 'nairobi', 0
640 db 'tarawa atoll', 0
641 db 'pyongyang', 0
642 db 'seoul', 0
643 db 'pristina', 0
644 db 'kuwait city', 0
645 db 'bishkek', 0
646 db 'vientiane', 0
647 db 'riga', 0
648 db 'beirut', 0
649 db 'maseru', 0
650 db 'monrovia', 0
651 db 'tripoli', 0
652 db 'vaduz', 0
653 db 'vilnius', 0
654 db 'luxembourg', 0
655 db 'skopje', 0
656 db 'antananarivo', 0
657 db 'lilongwe', 0
658 db 'kuala lumpur', 0
659 db 'male', 0
660 db 'bamako', 0
661 db 'valletta', 0
662 db 'majuro', 0
663 db 'nouakchott', 0
664 db 'port louis', 0
665 db 'mexico city', 0
666 db 'palikir', 0
667 db 'chisinau', 0
668 db 'monaco', 0
669 db 'ulaanbaatar', 0
670 db 'podgorica', 0
671 db 'rabat', 0
672 db 'maputo', 0
673 db 'rangoon', 0
674 db 'windhoek', 0
675 db 'yaren district', 0
676 db 'kathmandu', 0
677 db 'amsterdam', 0
678 db 'the hague', 0
679 db 'wellington', 0
680 db 'managua', 0
681 db 'niamey', 0
682 db 'abuja', 0
683 db 'lagos', 0
684 db 'oslo', 0
685 db 'bergen', 0
686 db 'stavanger', 0
687 db 'muscat', 0
688 db 'islamabad', 0
689 db 'karachi', 0
690 db 'melekeok', 0
691 db 'panama city', 0
692 db 'port moresby', 0
693 db 'asuncion', 0
694 db 'lima', 0
695 db 'manila', 0
696 db 'warsaw', 0
697 db 'lisbon', 0
698 db 'doha', 0
699 db 'bucharest', 0
700 db 'moscow', 0
701 db 'kigalo', 0
702 db 'basseterre', 0
703 db 'castries', 0
704 db 'kingstown', 0
705 db 'apia', 0
706 db 'san marino', 0
707 db 'sao tome', 0
708 db 'riyadh', 0
709 db 'dakar', 0
710 db 'belgrade', 0
711 db 'victoria', 0
712 db 'freetown', 0
713 db 'singapore', 0
714 db 'bratislava', 0
715 db 'ljubljana', 0
716 db 'honiara', 0
717 db 'mogadishu', 0
718 db 'pretoria', 0
719 db 'bloemfontein', 0
720 db 'madrid', 0
721 db 'colombo', 0
722 db 'khartoum', 0
723 db 'paramaribo', 0
724 db 'mbabane', 0
725 db 'stockholm', 0
726 db 'bern', 0
727 db 'geneva', 0
728 db 'zurich', 0
729 db 'damascus', 0
730 db 'taipei', 0
731 db 'dushanbe', 0
732 db 'dar es salaam', 0
733 db 'bangkok', 0
734 db 'lome', 0
735 db 'nukualofa', 0
736 db 'port of spain', 0
737 db 'tunis', 0
738 db 'ankara', 0
739 db 'ashgabat', 0
740 db 'funafuti', 0
741 db 'kampala', 0
742 db 'kiev', 0
743 db 'abu dhabi', 0
744 db 'dubai', 0
745 db 'london', 0
746 db 'washington', 0
747 db 'montevideo', 0
748 db 'tashkent', 0
749 db 'port vila', 0
750 db 'vatican city', 0
751 db 'caracas', 0
752 db 'hanoi', 0
753 db 'sanaa', 0
754 db 'lusaka', 0
755 db 'harare', 0
756 db 'st petersburg', 0
757 db 'odessa', 0
758 db 'manchester', 0
759 db 'liverpool', 0
760 db 'birmingham', 0
761 db 'frankfurt', 0
762 db 'munich', 0
763 db 'dortmund', 0
764 db 'new york', 0
765 db 'chicago', 0
766 db 'san francisco', 0
767 db 'los angeles', 0
768 db 'las vegas', 0
769 db 'boston', 0
770 db 'new jersey', 0
771 db 'dallas', 0
772 db 'atlanta', 0
773 db 'miami', 0
774 db 'vancouver', 0
775 db 'toronto', 0
776 db 'saopaulo', 0
777 db 'rio de janeiro', 0
778 db 'vladivostok', 0
779 db 'glasgow', 0
780 db 'edinburgh', 0
781 db 'lyon', 0
782 db 'venice', 0
783 db 'torshavn', 0
784 db 'nuuk', 0
785 db 'bristol', 0
786 db 'york', 0
787 db 'tel aviv', 0
788 db 'seattle', 0
789 db 'stuttgart', 0
790 db 'osaka', 0
791 db 'kyoto', 0
792 db 'sapporo', 0
793 db 'kagoshima', 0
794 db 'shanghai', 0
795 db 'chongqing', 0
796 db 'hong kong', 0
797 db 'macao', 0
798 db 'xian', 0
799 db 'lhasa', 0
800 db 'warrington', 0
801 db 'leeds', 0
802 db 'luxor', 0
803 db 'timbuktu', 0
804 db 'honolulu', 0
805 db 'bordeaux', 0
806 db 'cupertino', 0
809 ; ------------------------------------------------------------------