-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathupdate.s
619 lines (574 loc) · 12.1 KB
/
update.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
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
; procedures relating to updating the buffer
;
; todo probably want to have a proc for updating previously seen tiles to another tile
; todo update rest of code to work with new byte (vram increment flag)
.include "global.inc"
.export buffer_tiles
.export buffer_seen
.export buffer_messages
.segment "ZEROPAGE"
endy: .res 1 ; for buffer seen loop
endx: .res 1 ; for buffer seen loop
prevx: .res 1 ; for buffer seen loop
; represents player sight distance (hardcoded for now)
sight_distance = 1
.segment "CODE"
; update draw buffer with new bg tiles
; this assumes scrolling in direction of player movement
;
; clobbers: all registers, xpos, and ypos
.proc buffer_tiles
; disable scrolling if we're at edge
jsr can_scroll_dir
beq start_scroll_buffer
jmp start_seen_buffer
start_scroll_buffer:
; buffer leading edges
jsr buffer_edges
start_seen_buffer:
jsr buffer_seen ; this is for tiles *on* screen not edges
rts
.endproc
.proc buffer_edges
; initialize ppuaddr for buffering edge
jsr init_ppuaddr
; clear leading edge(s) (assumes cannot be seen)
jsr update_ppuaddr
jsr buffer_edge
jsr update_ppuaddr
jsr buffer_edge
; reset ppuaddr to origin from buffering edge
jsr reset_ppuaddr
rts
buffer_edge:
; update scroll metaxpos and metaypos depending on player dir
jsr update_coords
lda mobs + Mob::direction
cmp #Direction::left
beq len_30
cmp #Direction::right
beq len_30
; going up or down, len = 32
lda #32
jmp update_draw_length
len_30:
lda #30
update_draw_length:
sta draw_length
; write ppuctrl byte, updating increment depending on direction
lda mobs + Mob::direction
cmp #Direction::right
beq inc_vertically
cmp #Direction::left
beq inc_vertically
; increment horizontally
lda base_nt
sta ppu_ctrl
jmp buffer_tiles
inc_vertically:
lda base_nt
ora #%00000100 ; increment going down
sta ppu_ctrl
buffer_tiles:
jsr start_buffer
ldx #$00
buffer_tile_loop:
sty draw_y
; check if we can see or already seen tile
lda metaxpos
lsr
sta xpos
lda metaypos
lsr
sta ypos
jsr can_player_see
beq load_seen
jsr was_seen
beq load_seen
; can't see, load BG for now
lda #$00
jmp update_buffer
load_seen:
jsr get_bg_metatile
update_buffer:
ldy draw_y
jsr append_buffer
; increment xpos or ypos depending on player dir
lda mobs + Mob::direction
cmp #Direction::right
beq inc_metay
cmp #Direction::left
beq inc_metay
; inc metax
inc metaxpos
jmp continue_loop
inc_metay:
; inc metay
inc metaypos
continue_loop:
ldx cur_tile
; check draw length
cpx draw_length
beq done
jmp buffer_tile_loop
done:
; write zero length for next buffer write
lda #$00
sta draw_buffer, y
rts
; increase or decrease ppuaddr depending on scroll dir
;
; in: scroll dir
; clobbers: x register
.proc update_ppuaddr
lda mobs + Mob::direction
cmp #Direction::right
beq update_right
cmp #Direction::left
beq update_left
cmp #Direction::down
beq update_down
;cmp #Direction::up
;beq update_up
update_up:
jsr dey_ppu
rts
update_down:
jsr iny_ppu
rts
update_left:
jsr dex_ppu
rts
update_right:
jsr inx_ppu
rts
.endproc
; todo not exactly working since player is moving in 16 pixel increments
; update metaxpos and metaypos depending on player dir for the bg tile
;
; in: scroll dir
.proc update_coords
lda mobs + Mob::direction
cmp #Direction::right
beq update_right
cmp #Direction::left
beq update_left
cmp #Direction::down
beq update_down
;cmp #Direction::up
;beq update_up
update_up:
jsr get_first_col
sta metaxpos
jsr get_first_row
sta metaypos
rts
update_down:
jsr get_first_col
sta metaxpos
jsr get_last_row
sta metaypos
dec metaypos
rts
update_left:
jsr get_first_col
sta metaxpos
jsr get_first_row
sta metaypos
rts
update_right:
jsr get_last_col
sta metaxpos
dec metaxpos
jsr get_first_row
sta metaypos
rts
.endproc
; initialize the PPU address to point to start address for buffering
; assumes ppuaddr is pointing to origin
.proc init_ppuaddr
; flip nametable if going right or down
lda mobs + Mob::direction
cmp #Direction::right
beq right_of_nt
cmp #Direction::down
beq bottom_of_nt
; origin works for going left or up
rts
right_of_nt:
; flip nametable
jsr inx_ppu_nt
; decrement x to get back to end of previous nametable
jsr dex_ppu
rts
bottom_of_nt:
; flip nametable
jsr iny_ppu_nt
; decrement y to get back to end of previous nametable
jsr dey_ppu
rts
.endproc
; reset the PPU address to point to origin
.proc reset_ppuaddr
; first reset to origin of screen
lda mobs + Mob::direction
cmp #Direction::right
beq reset_right
cmp #Direction::down
beq reset_down
; if we went left or up, we're already at origin of screen
rts
reset_right:
; flip nametable
jsr dex_ppu_nt
; increase x to get to origin
jsr inx_ppu
rts
reset_down:
; flip nametable
jsr dey_ppu_nt
; increase y to get to origin
jsr iny_ppu
rts
.endproc
.endproc
; update draw buffer with seen bg tiles
;
; clobbers: all registers, xpos, and ypos
; todo bug when hitting max tiles - 5, introduced by 8473542e9c2809cd4f8fe2cdb76bfcfa8a54fc46
.proc buffer_seen
; remember original ppu pos
lda ppu_addr
pha
lda ppu_addr + 1
pha
; set start & end x/y pos
set_startx:
lda mobs + Mob::coords + Coord::xcoord
asl ; multiply by 2
sec
sbc #sight_distance*2
bcc forcex
sta metaxpos
sta prevx
jmp set_starty
forcex:
lda #0
sta metaxpos
set_starty:
; get starty
lda mobs + Mob::coords + Coord::ycoord
asl ; multiply by 2
sec
sbc #sight_distance*2
bcc forcey
sta metaypos
jmp set_endx
forcey:
lda #0
sta metaypos
set_endx:
lda metaxpos
clc
adc #(sight_distance*2 + 1)*2
; check within bounds
cmp #max_width*2
bcs force_endx
sta endx
jmp set_endy
force_endx:
lda #max_width*2
sta endx
set_endy:
lda metaypos
clc
adc #(sight_distance*2 + 1)*2
; check within bounds
cmp #max_height*2
bcs force_endy
sta endy
jmp inx_ppu_start
force_endy:
lda #max_height*2
sta endy
; increment PPU X
inx_ppu_start:
ldy xoffset
inx_ppu_loop:
cpy metaxpos
beq iny_ppu_start
jsr inx_ppu
iny
jmp inx_ppu_loop
; increment PPU Y
iny_ppu_start:
ldy yoffset
iny_ppu_loop:
cpy metaypos
beq loop_start
jsr iny_ppu
iny
jmp iny_ppu_loop
loop_start:
; initialize draw_length
lda #(sight_distance*2 + 1)*2 ; increment by 1 for player
sta draw_length
;jsr next_index
loop:
; end when endy hit
lda metaypos
cmp endy
bcc loop_start_buffer
jmp done
loop_start_buffer:
; set vram increment
lda base_nt
sta ppu_ctrl
; start buffer
jsr start_buffer
; now we're ready to draw tile data
tile_loop:
sty draw_y
; update xpos and ypos with meta pos
lda metaxpos
lsr
sta xpos
lda metaypos
lsr
sta ypos
; ensure xpos and ypos is valid
jsr within_bounds
bne tile_bg
; check if we can see
jsr can_player_see
beq draw_seen
; draw seen tile, if already seen
jsr was_seen
; no tile was seen, draw bg
bne tile_bg
draw_seen:
; update seen tile
jsr update_seen
; success, draw tile
jsr get_bg_metatile
ldy draw_y
jsr append_buffer
jmp loop_nextx
tile_bg:
ldy draw_y
lda #$00
jsr append_buffer
loop_nextx:
inc metaxpos
lda metaxpos
cmp endx
beq loop_donex
; redo loop
jmp tile_loop
loop_donex:
; reset x
lda prevx
sta metaxpos
loop_next:
; store zero length at end
lda #$00
sta draw_buffer, y
; increment y pos
inc metaypos
; increment PPU row
jsr iny_ppu
; continue loop until batching finished
jmp loop
done:
; reset ppu addr
pla
sta ppu_addr + 1
pla
sta ppu_addr
rts
.endproc
; buffer the messages to draw buffer
.proc buffer_messages
message_ppu_offset = $20
message_ppu_start = $2C
ldx #message_ppu_start
txa
pha ; remember ppu index for next iteration
lda #0
pha ; remember message index
write_message_header:
; store next draw buffer index into y
jsr next_index
; write the message length
lda #message_strlen
sta draw_buffer, y
iny
; write the PPU addr high byte
lda #$23
sta draw_buffer, y
iny
; write the PPU addr low byte
txa
sta draw_buffer, y
iny
write_message_str:
pla
tax
; update tmp_message using stack var
txa
sta a1
txa
pha
ldx a1
jsr update_message_str
jsr buffer_str
sta draw_length
; add damage/amount
ldx a1
jsr buffer_amount
ldx draw_length
fill_loop:
cpx #message_strlen
beq finish_buffer
; done, fill with blank spaces
lda #$00
sta draw_buffer, y
inx
iny
jmp fill_loop
finish_buffer:
; store a length of zero at end, to ensure we can get next index
lda #$00
sta draw_buffer, y
continue_loop:
pla
clc
adc #.sizeof(Message)
tay
; end condition
cmp #max_messages*.sizeof(Message)
beq done
; increment ppu offset and add to stack
pla
clc
adc #message_ppu_offset
pha
tax ; for next loop iteration
tya
pha
jmp write_message_header
done:
pla
rts
; buffer amount to draw buffer
; increment x by amount tiles drawn
buffer_amount:
jsr has_amount
beq update_buffer_amount
; default condition
rts
update_buffer_amount:
; buffer number to draw buffer
lda messages+Message::amount, x
jsr buffer_num
clc
adc draw_length
sta draw_length
rts
.endproc
; update scroll amount
;
; in: scroll dir
; clobbers: x register
.proc update_scroll
; disable scrolling if we're at edge
jsr can_scroll_dir
bne failure
lda mobs + Mob::direction
cmp #Direction::right
beq update_right
cmp #Direction::left
beq update_left
cmp #Direction::down
beq update_down
;cmp #Direction::up
;beq update_up
update_up:
jsr scroll_up
rts
update_down:
jsr scroll_down
rts
update_left:
jsr scroll_left
rts
update_right:
jsr scroll_right
rts
failure:
rts
.endproc
; check mob dir to ensure we can scroll in that dir
;
; output: 0 if success
.proc can_scroll_dir
lda mobs + Mob::direction
cmp #Direction::right
beq check_right
cmp #Direction::left
beq check_left
cmp #Direction::down
beq check_down
;cmp #Direction::up
;beq check_up
check_up:
lda mobs + Mob::coords + Coord::ycoord
asl
; ensure we're not at top of dungeon
cmp #vertical_bound
bcc failure
; edge case for walking up from bottom of dungeon
cmp #(max_height*2) - (screen_height-vertical_bound)
bcs failure
jmp success
check_down:
lda mobs + Mob::coords + Coord::ycoord
asl
; edge case for walking down from top of dungeon
cmp #vertical_bound
beq failure ; edge case for going down
bcc failure
; ensure we're not at bottom of dungeon
cmp #(max_height*2) - (screen_height-vertical_bound)
beq success; edge case for going down
bcs failure
jmp success
check_left:
lda mobs + Mob::coords + Coord::xcoord
asl
; ensure we're not at top of dungeon
cmp #horizontal_bound
bcc failure
; edge case for walking left from right of dungeon
cmp #(max_width*2) - (screen_width-horizontal_bound)
bcs failure
jmp success
check_right:
lda mobs + Mob::coords + Coord::xcoord
asl
; edge case for walking right from left of dungeon
cmp #horizontal_bound
beq failure ; edge case for going right
bcc failure
; ensure we're not at end of dungeon
cmp #(max_width*2) - (screen_width-horizontal_bound)
beq success; edge case for going right
bcs failure
jmp success
failure:
lda #1
rts
success:
lda #0
rts
.endproc