-
Notifications
You must be signed in to change notification settings - Fork 0
/
turtle.asm
465 lines (369 loc) · 9.83 KB
/
turtle.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
; ===
; === VIRTUAL TURTLE
; === Blake Burgess
; === March - April 2014
; ===
; === Control an on-screen turtle by giving it commands: left, right, up, down, and paint.
; ===
; === The program features simple command processing and collision detection, and uses a 40x25 text mode.
; === Because it is designed to work in both MS-DOS and MikeOS, it includes string parsing functions
; === already, so the program does not have to rely solely on the MikeOS API system calls.
; ===
; === For this custom library, I devised a scheme that allows me to selectively pick which procedures to
; === import from each included source file. This means that I can minimize unnecessary program space that
; === is wasted to unused procedures. It uses the Flat Assembler's macro functions to accomplish this;
; === therefore, this program will not compile under the Net Assembler without modifications.
; ===
org 0x100 ; MS-DOS program
jmp start
; ==============================
; === INCLUDES AND SYMBOLS =====
; ==============================
; Only need to import the procedures necessary. Macros within the includes can be used without
; importing them first.
macro import function {function}
include "screen.asm"
include "string.asm"
import string.teletype
import string.match
include "keyboard.asm"
import keyboard.inputString
import keyboard.waitForKey
cursor.xPos equ dl
cursor.yPos equ dh
start.xPos equ 20
start.yPos equ 12
promptColor equ 0x1F ; white on blue text
fieldColor equ 0x2F ; white on green text
paintColor equ 0x4F ; white on red text
turtleFace equ 0x02 ; filled smiley face
; ==============================
; === ENTRY POINT ==============
; ==============================
start:
.getScreenInfo:
screen.getMode
mov di, data_state.screenMode
mov [di], al ; preserve screen mode
.setScreenMode:
mov al, screen.mode.text.4025
screen.setMode ; set screen to 40x25 text, 16 colors
createScreen:
.fillGreen:
mov cx, 23 ; number of rows to fill
mov bh, 0 ; first page
xor dx, dx ; position at 0, 0
mov al, 0 ; null character
.fillGreen.nextLine:
screen.text.setCursorPosition
push cx
mov cx, 40 ; characters to write
mov bl, fieldColor
screen.text.setCharacter
inc dh ; next row
pop cx
loop .fillGreen.nextLine
.fillPrompt:
mov cx, 2 ; number of rows to fill
mov cursor.xPos, 0 ; position at 0, 23
mov cursor.yPos, 23
.fillPrompt.nextLine:
screen.text.setCursorPosition
push cx
mov cx, 40 ; characters to write
mov bl, promptColor
screen.text.setCharacter
inc dh ; next row
pop cx
loop .fillPrompt.nextLine
.createTurtle: ; create turtle at start position
mov cursor.xPos, start.xPos
mov cursor.yPos, start.yPos
screen.text.setCursorPosition
mov al, turtleFace
string.putChar
call showHelp
call showPrompt
; ==============================
; === MAIN PROGRAM LOOP ========
; ==============================
main:
; get command string from keyboard
; ==============================
mov al, 8 ; 8 max characters
mov ah, 1 ; echo enabled
mov di, data_str.buffer ; pointer to string buffer
call keyboard.inputString
; interpret string and perform the command
; ==============================
.checkInput:
mov si, data_str.buffer
mov di, data_command.up
call string.match ; == "up"
jnc @f ; no match? check the next command
call handler.goUp
jmp .checkInput.end
@@:
mov di, data_command.down
call string.match ; == "down"
jnc @f ; no match? check the next command
call handler.goDown
jmp .checkInput.end
@@:
mov di, data_command.left
call string.match ; == "left"
jnc @f ; no match? check the next command
call handler.goLeft
jmp .checkInput.end
@@:
mov di, data_command.right
call string.match ; == "right"
jnc @f ; no match? check the next command
call handler.goRight
jmp .checkInput.end
@@:
mov di, data_command.paint
call string.match ; == "paint"
jnc @f ; no match? check the next command
call handler.paint
jmp .checkInput.end
@@:
mov di, data_command.exit
call string.match ; == "exit"
jnc @f ; no match? check the next command
jmp exit
@@:
call showHelp
.checkInput.end:
call showPrompt
jmp main
; ==============================
; === PROGRAM FUNCTION SECTION =
; ==============================
handler:
.goUp:
mov al, byte [data_turtle.yPos]
cmp al, 0
jz @f ; collision detection
mov cursor.xPos, byte [data_turtle.xPos]
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
mov al, ' ' ; erase old face
string.putChar
mov al, byte [data_turtle.yPos]
dec al ; save new cursor position
mov [data_turtle.yPos], al
mov cursor.yPos, al ; update new cursor position on screen
mov cursor.xPos, byte [data_turtle.xPos]
screen.text.setCursorPosition
call paintPixel ; paint pixel if enabled
mov al, turtleFace ; display new face
string.putChar
ret
@@:
call clearMessageArea
call showBump
ret
.goDown:
mov al, byte [data_turtle.yPos]
cmp al, 22
jz @f ; collision detection
mov cursor.xPos, byte [data_turtle.xPos]
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
mov al, ' ' ; erase old face
string.putChar
mov al, byte [data_turtle.yPos]
inc al ; save new cursor position
mov [data_turtle.yPos], al
mov cursor.yPos, al ; update new cursor position on screen
mov cursor.xPos, byte [data_turtle.xPos]
screen.text.setCursorPosition
call paintPixel ; paint pixel if enabled
mov al, turtleFace ; display new face
string.putChar
ret
@@:
call clearMessageArea
call showBump
ret
.goLeft:
mov al, byte [data_turtle.xPos]
cmp al, 0
jz @f ; collision detection
mov cursor.xPos, byte [data_turtle.xPos]
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
mov al, ' ' ; erase old face
string.putChar
mov al, byte [data_turtle.xPos]
dec al ; save new cursor position
mov [data_turtle.xPos], al
mov cursor.xPos, al ; update new cursor position on screen
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
call paintPixel ; paint pixel if enabled
mov al, turtleFace ; display new face
string.putChar
ret
@@:
call clearMessageArea
call showBump
ret
.goRight:
mov al, byte [data_turtle.xPos]
cmp al, 39
jz @f ; collision detection
mov cursor.xPos, byte [data_turtle.xPos]
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
mov al, ' ' ; erase old face
string.putChar
mov al, byte [data_turtle.xPos]
inc al ; save new cursor position
mov [data_turtle.xPos], al
mov cursor.xPos, al ; update new cursor position on screen
mov cursor.yPos, byte [data_turtle.yPos]
screen.text.setCursorPosition
call paintPixel ; paint pixel if enabled
mov al, turtleFace ; display new face
string.putChar
ret
@@:
call clearMessageArea
call showBump
ret
.paint:
mov al, byte [data_turtle.paintToggle]
cmp al, 0
jnz .paint.disable
.paint.enable: ; toggle bit to 1
mov byte [data_turtle.paintToggle], 1
call clearMessageArea ; clear message line
mov cursor.xPos, 0 ; "Paint enabled"
mov cursor.yPos, 23
screen.text.setCursorPosition
mov si, data_str.paintOn
call string.teletype
ret
.paint.disable: ; toggle bit to 0
mov byte [data_turtle.paintToggle], 0
call clearMessageArea ; clear message line
mov cursor.xPos, 0 ; "paint disabled"
mov cursor.yPos, 23
screen.text.setCursorPosition
mov si, data_str.paintOff
call string.teletype
ret
; ==========
exit:
.restoreScreen:
mov di, data_state.screenMode
mov al, byte [di]
screen.setMode
.return:
mov ax, 0x4C00
int 0x21
; ==============================
; === PROCEDURE SECTION ========
; ==============================
paintPixel:
pusha
mov al, byte [data_turtle.paintToggle]
cmp al, 0 ; if paint is toggled off, break
jz @f
mov cx, 1 ; else, set background color
mov bl, paintColor
screen.text.setCharacter
@@:
popa
ret
; ==========
clearMessageArea:
pusha
mov cursor.xPos, 0 ; position at 0, 23
mov cursor.yPos, 23
screen.text.setCursorPosition
mov al, ' '
mov bl, promptColor
mov cx, 40
screen.text.setCharacter ; clear prompt line
popa
ret
; ==========
showBump:
pusha
mov cursor.xPos, 0 ; position at 0, 23
mov cursor.yPos, 23
screen.text.setCursorPosition
mov si, data_str.bump ; show bump message
call string.teletype
popa
ret
; ==========
showHelp:
pusha
mov cursor.xPos, 0 ; position at 0, 23
mov cursor.yPos, 23
screen.text.setCursorPosition
mov si, data_str.help ; show help message
call string.teletype
popa
ret
; ==========
showPrompt:
pusha
mov bh, 0 ; position at 0, 24
mov cursor.xPos, 0
mov cursor.yPos, 24
screen.text.setCursorPosition
mov al, ' '
mov bl, promptColor
mov cx, 40
screen.text.setCharacter ; clear prompt line
mov cursor.xPos, 0 ; position at 0, 24
mov cursor.yPos, 24
screen.text.setCursorPosition
mov al, '>'
string.putChar ; display carat
popa
ret
; ==============================
; === DATA SECTION =============
; ==============================
data_state:
.screenMode:
db ?
data_turtle:
.xPos:
db start.xPos
.yPos:
db start.yPos
.paintToggle:
db 0
data_command:
.up:
db "up", 0
.down:
db "down", 0
.left:
db "left", 0
.right:
db "right", 0
.paint:
db "paint", 0
.help:
db "help", 0
.exit:
db "exit", 0
data_str:
.help:
db "up, down, left, right, paint, help, exit", 0
.paintOn:
db "Paint toggled on", 0
.paintOff:
db "Paint toggled off", 0
.bump:
db "Bump! Hit a wall", 0
.buffer:
db 10 dup (0)