summaryrefslogtreecommitdiff
path: root/source.asm
blob: eec72a80d7ca4305889c41e805c53fe9542a651a (plain) (blame)
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
covered_color equ 0x70
controls_color equ 0x0f
flag_character equ 'F' 
bombs_per_65535 equ 5000

board_width equ 26
board_height equ 10
offset_x equ 1
offset_y equ 1

org 0x0100

  mov ax, 0x0501
  int 0x10

  xor ah, ah
  int 0x1a

  test dx, dx
  jnz nonzero
  inc dx
nonzero:
  mov word [xorshift_state], dx

  mov cx, board_width * board_height
  mov si, cx
  mov di, board_flags
bomb_loop:
  call xorshift
  cmp ax, bombs_per_65535
  ja .no_bomb
  mov byte [di], board_bomb
  dec si
.no_bomb:
  inc di
  loop bomb_loop
  mov word [non_bombs_left], si

  xor bx, bx
  mov di, board_numbers
number_loop:
  call get_number_of_bx
  mov byte [di], al
  inc di
  inc bl
  cmp bl, board_width
  jne number_loop
  xor bl, bl
  inc bh
  cmp bh, board_height
  jne number_loop

  push 0xb900
  pop es

  xor di, di
  mov ax, ' '
  mov cx, 80 * 25
  rep stosw

  mov di, offset_y * 80 * 2 + offset_x * 2
  mov cx, board_width * 3
  mov ax, (covered_color << 8) | 0xdf
  rep stosw

  mov di, (offset_y + 1) * 80 * 2 + offset_x * 2
  mov ax, (covered_color << 8) | ' '
gray_loop:
  mov cx, board_width * 3
  rep stosw
  add di, (80 - board_width * 3) * 2
  cmp di, (offset_y + board_height * 2) * 80 * 2 + offset_x * 2
  jne gray_loop

  mov cx, board_width * 3
  mov ax, (covered_color << 8) | 0xdc
  rep stosw

  mov si, controls_str
  mov di, (offset_y + board_height * 2 + 2) * 80 * 2 + offset_x * 2 + ((board_width * 3 - controls_str.len) / 4) * 2
  mov cx, controls_str.len
  mov ah, controls_color
show_controls_loop:
  mov al, byte [si]
  mov word [es:di], ax
  inc si
  add di, 2
  loop show_controls_loop

  call set_cursor

main_loop:
  xor ah, ah
  int 0x16

  cmp ah, 0x48
  je up_arrow

  cmp ah, 0x50
  je down_arrow

  cmp ah, 0x4b
  je left_arrow

  cmp ah, 0x4d
  je right_arrow

  cmp ah, 0x20
  je dig

  cmp ah, 0x21
  je flag

  cmp ah, 0x10
  jne main_loop

  mov ax, 0x0500
  int 0x10

  mov ax, 0x4c00
  int 0x21

xorshift_state:
  dw 0

xorshift:
  mov ax, word [xorshift_state]
  mov dx, ax
  shl dx, 7
  xor ax, dx
  mov dx, ax
  shr dx, 9
  xor ax, dx
  xor ah, al
  mov word [xorshift_state], ax
  ret

;bx - y:x
;preserves bx, di, and si
;returns in ax
bx_has_bomb:
  push bx
  movzx ax, bh
  mov cx, board_width
  mul cx
  xor bh, bh
  add bx, ax
  mov ax, board_bomb
  and al, byte [board_flags + bx]
  pop bx
  ret

;bx - y:x
;preserves bx, di, and si
;returns in ax
bx_uncovered:
  push bx
  movzx ax, bh
  mov cx, board_width
  mul cx
  xor bh, bh
  add bx, ax
  mov ax, board_uncovered
  and al, byte [board_flags + bx]
  pop bx
  ret

;bx - y:x
;preserves bx and di
;returns in al
get_number_of_bx:
  xor si, si

  test bh, bh
  jz .no_ups

  dec bh

  test bl, bl
  jz .no_ul

  dec bl
  call bx_has_bomb
  add si, ax
  inc bl

.no_ul:
  call bx_has_bomb
  add si, ax

  cmp bl, board_width - 1
  je .no_ur

  inc bl
  call bx_has_bomb
  add si, ax
  dec bl

.no_ur:
  inc bh

.no_ups:
  test bl, bl
  jz .no_cl

  dec bl
  call bx_has_bomb
  add si, ax
  inc bl

.no_cl:
  cmp bl, board_width - 1
  je .no_cr

  inc bl
  call bx_has_bomb
  add si, ax
  dec bl

.no_cr:
  cmp bh, board_height - 1
  je .no_downs

  inc bh

  test bl, bl
  jz .no_bl

  dec bl
  call bx_has_bomb
  add si, ax
  inc bl

.no_bl:
  call bx_has_bomb
  add si, ax

  cmp bl, board_width - 1
  je .no_br

  inc bl
  call bx_has_bomb
  add si, ax
  dec bl

.no_br:
  dec bh

.no_downs:
  mov ax, si
  ret

set_cursor:
  mov ah, 0x02
  mov bh, 0x01
  mov cx, word [cursor_x]
  mov dl, cl
  add dl, cl
  add dl, cl
  add dl, offset_x + 1
  mov dh, ch
  add dh, ch
  add dh, offset_y + 1
  int 0x10
  jmp main_loop

up_arrow:
  mov al, byte [cursor_y]
  test al, al
  jz main_loop

  dec al
  mov byte [cursor_y], al
  call set_cursor
  jmp main_loop

down_arrow:
  mov al, byte [cursor_y]
  cmp al, board_height - 1
  je main_loop

  inc al
  mov byte [cursor_y], al
  call set_cursor
  jmp main_loop

left_arrow:
  mov al, byte [cursor_x]
  test al, al
  jz main_loop

  dec al
  mov byte [cursor_x], al
  call set_cursor
  jmp main_loop

right_arrow:
  mov al, byte [cursor_x]
  cmp al, board_width - 1
  je main_loop

  inc al
  mov byte [cursor_x], al
  call set_cursor
  jmp main_loop

dig:
  call get_board_flags_at_cursor
  test al, board_uncovered | board_flagged
  jnz main_loop

  test al, board_bomb
  jnz lose

  or al, board_uncovered
  call set_board_flags_at_cursor

  push ax
  call get_cursor_vram_offset
  mov di, ax
  pop ax

  call get_number_at_cursor
  movzx bx, al
  mov al, byte [bx + uncovered_numbers]
  mov ah, byte [bx + uncovered_colors]
  mov word [es:di], ax

  mov bx, word [cursor_x]
  test bh, bh
  jz .top_full_block

  dec bh
  call bx_uncovered
  inc bh
  test al, al
  jnz .top_full_block

  mov word [es:di - 80 * 2 - 2], (covered_color << 8) | 0xdc
  mov word [es:di - 80 * 2], (covered_color << 8) | 0xdc
  mov word [es:di - 80 * 2 + 2], (covered_color << 8) | 0xdc
  jmp .middle

.top_full_block:
  mov word [es:di - 80 * 2 - 2], ' '
  mov word [es:di - 80 * 2], ' '
  mov word [es:di - 80 * 2 + 2], ' '

.middle:
  mov byte [es:di - 2 + 1], 0
  mov byte [es:di + 2 + 1], 0

  cmp bh, board_height - 1
  je .bottom_full_block

  inc bh
  call bx_uncovered
  dec bh
  test al, al
  jnz .bottom_full_block

  mov word [es:di + 80 * 2 - 2], (covered_color << 8) | 0xdf
  mov word [es:di + 80 * 2], (covered_color << 8) | 0xdf
  mov word [es:di + 80 * 2 + 2], (covered_color << 8) | 0xdf
  jmp .dec_bombs

.bottom_full_block:
  mov word [es:di + 80 * 2 - 2], ' '
  mov word [es:di + 80 * 2], ' '
  mov word [es:di + 80 * 2 + 2], ' '

.dec_bombs:
  mov ax, word [non_bombs_left]
  dec ax

  test ax, ax
  jz win

  mov word [non_bombs_left], ax

  jmp main_loop

uncovered_colors:
  db 0x08, 0x08, 0x0a, 0x0c, 0x0b, 0x0e, 0x09, 0x07, 0x0f
uncovered_numbers:
  db " 12345678"

flag:
  call get_board_flags_at_cursor
  test al, board_uncovered
  jnz main_loop
  xor al, board_flagged
  push ax
  call get_cursor_vram_offset
  mov di, ax
  pop ax
  call set_board_flags_at_cursor

  test al, board_flagged
  jz .not_flagged

  mov byte [es:di], flag_character
  jmp main_loop

.not_flagged:
  mov byte [es:di], ' '
  jmp main_loop

;as rows
board_flags:
  times board_width * board_height db 0
board_bomb equ 1
board_uncovered equ 2
board_flagged equ 4

board_numbers:
  times board_width * board_height db 0

get_board_flags_at_cursor:
  movzx ax, byte [cursor_y]
  mov cx, board_width
  mul cx
  movzx bx, byte [cursor_x]
  add bx, ax
  mov al, byte [board_flags + bx]
  ret

get_cursor_vram_offset:
  mov cx, word [cursor_x]

  mov bl, cl
  add bl, cl
  add bl, cl
  add bl, offset_x + 1

  mov bh, ch
  add bh, ch
  add bh, offset_y + 1

  mov cx, 80
  movzx ax, bh
  mul cx
  xor bh, bh
  add ax, bx
  add ax, ax

  ret

;preserves ax and di
set_board_flags_at_cursor:
  mov si, ax
  movzx ax, byte [cursor_y]
  mov cx, board_width
  mul cx
  movzx bx, byte [cursor_x]
  add bx, ax
  mov ax, si
  mov byte [board_flags + bx], al
  ret

;preserves di
get_number_at_cursor:
  movzx ax, byte [cursor_y]
  mov cx, board_width
  mul cx
  movzx bx, byte [cursor_x]
  add bx, ax
  mov al, byte [board_numbers + bx]
  ret

cursor_x:
  db 0
cursor_y:
  db 0

non_bombs_left:
  dw 0

controls_str:
  db "Controls:   Arrows - Move Cursor   D - Dig   F - Flag   Q - Quit"
.len equ $ - controls_str

win:
  push ds
  pop es

  mov ax, 0x1300
  mov bx, 0x010f
  mov cx, .len
  mov dx, 0x0a24
  mov bp, .str
  int 0x10

  jmp win_or_lose

.str:
  db "You win!"
.len equ $ - .str

lose:
  push ds
  pop es

  mov ax, 0x1300
  mov bx, 0x010f
  mov cx, .len
  mov dx, 0x0a23
  mov bp, .str
  int 0x10

  jmp win_or_lose

.str:
  db "You lose!"
.len equ $ - .str

win_or_lose:
  mov ax, 0x1300
  mov bx, 0x010f
  mov cx, .len
  mov dx, 0x0c1d
  mov bp, .str
  int 0x10

  xor ax, ax
  int 0x16

  mov ax, 0x0500
  int 0x10

  mov ax, 0x4c00
  int 0x21

.str:
  db "Press any key to quit."
.len equ $ - .str