-
Notifications
You must be signed in to change notification settings - Fork 0
/
mapact.s
582 lines (499 loc) · 14.8 KB
/
mapact.s
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
/*
* Dragon - Map actors (enemies and objects), backend
* Copyright (C) 2017 Sandor Zsuga (Jubatian)
*
* This program 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/>.
*/
#include "m74cfg.h"
#include <avr/io.h>
; (Needed only for register names X, Y and Z)
.section .bss
v_store: .space 108 ; Active actor storage (12 x 9 bytes)
v_avail: .space 32 ; Availibility bitmap (256 bits)
.equ v_drx, MEM_LOC_0 ; Dragon X location + 192 (low, high) (Right of 384 x 384 active region)
.equ v_dry, MEM_LOC_2 ; Dragon Y location + 192 (low, high) (Bottom of 384 x 384 active region)
.section .text
/*
** Initializes the storage with all active actors cleared (free) and all
** non-destroyed. The dragon sprite is used to set up initial dragon location.
*/
.global mapact_init
mapact_init:
; Store dragon location
ldi ZL, lo8(dragon_spr)
ldi ZH, hi8(dragon_spr)
ldi XL, lo8(v_drx)
ldi XH, hi8(v_drx)
ld r24, Z+ ; Dragon X low
ld r25, Z+ ; Dragon X high
subi r24, 0x40
sbci r25, 0xFF ; Add 192
st X+, r24
st X+, r25
ld r24, Z+ ; Dragon Y low
ld r25, Z+ ; Dragon Y high
subi r24, 0x40
sbci r25, 0xFF ; Add 192
st X+, r24
st X+, r25
; Clear active actor storage
ldi XL, lo8(v_store)
ldi XH, hi8(v_store)
clr r25
ldi r24, 12
inicl0:
st X, r25
adiw XL, 9
dec r24
brne inicl0
; Clear availability map (to all available)
ldi XL, lo8(v_avail)
ldi XH, hi8(v_avail)
ldi r25, 0xFF
ldi r24, 32
inicl1:
st X+, r25
dec r24
brne inicl1
ret
/*
** Polls a ROM source for actors which should be activated, and activates them
** as necessary or possible. The ROM source is specified by its start address,
** the type of actors it should provide and the ID of the first actor within.
** Activated actors start with their User Data being zero. Returns the number
** of actors within the source added to the passed ID.
**
** Inputs:
** r24: id
** r22: typ
** r21:r20: src
** Outputs:
** r25:r24: id + no_of_actors (r25 zero)
*/
.global mapact_pollsrc
mapact_pollsrc:
push r2
push r3
push r4
push r5
lds r2, v_drx + 0
lds r3, v_drx + 1
lds r4, v_dry + 0
lds r5, v_dry + 1
movw ZL, r20
ori r22, 0x80 ; Add occupied flag
ldi r18, 0x0C ; Initial absolute X
ldi r19, 0
ldi r20, 0x07 ; Initial absolute Y
ldi r21, 0
clr r1 ; Make sure this is zero (although required by C)
mov r23, r24
rjmp psrl0e
psrl0:
inc r23 ; Next ID
psrl0e:
; Load next actor (or exit at end of list)
lpm r25, Z+
sbrs r25, 7
rjmp psra ; To absolute position input
mov r24, r25
andi r24, 0x70 ; Y position
add r20, r24
adc r21, r1
subi r20, 0x40
sbci r21, 0 ; Absolute Y acquired
andi r25, 0x0F ; X position
swap r25
add r18, r25
adc r19, r1
subi r18, 0x80
sbci r19, 0 ; Absolute X acquired
psrac:
; Activity check
movw XL, r2
sub XL, r18
sbc XH, r19 ; Subtract from right edge: should be between 0 - 383 for visibility.
subi XL, 0x80
sbci XH, 0x01 ; Subtract 384 to check if within the 0 - 383 visibility box
brcc psrl0 ; Not in visibility box
movw r24, r4
sub r24, r20
sbc r25, r21 ; Subtract from bottom edge: should be between 0 - 383 for visibility.
subi r24, 0x80
sbci r25, 0x01 ; Subtract 384 to check if within the 0 - 383 visibility box
brcc psrl0 ; Not in visibility box
; Too near check: a 256 x 256 box within the 384 x 384 visibility box
; where new actors shouldn't be created (they would pop out of the
; void).
subi XL, 0xC0
sez ; (sbci only clears Z to incidate Z for the whole result)
sbci XH, 0xFE ; Add 320, XH became zero if within the 256 px inner box
brne .+8
subi r24, 0xC0
sez ; (sbci only clears Z to incidate Z for the whole result)
sbci r25, 0xFE ; Add 320, r25 became zero if within the 256 px inner box
breq psrl0 ; If both X and Y is within, then within the 256 x 256 clearance box
; Availability check
ldi r25, 0x80 ; For selecting the bit
mov XL, r23 ; For selecting the byte
lsr XL
brcc .+2
lsr r25
lsr XL
brcc .+4
lsr r25
lsr r25
lsr XL
brcc .+2
swap r25
clr XH
subi XL, lo8(-(v_avail))
sbci XH, hi8(-(v_avail))
ld r24, X
and r25, r24
breq psrl0 ; Actor is destroyed, so skip
; ID check: If already active, do nothing
ldi r24, 12 + 1
ldi XL, lo8(v_store - 7)
ldi XH, hi8(v_store - 7)
psrl2:
adiw XL, 7
dec r24
breq psrl2x
ld r0, X+
ld r25, X+
sbrc r0, 7 ; Free slot (r0.7 clear): skip
cpse r25, r23 ; Non-free slot: Check ID
rjmp psrl2 ; ID not equal: skip (or free slot)
rjmp psrl0 ; ID equal: don't add again
psrl2x:
; Actor should be active.
; r19:r18: X absolute position
; r21:r20: Y absolute position
; r23: ID
; r22: Type & Priority (occupation flag added)
; Velocities, User data starts out zero.
; Check the RAM storage for the followings:
; r24: Free slot search
; r25: A low priority slot (if free slot search fails)
ldi r24, 12
ldi r25, 0
ldi XL, lo8(v_store)
ldi XH, hi8(v_store)
psrl1:
ld r0, X
sbrs r0, 7
rjmp psrl1f ; Free slot: search completed
adiw XL, 9
sbrs r0, 6
mov r25, r24 ; Low pri. slot found (r25: How far back it is from end)
dec r24
brne psrl1 ; When this exits, X == v_store + 9 * 12
cpi r25, 0
breq psre2 ; No free slot, no low pri. slot: Totally occupied, exit
sbrs r22, 6
rjmp psre2 ; Input is low priority: No further allocations will happen, exit
ldi r24, 9
mul r25, r24
sub XL, r0
sbc XH, r1 ; Step back onto low priority slot to occupy it
psrl1f:
; Free (or taken over Low Pri.) slot available, populate it
st X+, r22 ; Occupation, Type & Priority
st X+, r23 ; ID
push r23
push r22
movw r0, r20
movw r24, XL
movw r22, r18
call levelcor_encode
movw r20, r0
pop r22
pop r23
clr r1
st X+, r1 ; X velocity
st X+, r1 ; Y velocity
st X+, r1 ; User data 0
st X+, r1 ; User data 1
; Completed, go on with next data
rjmp psrl0
psra:
; Absolute position input (see above at Load next actor)
cpi r25, 0x7F
breq psre1 ; End of list
mov r21, r25 ; Absolute position input
lpm r19, Z+
lpm r18, Z+
mov r20, r18
andi r20, 0xF0 ; Y low part
ori r20, 0x07
andi r18, 0x0F ; X low part
swap r18
ori r18, 0x0C
rjmp psrac ; Go on to activity & availability checks
; Skim over the remaining objects to count them
psrsk:
lpm r25, Z+
lpm r25, Z+
psre2:
inc r23 ; Next ID
lpm r25, Z+
sbrc r25, 7
rjmp psre2 ; Was relative position
cpi r25, 0x7F ; End of list?
brne psrsk ; Was absolute position
psre1:
clr r25
mov r24, r23
pop r5
pop r4
pop r3
pop r2
ret
/*
** Fills up actor structure from an actor (from active actor storage). Returns
** nonzero if the actor does not exist (free slot). Fields in the spr member
** not used by the actor structure are left unchanged.
**
** Inputs:
** r24: no
** r23:r22: actor
**
** Outputs:
** r25:r24: 1 if actor did not exist, 0 otherwise.
*/
.global mapact_get
mapact_get:
cpi r24, 12
brcc getne ; Invalid actor number
ldi r25, 9
mul r24, r25
movw XL, r0
subi XL, lo8(-(v_store))
sbci XH, hi8(-(v_store))
clr r1 ; (For proper C interfacing)
ld r25, X+
sbrc r25, 7
rjmp getex ; The actor exists
getne:
ldi r24, 1
ldi r25, 0
ret
getex:
; Existing actor: populate the actor structure
andi r25, 0x7F ; Mask off type & priority
ld r24, X+ ; ID
movw r18, r24
movw r24, XL
movw ZL, r22 ; Actor structure
adiw ZL, 2
movw r20, ZL
adiw ZL, 4 ; Positioned at X velocity
movw r0, ZL
call levelcor_decode
movw ZL, r0
clr r1
ld r23, X+ ; X velocity
st Z+, r23
ld r23, X+ ; Y velocity
st Z+, r23
adiw ZL, 3 ; Skip xacc, yacc and flg members
st Z+, r19 ; Type
ld r23, X+ ; User data 0
st Z+, r23
ld r23, X+ ; User data 1
st Z+, r23
st Z+, r18 ; ID
; Return existing
clr r24
clr r25
ret
/*
** Destroys actor by ID. If the actor is active, it is removed from the active
** actor storage as well.
**
** Inputs:
** r24: id
*/
.global mapact_destroy
mapact_destroy:
; Clear availability bit
ldi r25, 0x80 ; For selecting the bit
mov XL, r24 ; For selecting the byte
lsr XL
brcc .+2
lsr r25
lsr XL
brcc .+4
lsr r25
lsr r25
lsr XL
brcc .+2
swap r25
clr XH
subi XL, lo8(-(v_avail))
sbci XH, hi8(-(v_avail))
ld r0, X
com r25
and r0, r25
st X, r0 ; Masked off actor availability (destroyed)
; Find and free actor's slot (or slots in case of some bug)
ldi XL, lo8(v_store - 8)
ldi XH, hi8(v_store - 8)
ldi r25, 13
clr r1 ; Make sure it is zero (for freeing)
desl0:
dec r25
breq desl0x
adiw XL, 9
ld r0, X
cpse r0, r24
rjmp desl0 ; Not the given ID, continue iterating
sbiw XL, 1 ; Back onto flags
st X+, r1 ; Free the slot
rjmp desl0
desl0x:
ret
/*
** Modifies actor by the given structure. Anything may be altered. If the new
** location is too far from the dragon, the actor is inactivated. If the given
** actor number is free, nothing happens.
**
** Inputs:
** r24: no
** r23:r22: actor
*/
.global mapact_set
mapact_set:
cpi r24, 12
brcc setne ; Invalid actor number
ldi r25, 9
mul r24, r25
movw XL, r0
subi XL, lo8(-(v_store))
sbci XH, hi8(-(v_store))
clr r1 ; (For proper C interfacing)
ld r25, X
sbrc r25, 7
rjmp setex ; The actor exists
setne:
ret
setex:
; Existing actor: populate from the actor structure
movw ZL, r22 ; Actor structure
adiw XL, 2 ; Position at pixel locations
ld r18, Z+ ; X pixel location, low
ld r19, Z+ ; X pixel location, high
ld r20, Z+ ; Y pixel location, low
ld r21, Z+ ; Y pixel location, high
movw r24, XL
movw r22, r18
movw r0, r20
call levelcor_encode
movw r20, r0
clr r1
adiw ZL, 2 ; Skip xbs and ybs members
ld r23, Z+ ; X velocity
st X+, r23
ld r23, Z+ ; Y velocity
st X+, r23
adiw ZL, 3 ; Skip xacc, yacc and flg members
ld r25, Z+ ; Type
ld r23, Z+ ; User data 0
st X+, r23
ld r23, Z+ ; User data 1
st X+, r23
ld r24, Z+ ; ID
sbiw XL, 9 ; Roll back to flags
ori r25, 0x80 ; Add occupied flag
; Check activity and remove if not active
lds ZL, v_drx + 0
lds ZH, v_drx + 1
sub ZL, r18
sbc ZH, r19 ; Subtract from right edge: should be between 0 - 383 for visibility.
subi ZL, 0x80
sbci ZH, 0x01 ; Subtract 384 to check if within visibility box
brcc setcl ; Not in visibility box
lds ZL, v_dry + 0
lds ZH, v_dry + 1
sub ZL, r20
sbc ZH, r21 ; Subtract from bottom edge: should be between 0 - 383 for visibility.
subi ZL, 0x80
sbci ZH, 0x01 ; Subtract 384 to check if within visibility box
brcc setcl ; Not in visibility box
st X+, r25 ; Finish writing flags & ID
st X+, r24
ret ; Active, so retain it and return
setcl:
; Inactive actor: remove it from the active actor list
st X, r1 ; Write zero into flags, so unoccupied
ret
/*
** Updates actors in relation to the dragon's changed location, removing
** actors which ended up too far from it.
*/
.global mapact_update
mapact_update:
; Store dragon location
ldi ZL, lo8(dragon_spr)
ldi ZH, hi8(dragon_spr)
ldi XL, lo8(v_drx)
ldi XH, hi8(v_drx)
ld r18, Z+ ; Dragon X low
ld r19, Z+ ; Dragon X high
subi r18, 0x40
sbci r19, 0xFF ; Add 192
st X+, r18
st X+, r19
ld r20, Z+ ; Dragon Y low
ld r21, Z+ ; Dragon Y high
subi r20, 0x40
sbci r21, 0xFF ; Add 192
st X+, r20
st X+, r21
; Iterate over the actors, and remove those which are not active.
ldi XL, lo8(v_store)
ldi XH, hi8(v_store)
ldi r25, 12
mov r0, r25
clr r1 ; Make sure zero, for freeing
movw ZL, r20 ; Dragon Y will be here
updl0:
ld r24, X
sbrs r24, 7 ; Occupied?
rjmp updl0s ; Unoccupied: skip calculations
adiw XL, 2
call levelcor_decode_asm
sub r22, r18
sbc r23, r19 ; Subtract right edge: should be between -384 - -1 for visibility.
subi r22, 0x80
sbci r23, 0xFE ; Add 384 to check if within visibility box
brcs updcl ; Not in visibility box
sub r20, ZL
sbc r21, ZH ; Subtract bottom edge: should be between -384 - -1 for visibility.
subi r20, 0x80
sbci r21, 0xFE ; Add 384 to check if within visibility box
brcs updcl ; Not in visibility box
adiw XL, 4 ; Remained active, go on
dec r0
brne updl0
ret
updcl:
sbiw XL, 5
st X, r1 ; Zero flags: Free slot
updl0s:
adiw XL, 9 ; Was a free slot, go on
dec r0
brne updl0
ret