-
Notifications
You must be signed in to change notification settings - Fork 0
/
newbies.txt
849 lines (691 loc) · 51.2 KB
/
newbies.txt
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
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
breakif {_scan>#262}
break ranoutoftime
ldy scanline ; 3
dec scanline ; 5
bne ; 3
; vs:
ldy scanline ; 3
dey ; 2
bne ; 3
sty ; 3 ... 11 cycles either way
... random enemy locations or at least random flapping
... then semi-random flapping with respect to players height
... okay, turns out randoms are hard. can keep my own polycounter in RAM and perhaps even feed it with POT input noise. but it looks like non-random is easier than random.
... maybe too much gap filling, but stuff rolls
... gap filling itself looks really solid
... maybe before/after? before should be caught by the INTIM cmp to 6
... adding another INTIM=0 test with a _vsync before jumping in to _plotonscreen seems to help
... what happends exactly when we fly off the edge of the world?
... it works perfectly! we can actually see the start of the world again before we cross the boundary.
... collision detection resets the joystick button latch when the player collides but there's no similar anti-flap mechanism for monsters
... maybe set a bit in tickcounter?
... can't flap if an odd number
... or make collisions() a sort of a subroutine that takes an X parameter and is capable of returning to one of two places
... for return pointer, caller is occupied with _vsync
... or just use X!
... stop handling collisions in-line but instead handle them by the caller
... collisionsreturn0, 1
... okay, continue to handle momentum cancelling/bounce in-line
collision_bits collision_platform ($ff if none)
collisions7 does _cleartrigger ... 00000010 00000001
... enemies should probably not hang down below platforms they're standing on; only draw them upwards from their exact spot
... might be fixed now
... enemy falls through the platform rather than coming to rest on it
... seems to work when the thing is first started, but dicking around with his position, this happened
... why can't I see the enemy fall from the sky?
... oh, now he rises from the floor
... but come to think of it, in real Joust, enemies did generate out of the floor
fps is wrong now; the thing is running too fast so there's more wrong than just having changed beq to bmi/bpl to draw the 0 scanline
59.55fps
renderdone happens on line 145 (previously was scanline 144... makes sense)
scoredone happens on line 154 ... that leaves 38 bonus lines plus 30 lines from overscan before vsync then 37 lines of vblank (previously was 152)
7.vsync1 262 (previously 260)
8.vsync0 37 (same)
... changed 127->125 for TIM64T at scoredone and that fixed it. not sure why the fps was so far off.
v/ _readstick needs to allow running along platform surfaces
v/ _momentum loops over all of the movable objects (currently two)
v/ _collisions need to iterate over movable objects
v/ collisions needs to not reset the joystick latches when monsters collide with things =P
v/ re-working the vblank logic, I broke joystick button latching (which is part of the vblank enable register)
... need to re-read how this is supposed to work
... okay, writing a 1 to D6 of VBLANK enables latching; once enabled (or reset by turning off then on), INPT4 and 5 are high but go low and stay low on fire
v/ physics is kinda fucked; revisit
... playeryspeed is not handled comprehensively
... handle as 2s compliment
... check carry/zero in gamelogic to enforce floor/ceiling
v/ the TIM32 timings are quite probably off by one or so
... vblank, vsync early/late, etc
v/ our imaginary dude should have some height; rather than a platform at the same height as us being shown at eye level, it should be offset downwards
v/ land on platforms, bounce off of platforms when going up.
o. steal physics from flapping.20050207.asm?
v/ the flap and gravity routines need to look through the list of platforms (ugh)
o. no, we maybe just need to remember the position of the platform we're above/below
... doesn't entirely help with running in to platforms, face first, but could be a good optimization
... for the sake of rendering things, deltaz and deltay are relative to our eyes; our feet are probably lower down
o. could do this while rendering, but it would take an extra memory location to record the results
v/ get the order of these right: _readstick _collisions _momentum
_collisions records which platform we're standing on in tmp2 and sets bits in tmp1 for other collisions
handles collisions in-line, such as by zeroing out or reversing momentum: playeryspeed, playerzspeed
collisions also reset the joystick button latch to keep the user from flapping
_readstick
modify playerxspeed playeryspeed
_momentum
apply momentum
apply gravity
cap downward momentum at terminal velocity
decay forward/backward momentum
o. write more tests
... need to test for more edge cases in plotonscreen
... what happens when we try to plot something of the same width
... what happens when gap filling tries to plot something with the same width as what's there
... there's some resolution loss there; the perspectivetable table has 128 entries but line widths in it only does up to 19
XXX could improve the resolution if we had duplicate entries in pf*lookup and used all five bits (up to 31)
... what happens when we try to draw another line in the same platform on top of lastline
$cpu->write_8( $symbols->platnextline0a+1, 16 ); directly determines whether shit gets fucked up or not. huh. how!?
... aha. needs *21* on the clock to always be safe. otherwise, there may or may not be enough time left.
... my guess is that it goes negative and beyond and the ranoutoftime check doesn't work properly so it keeps trying to do more lines
... output curplat, deltaz, lastline
... yup, correct. it continues on from deltaz=2 to deltaz=1
XXX okay, we need to make timer expiring logic more intelligent, one way or another
... if there's a lastline, make sure that abs(curline-lastline) > INTIM before we continue
... do at 779 a version of what we do at 787... ok
... at position 00, 0b, it runs for 266 scanlines
... apparently, INTIM will have 00 on it when control goes to vblanktimerendalmost but A will get loaded with $FC and it'll loop down to 0 again
... and caller is set to 1 when this happens
... so what was the scanline at when we return when caller is 0?
... 225 vs 224. so the first call is running long
... even though INTIM still has 5 on it at position 00, 0b
... 00, 03 does this too when different values are plugged in
... or else invert control like we were thinking of before
v/ invert control
... maybe we just need to be able to jump back in to the middle of the gap filling code and make that essentially our new 'platresume'
... if we do that, we need to take in to account the worst case scenario of having to find the next line of the next platform
... okay: use 'caller' to track of vblank/vsync steps in middle of gap filling, and bail there if we completely run out of time
... have to re-dispatch to one of two gap filling loops though! or else include the macro twice. or else update X/lastline so we can jump in to the top.
... X (curline) moves towards lastline. jumping in to the top should work.
... have to take in to account the ~4 ticks needed to seek to the next platform line
fetching timer with 27 left on it at .plot9 curplat=0 deltaz=4 lastline=43
fetching timer with 25 left on it at unknown location curplat=0 deltaz=3 lastline=43
fetching timer with 23 left on it at .plot_up1 curplat=0 deltaz=3 lastline=42
... this plan would make large amounts or all of 07_timer.pl obsolete
XXX still need to know/care about the worst case time if we have to seek from one platform line to another
... caller = 0 = still in drawable plus 30 lines of overscan, 1 = 37 lines of vblank, then go to drawing kernel
... search for references to vblanktimerendalmost; there are three
... still need to burn CPU cycles when/if we finish drawing the level
... test this
... how to include the _vsync macro in _plotonscreen?
... can't easily update lastline and come back in at the top, which would let us only include one copy: lastline gets updated from X, and we've been filling in and inc/dec'ing X towards lastline
... or else include the _vsync macro twice? A is available. _vsync leaves the flags reading non-zero. but this makes two branches go out of range.
v/ fix scanline count
... position 02, 20 (default starting)
... scanline is 36 at 2.vsync0, s.cycle 45; 37 after a wsync; good
... scanline is 259 at 1.vsync1; 260 after a wsync; vsync over 260, 261, 262; good
... position 00, 1D
... scanline is 36, s.cycle 42 at 1.vsync0; good
... scanline is 259, s.cycle 38 at 1.vsync1; good
... location 00, 00.
... platnext0 is hitting on scanline 175, 176, 203, and 248
... platnext0vblanktimer hits on scanline 248; INTIM is 0E
... huh. when we hit scanline 259, there's still 02 on INTIM.
... how on earth does the time expire at different times depending on whether we finish rendering the platforms or run out of rendering time first?
... with 1 tick left on INTIM, we're still on scanline 259
... when we finally hit 0 ticks left, we're at scanline 260 s.cycle 25
... ah. TIM64T is loaded right after scoredone. at scoredone, we're already a scanline behind.
... we're on scanline 152 s.cycle 0 at 'score'; 00,1D hits 'score' at scanline 151 s.cycle 0
... 00,00 hits startofframe at scanline 36 s.cycle 38; 00,1d hits it at scanline 36 s.cycle 45; same
... 00,00 hits 'platforms' at scanline 39 s.cycle 62; 00, 1D hits it at scanline 38
sta WSYNC ; scanline 38 (second drawable but again we don't draw anything)
jmp renderpump ; always <-- XXXX aha! that was a bne but playery right shifted twice could be zero or non-zero
... location 00, 00, redux
... hits startofframe at scanline 36 cycle 48
... scanline 37 at the immediately following WSYNC
... scanline 38 at the WSYNC after storing tmp2
... scanline 38 cycle 32 right before the first 'platforms' WSYNC
... scanline 39 right after the first 'platforms' WSYNC
... hits 'score' at scanline 151 cycle 0
... hits 'scoredone' at scanline 158 cycle 66
... 02, 1C was still fucking up
... 'startofframe' happens at scanline 36 cycle 49
... hits 'renderpump at scanline 38 cycle 3
... hits 'platforms' at scanline 38 cycle 32
... hits 'score' at scanline 151 cycle 0
... hits 'scoredone' at scanline 158 cycle 66
... hits 'platnextline' with INTIM with 0 on it already
... too bad it isn't easy to test things to see if they're exactly equal to 1
... scanline flips from 259 to 260 at 'platnextline0a' (cmp #5)
... there are still 0C clicks (machine cycles) on the counter before it goess to $FF
... makes sense that the 64 machine cycles covering the duration of the timer being '0' won't perfectly overlap with the middle of a scanline but instead will partially span 2
... hits the 'beq .vsync1' in _vsync (2nd instruction in there) right as INTIM goes to $FF
... hits '1.vsync1' at scanline 260 cycle 14 -- late!... INTIM is $FC at that point, apparently having wrapped.
... not sure what I can do here other than not waste cycles and maybe WSYNC immediately
... that seems to fix this one case
... yup, we're at scanline 259 cycle 57 at the start of the "do this immediately" STA WSYNC instruction inside _vsync; there are 1D ticks left on the timer
x. instead of drawing fat lines for each platform line, find the starting and ending scanlines of the visible portion of a platform and then
interpolate between them
... XXX starts of platforms behind us will be rendered; have to take care in plotonscreen not to draw outside of the framebuffer!
... ugh, do not want to deal with that... they can't be behind us. can't do neg deltaz. have to render in perspective.
... so we have to clip the line.
... let's maybe revisit this later.
... addressed this by having _arctan clamp deltay = deltaz and deltaz = 0 cases to the very top or bottom of the screen
x. write a large scale test that calls platlevelclear
... some of all of the three test platforms are drawn
... they're drawn starting and ending on the display where they're supposed to be
x. bug: why won't it render the one platform when there is only one platform in the level?
... is it rendering all of the platforms right now? haven't taken a close look at this
... this antique bug probably went away by way of other changes
... yup
x. I think the arctan Y=0 logic isn't working; platforms disappear entirely when they're dead center in middle of the screen
... 02_arctan.pl thinks its working
... still, wouldn't hurt to have more tests to make sure it actually gets rendered
o. XXX plotonscreen *might* run into a spot of bother when arctan stuffs scanline to 0, and then 0 gets stored as lastline, so then it doesn't there to be a lastline
... actually, that should be okay
... after stuffing scanline to 0 or viewsize-1, plotonscreen shouldn't be called again
... a lastline of 0 will just cause it to not try to do any gap filling, which is fine
... rendering in 72 cpu cycles now
x. unit test cycle counts
... unit tests to make sure we plot a platform or two within a fixed number of cycles so we know if we accidentally make it really slow again
... done; tracking cycle counts in the commit messages
... get 04_runtime.pl going with per-instruction (typical) cycle counts
... done
x. with the revised deltaz loop control (allowing deltaz=0 and deltaz = deltay), when deltay=deltaz=0, it'll keep rendering that platform over and over
... platrenderline checks ( deltay <= deltaz ) work fine with deltaz = deltay = 0
... .platlinedelta stuffing works; Y is positive so scanline gets stuffed as #0
... in .platlinedelta, maybe we need to first stuff case of the deltay = 0 before we look at other stuffed cases
... yup
... make sure we aren't rendering with deltay > deltaz again
... working on that in 05_times2.pl
... yup
# supposedly, there are 5320 machine cycles total available during vblank and overscan
9263 down from 10444 down from 10554 down from 10729
9456 down from 10744 down from 10898 down from 11216
5800 up from 5780 down from 5835 down from 5956
8674 down from 9878 down from 10163 up from 9988
5885 down from 6262 down from 7499 up from 6526
x. we can't ever actually get on a platform; there's always a gap of sky/background below it
... for one, we do need to render one chunk of the platform that's behind the player if only so that we can gap fill to it; ugh, that's gunna be ugly
... arctangent needs to start with z=0 I guess
... looks like we lose noticible precision that way; not sure
... hard-code checks for when deltaz = 0 in plotonscreen to automatically clamp the line to the very top or bottom?
... but not in plotonscreen; it doesn't take deltax/y; arctangent does
... add a special path that skips _arctan and goes straight to plotonscreen when deltaz = 0
... platrenderline does a jmp platnext if deltay > deltaz check
... platnextline does jmp platnext if deltaz - 2 < 0 check
... ugh, we know where to plot the platform bit (very top or bottom), but we don't know how wide to make it
... need a hypot with z=0
... another small table perhaps, just of those?
... also, _plotonscreen is a lot to inline, and it's only a macro right now
... no problem, just branch back to it and treat deltaz=0 as one last go and deltaz<0 as done condition
... we want to skip arctan but maybe not plathypot; distance away tells us fatness of line to draw
... it might be easier to rig plotonscreen to clamp the line one way or the other if deltaz=deltay... or insert logic before the call to it
... and save the extra _plathypot macro call
... we still want to stop looping when deltay > deltaz so we don't waste CPU
... yup, works
x. plotonscreen is kind of fucked; little changes (and new features) radically change what gets drawn when they're enabled/disabled
... but unit tests aren't picking up on any differences in what gets plotted when branching to plotonscreen3a or plotonscreen8 is enabled when drawing to lastline
... differences in what gets rendered seems to have been in the past largely influenced by run time and it running out of time to render things
... things should be much better in that regard now so I'm not sure what's up
x. use unit tests to figure out how long rendering takes in different circumstances.
o. get some banding going for sky / horizon
... go into rarified air where it starts to get black and spacey at high levels
... maybe greenish ground instead of brown
... need to move padding to the top too to balance it out
... add the players Y position to the 'background' table index
... need to cap off players Y height otherwise the platforms start repeating and we run out of background material
o. observed deltaz=0 while debugging shorter lines overwriting wider ones; maybe that's the problem? if not, have to reproduce this view angle
... playerz=0, playery=$23,
... this is likely gone now, fixed in dfab7f
x. shouldn't be calling arctan with 0s for deltas since part of the formula the table is generated with is atan($z/$y)
... calling it with two 0 deltas will make it run forever; okay, it handles this special case now, though I wish I didn't have to spend the CPU cycles
... swapping Y and Z could avoid a division by zero if we stop following the platform when deltaz == 1, which we currently do
... the way the table is computed and used now, Z will always be >= 1 and Y no longer needs a special case as the table handles it correctly
x. make the arctan table two pages long instead of one for more precision?
... skipping this one as the 256 byte utilization instead of 128 byte seems pretty good
x. write tests
... z-buffering -- drawing over stuff and failing to draw behind stuff
... lastline being updated or not updated as appropriate
... gap filling with correct color
$cpu->set_pc($symbols->platlevelclear);
$cpu->write_8( $symbols->deltaz, 10 );
$cpu->write_8( $symbols->deltay, 2 );
$cpu->write_8( $symbols->INTIM, 0x10 ); # stuff a value in the timer output so platform rendering doesn't think its out of time
x. readstick isn't currently keeping Y from going below 0 and that trashes things as soon as it goes below 0
... kinda in the process of reworking readstick and gamelogic
... playery higher than $2c or so also keeps it from redrawing even if we go back down
... huh, jsr'ing to platlevelclear instead of platresume in the first of three calls makes it able to recover
... readstick now limits Y, and some serious bug thrashing seems to have cleared up the redraw and garbage problems
x. the thing is currently rendering a lot of width 0 stuff; this gets drawn as nothing on the display; this is probably a fuck-up with the arctan lookup
operating without bounding
... actually, the test was bunk; was testing the zero bit to test if A was zero, but it didn't match, so stats were off; actually doing no zero width platforms
x. testing making no calls to platresume and that seems to be working pretty well; maybe I should do an experiment and have it count how many lines it does
... $0e or so. not many. okay, $14 with the first jsr platresume after the jsr platlevelclear enabled. same ($14) with the 3rd platresume enabled.
... after add gap filling logic to plotonscreen to replace the fatlines logic, it is drawing fewer platforms but says $1C lines considered (28);
it's also drawing everything forward of our position so many of those probably aren't visible
x. observing a lot of garbage being drawn that isn't platform
... aha, curplat is going way past 08; not detecting the end of level0 properly
... break on platnext0
... okay, it's fine until we return and platresume is called again
... fixed; on resume, check to see if we're off the end of level0
x. hey, wait... deltaz is apparently counting down to 1 for all platflorms, not just the ones we're standing on
... dec deltaz ; deltaz goes down to zero; ... not always! only when it isn't off in the distance!
... how does this look right at all?
... platfound initializes deltaz with level0+1,y - playerz
... changed it to count down to level0+0,y - playerz and stop
... hey, the platforms got a lot shorter. I guess it really was just drawing them until it ran out of CPU!
... so that's where all of the CPU was going! it really looked right, too. huh. crazy.
... okay, now it's really, really fast; it creams through the three platforms during the first call and finishes with lots of time left on the clock
x. egads, how many times do we draw a bit platform over a bit of the same platform?
... interpolating between start/end is starting to look more and more appealing
... $15 times; not terrible; still...
; how often do we draw a bit of platform over a bit of platform of the same color?
lda view,x
and #%1110000
ldy curplat
cmp level0+3,y
bne testytest
inc num0
testytest
x. I think I have z-buffering hooked up backwards! low numbers are far away
... well, flipping the sense of it makes it draw nothing on the plain background, and tracing it, it does the right thing in the case of the plain background
... correct in the case of 8 being in the frame buffer and it wanting to draw a 9 there
x. reconsider trying to enforce a 45 degree viewing angle; we're rendering up to $1E platform lines and can't stuff the green platform off in the distance any more
... done; this speeds things up a lot
x. remember the last scan line we drew a line on so we can fill in the gaps when we draw the next line.
... need to handle the case where lastline-curline is +/- 1 and not recurse so we don't clobber a narrower line with a fatter line... okay
... after this, we had to bump up our INTIM check from 7 to 9 (128 more cycles) to avoid screen jump; we're rending up to $1C lines but we can't see
the far away green platform at the start any more
... also, closer things aren't being rendered when they should
... could at least shave some cycles from plotonscreen so we can put INTIM back down to 8 at least
... upwards of $29 gap lines are filed in (or depth checked to see if they can be filled in); this is waaay too many
... is there a black platform...?
... even skipping the terrible zero width platform pieces, I'm seeing $28 bits of gap filled in though the green platform bit starts to show up again
x. with some inc num0 logic, I'm not finding any cases where 255/out of range stuff is being returned from arctan; dropping the error checking
x. really not convinced we're getting 111 lines of display; is the 45 degree angle check to blame? what is the real range of the hypot table?
... go through this rendering logic again
... angle = atan(y_delta/z_delta)... delta_z must be greater than (>) delta_y or it's out of our 45 degree range
... yeah, that 45 degree check, or some related logic, was screwing us up there; still want to go through all of the rendering math and check things
... okay, we were *not* getting 110 lines of display; the arctan table has to be generated for the lines since it returns the scan line number
x. get rid of marksweep in favor of just blanking at the start of the frame and redrawing
x. jmp platnext ; XX experimental -- on the same level as the platform? don't show it. sucks that our arctan table doesn't have any 0s in it so this case can be handled correctly, but maybe that can be tweaked.
^--- fix this somehow; maybe treat the platform as if it is 1 lower than us while we're exactly on it
x. lda playerzspeed ; this is 1.4.3 fixed place
^--- make not 1.4.3 and I don't think it is anyway
x. rename plattryline to platrenderline since that's where the rendering happens
x. curline and deltaz are probably redundant with each other as well and one could be eliminated
... probably eliminate curline since a lot of routines use deltaz directly and its more immediately useful
x. get rid of the platstart variable
... we can get rid of platstart if we skip the optimization where we figure out which line of the platform is the first one we can see
... I don't think this will hurt us too much
... then we'll just be working from level0,1 backwards to level0,0
... curline starts at level0,1 and goes towards level0,0
... we stop using tmp1 which was platend, which was actually the platstart, which is level0,0
... okay, now curline just moves straight from level0,1 to level0,0
x. try to get rid of curlinewidth?
... easily done; saved once, loaded once, with no tmp destructive routines in between
... oops, mostly did this with abusing the S register but didn't quite finish it; trying to take it out entirely made things glitch
... okay, except for the fatlines logic that's commented out, this is done
x. get rid of all of these jsrs to save memory
x. rework so that the level0 data structure includes platstart and platend rather than platstart and platlength; simplifies logic/temp usage a bit
x. try to get rid of deltayneg and instead do 2's compliment like god intended?
... playery - platform height ... > 0 = platform is below us, < 0 = platform is above us
... previously, if the platform was higher than the player, we redid the math and did platform height - playery
... routines using deltay
... arctan
... plathypot
... platlineseek, to figure out if a line is as far ahead of us as it is above/below us to compute a 45 degree viewing angle
... fatlines
x. in platnext:
; this leaves this uninitialized; don't do this
; lda INTIM
; cmp #8
; cmp #9
; bpl platnext0
; jmp vblanktimerendalmost ; not enough time left to start another platform
jmp platnext0
.. in platlevelclear: sty curplat ; XXX don't reset to 0; create a variable for current platform player is on and use that instead
... not sure about that. don't want to create a new variable, and skipping past stuff we can't see should be pretty quick or we can make it quicker.
x. try to get rid of curlineoffset?
... plathypot is called right after it is computed, and that uses tmp1 and tmp2
... keep in the stack pointer register?
... yup, totally worked
x. iny ; move to the platform length <-- this is silly
do this instead: lda level0+1,y
x. platlinedelta can be in-lined; only used one place
... did it with a macro
x. attempts to make deltaz an alias to tmp1 have failed; not sure why that won't work; a lot of these vars look like they can be cut down
aha... plathypot makes heavy use of deltaz, deltay, tmp1 and tmp2; mucking that all up
x. platresume is called from three places; are we over-running the timer in any of them?
when the time is less than $30 ($30 * 64 CPU cycles), we stop doing lines
$11, $b5
$16
$00, $16, $90 (probably an overflow), $b9 (probably an overflow; called from where #$2a = 42 is stuck in TIM64T)
$12 when TIM64T is loaded with $5F
$14 when TIM64T is loaded with $22 ($22 is less than platresume_timer_ticks_need, which is $30)
$B5 when TIM64T is loaded with $2A ($2A is less than platresume_timer_ticks_need)
$06 when TIM64T is loaded with $5F
$14 when loaded with $22
$B5 when loaded with $2A (probably overflowed) ... watch it overflow?
$11 when loaded with $5F
... okay, loaded with #$22, tracing...
... $20 ticks left on the timer by the time we hit platfound
... it does a line before checking what's left in the timer
... $1F at platlineseek
... $1E at platlinedelta
... $1D at plathypot
... $1C at plotonscreen
... $1B at platnextline
... fatlines
... oops, by platnextline a few times as the thing continues to wind down; platnextline is where INTIM is checked and compared to hard-coded #6
... platnext also compares INTIM to #8
... platlevelclear compares INTIM to platresume_timer_ticks_need which is currently 48 (!!)
... so it looks like maybe we can only check in platnextline and be okay
... nope
... still, platresume_timer_ticks_need is stupid. that's the time we think it takes to render all platforms. doesn't fit with large/varied levels.
... okay, got rid of platresume_timer_ticks_need and it now only exits at platnext or platnextline on very small remaining timer values.
... platresume_timer_ticks_need was really only useful because it kept it from marksweeping and restarting when it didn't have time to finish
... and that avoided flicker from doing multiple restarts and marksweeps in the same frame with the second not finishing
... had to rework; marksweep is called once at the end of the frame rather than every time it hits the end of the level; that works right now but isn't 100%;
... if it takes more than two frames to draw the screen, stuff will be prematured deleted
... marksweep should only be done at the end of the frame if the thing has since rendered all of the platforms start to end
... vblanktimerendalmost counts how many loops it has to do before the timer runs down to zero; with the hard coded values plugged in now, it's between 9-24
x. why the hell do we jsr gamelogic in platlevelclear2?
... apparently just because that's the point where it's kind of done with things in there
... fixed
x. in platrumes, don't iterate until the end of all of the platforms but instead do a fixed number of platforms or work for a fixed number of frames
... to better accomodate large levels and wrap-around
... maybe no wrap-around for a platformer
... okay, it only goes to the end now and doesn't attempt to restart until explicitly told to
x. marksweep should only be done at the end of the frame if the thing has since rendered all of the platforms start to end
... otherwise, if it takes more than two frames to draw all of the platforms, stuff will be premature deleted
... or else just clamp down how much data we render (eg, only 100 lines of data) and then stop and call it good; yeah, even better
... looks like we have *plenty* of time right now to redraw platforms completely for the frame
... but the platform draw logic should also draw enemies
... getting rid of mark sweep would free up that bit
... that bit could potentially be useful for marking up sprite data
; after finding the first platform, seeking, and one divide, INTIM reads #$23 (35). starts at #$2B (43).
; update: after doing the first platform's first line with the z/y atan table, INTIM reads #$27. better.
; 76 cycles per line, 37 vblank lines, for a meager 2812 cycles
done:
; todo: add clause for ignoring platforms *too* far away, or else let CPU be the limiting factor
... cpu is the limiting factor
; done: figure out how many frames it takes to draw in a screen, then every that many frames, actually read control and blank the screen
; done: count generations (vblanks) and don't redraw everything more than once...
; idea: store a "display list" type thing with instructions: how many lines to repeat the same thing;
; then color to change, width to change to, and width delta (+/- width with a small fractal part) each line.
; this would allow double buffering, quicker rendering of the platforms (bresenham), etc. since there's only
; about three platforms on the screen right now, this would be a very short list.
; idea: joust...? left/right turns you around, forward makes you run on a platform, button flaps, of course
; or no turn-around initially, since that would require rendering the level from the opposite perspective
v/ we stop filling gaps when we start running low on CPU. is there a better way to handle this?
... fill gaps faster and don't even attempt to draw a line of a platform unless there's lots of time left on the clock
... not perfect
.............
toggle debugger mode in stella is `
enter options menu mode is TAB
enter ROM launcher is escape
quit is control-q
......
76 (228/3) CPU clock cycles per scan line
3 lines of vsync, 37 lines of vblank, 30 lines of overscan = 70 lines * 76 CPU cycles = 5,320 game logic cycles
in this order: vertical sync, 192 lines of actual picture, then overscan
there are 22.6 cpu cycles each line after hsync and before the actual picture area
..........
there are viewsize lines (currently 101)
102 is score display setup
103-111 in score display itself
112 in score display teardown
................
... can we read the value back from TIM64 to figure out where we're at instead of storing data in 'caller'?
... can read the current value back, but it counts down
... I think. stella's debug view suggests otherwise. XXX revisit this if we want to try to save a byte.
o. 3D glasses support; use alternating sets of pf*lookup tables for left and right eyes
o. the plotonscreen rule where it skips drawing if the new line is in the same position as lastline isn't great when deltay = 0
... the platform is drawn only at its shortest point, not the nearer widest
... ignoring this as that's only a moment of the animation and the next and previous frames will look okay
... and if you see if the leading edge of the platform on deltay = 0, then you're not going to land on it anyway
; todo next: sprites. nice thing about first person is we don't need to draw ourselves! so we can realistically have
; two enemy birds flying around. enemy birds are going need x, y, and at least one velocity.
; clipping will be a bitch!
; near/in gamelogic, make the enemy bird fly
; compute distance with the current deltay, deltaz vars and arctan table
; peek into the framebuffer and see if there is something nearer than them
; modify the inner loop to show a damn sprite or two... vary the colors, width, and graphics... good luck!
; todo: game logic is very rough. besides floating down, we also seem to float back to the start of the level!
; todo: give the player a point every time they kill a bird!
; todo: waves. when the birds are dead, pause a moment, and create more!
o. DCP Plus demo shows how to use the Pitfall 2 custom hardware (supported by Stella, Harmony, and Melody) which has fast fetchers and overrides lda #xx! awesome!
o. too bad it doesn't override sta instead =P
o. replace this code for disabling sprites with something that shows a sprite or two:
sta PF0
sta PF1
sta PF2
lda #%00001110
sta COLUPF
... should be easy to decide whether to hide/show a scanline of player data; compare the Z position of the player to the width (distance) of the platform piece
o. _plathypot could probably be optimized
o. let's turn this into a sort of freerunning first person platformer
... Integral Trees-ish?
... very low gravity
... lots of stuff to jump off of
... springy stuff too!
... try to maintain altitude
... omg! vines to swing on, pitfall style?
... "Sky Castles" ... sky castle theme... use a sprite to render off in the distance castleage
... sometimes the user can flap a bit (mario style get a run for it and fly for a while), sometimes for a limited time they can fly around, sometimes only jump
... some kinds of power ups or something; changing bodies?
... philosophy: create a machine that's fun to play with
... would be fun to have things occasionally falling from the sky
... lob things on an arc to hit switches of some sort to raise grates and divert water?
... bouncing big ball things kicking around?
... shoot arrows to flip switches and kill knights?
... platforms that move around?
o. maybe rather than the platforms being solid colored, make them striped as in Atari 2600 - Demoscene - 02 - Ataventure - Atari 2600 demo by Kk Dma.mp4
... could use the specified platform color when drawing the main lines and then fill gaps with another (black? level0+5,y?)
... also Atari 2600 - Demoscene - 04 - Trsi Digital Sounds System Crest - aTaRSI (2013) Atari Vcs.mp4 shades things darker when they're further away -- nice!
... the background should also be shaded and colored
... probably as a function of playery
o. shade platforms darker when they're further away
... drop off to darkness should be logarithmic
... good thing we already have a lookup table
... platforms with different colors on the top and bottom?
... key platform pf bitmap graphics off of color plus width (use the whole scanline value) to draw different shape platforms
... such as round things
... yup, bitmaps for the platforms
o. maybe make the ground greenish rather than brownish
... or maybe we're above water
o. plotonscreen would let us draw veritcal bars such as tree trunks
... leafy vines
... metal grates
... brick walls
... waterfalls
o. need to get sprite rendering going too
... we have 14 cycles free right now.
... if that isn't enough to pull sprite data from the frame buffer, then at least it should be enough to:
lda (spritedata_pointer),y ; 5 cycles
sta GRP0 ; 3 cycles
... low byte of the zero page spritedata_pointer would have to be modified during vblank rendering to position the sprite
... would use 200 or so bytes of data for the sprite rather than enabling/disabling it; that makes animation prohibitive
... would be to cool to, if the 0 bit (eg) is clear, then instead of doing platform rendering, do sprite rendering using the other 7 bits of data!
... existing platform/background data could just repeat for that line
... sprite data would be explicitly turned off and explicitly updated but otherwise itself would just repeat
... that would make for tall, skinny, stretched out sprites
o. make the top 1/3rd and bottom 1/3rd of the screen have 2 scan line resolution while the middle still has one
... warp the arctangent table
... run two different kernels
... this would help a lot with gap filling to the edges of the screen which is currently eating up obscene numbers of cycles
o. really need to lock it down to an odd number of scanlines; otherwise, we can't +/- any number in arctangent without walking one off the end when adding
... currently at an odd number
ROM bytes used up to $fa0e ... that's almost 2/3rds full
ROM bytes used up to $fb0e ... after collision detection, flapping, joystick control
0xffff - 0xfb0e is 1265, or just over 1k left of our 4k.
XXX maybe move shading to render time, and alternate between two colors for each line of platform?
XXX this would make the display kernel faster but require more bits in RAM for color
o. references to level0 in code might get changed to indirect through a zero page pointer; eg
lda level0,y ; load the first byte, the Z start position, of the current platform
to: lda (level0),y
... if we want moving platforms.
... future game?
o. some platform colors bounce, some teleport...? or are we just doing Joust?
o. could be implemented with collisions_platform
o. computer players
o. x,y,xspeed,yspeed,dead_respaw_time
o. decision to flap based on whether they're eye level with a platform that's near, and based on whether they're eye level with the player who is near
o. collision detection with player
collision_bits and collision_platform are redundant with the new plan of reseting the joystick button latch and and zero'ing momentum, but they're handy for the unit tests
XXX playerz A4 and playery 0 (and other values) shows render artifacts
XXX need to rate limit flapping with some kind of a timer or something
XXX readstick1, readstick2, readstick3 are exactly the same except for a constant value they use. should table-ize the flap_z values and index it by joystick bits.
XXX _collisions needs to detect collisions with enemies as well
... okay, it does, but it doesn't do anything with this knowledge.
XXX there are visual artifacts (garbage pf data) when we're far away from the platforms. wrote 10_...pl to test for this.
XXX bcs gamelogic2 ; don't write back to playerz if this addition would take it above $ff XXXX actually, wouldn't this be the win condition for the level?
XXX beq gamelogic4 ; don't write back to playery if this subtraction would take it to zero; XXX actually, wouldn't this be the death condition?
num0 could be eliminated
arctan needs to be callable as a subroutine
not *too* long; could re-use the macro
computedreturn/returntable/return0, return1, return2 is the alternative
we have this caller variable that's used in the _vsync macro; it could be re-used, but collision_platform and collision_bits would get clobbered
v/ can we do without collision_bits and collision_platform? do we actually use those in logic anywhere? if only in tests, then it's okay if a faked RTS clobbers them
v/ shit. _readstick in readstick8 needs to know if we're on a platform.
v/ I guess a hackish work-around would be to assume that if ymomentum was zero, we're standing on a platform.
XXX draw enemies on the screen
XXX _arctan takes deltaz and deltay and returns a scan line number; need to call this as a subroutine of sorts to figure out which scanline to draw the enemy on
XXX _plotonscreen needs to be callable as a subroutine or else I need a smaller simplified inline version that doesn't do lastline gap filling
XXX unit test enemy momentum and collisions?
_drawenemies inline _arctan again custom _plotonscreen
and #%00011111 ; mask off the color part and any other data
in the low five bits of stuff in view[], 0..19 is valid, but those five bits can hold 0..31.
are there some indexes that just never get used? (0 is not drawn, 19 is full width)
# 0: 1737204
# 1:
# 2:
# 3: 371
# 4: 1870
# 5: 3579
# 6: 2221
# 7: 1245
# 8: 2050
# 9: 720
# 10: 1861
# 11: 703
# 12: 742
# 13: 684
# 14: 847
# 15:
# 16: 738
# 17: 956
# 18:
# 19: 24689
... maybe use some of those as codes to turn sprite rendering on/off?
... if the color bits == 0b000, then branch to update the sprite pointers (indirect loading sprite data through tmp1, tmp2)
enemy really only has two three operations:
1. start rendering a new player with a given width
2. stop rendering the player
v/ a buffer with the player pattern data plus about a hundred lines of 0s ... enemy
... with the revised plan which doesn't automatically update the pattern buffer from memory each line,
playerdata, which initially points to enemybird, is indexed by scanline (in Y), which counts down to zero. so stuff gets drawn upside down:
lda (playerdata),y ; +5 41
... not only does it get upsidedown, but we can't reset it to 0!
... well, we can, but it would involved computing the negative and storing that in playerdata's lo.
... that could totally be done 'enemy'
this corrected version is too slow to run as part of 'platforms':
ldy spritepointer ; +3 36
lda enemybird,y ; +4 40
sta GRP0 ; +3 43
inc spritepointer ; +5 48 ... 15 cycles
... or that logic can be moved to 'enemy', which has implications in that data doesn't update unless the line contains an update command
lda (playerdata),y ; +5 (with scanline loaded into Y, which happens anyway)
sta GRP0 ; +3 ... 8 cycles
... but that would mean doing math to figure out what playerdata(lo) should be when we're trying to set it. to zero it, we'd have to set it to scanline eor $ff
... moving sprite pattern updating logic to 'enemy' probably makes the most sense. it can fetch one of 8 different pieces of pattern and update it, and it'll stretch automatically until updated again.
... the sprites are going to be ugly. most are only going to get a few updates. they're not going to be recognizable. but we can run for this until/unless we want to try to change it again.
stretch the bird out and then draw four points of him when we render (including the off position at the bottom)
_drawenemies was stubbed out
ldx #0 ; iterate over the objects to apply momentum to
momentum0
...
momentum9
inx
cpx #num_bodies
bcs momentum9a ; branch to exit if Y >= num_bodies
jmp momentum0 ; else go back for another pass on the next movable body
momentum9a
ENDM
delay ending VBLANK till as far near the end of scanline 37 as we go before doing a VSYNC
add 'enemy' excursion to the 'platforms' render kernel; execution is sent there from 'renderpump' when the foreground color comes back as 0. that updates the sprite pattern buffer and width.
XXX sprite width and position (both related) should be established at the top of the frame.
don't write enemies into view[] at all.
instead, just compute high byte (which strite strip to use) and low byte (position on screen) and go back to what we were doing.
set sprite width for player0, player1 right after we do the _arctan.
XXX three different sprite strips depending on whether we're looking at the bird from head on, above, or below
; table of useful NUSIZ0 values; translates two bits to three bits; the %11 index is unused
nusize
.byte %00000000, %00000101, %00000111
and #%00000011 ; +2 51 ... the bottom two bits cointain the sprite width; 000, 101, 111 are the only reasonable values to plug in to NUSIZ0
tax ; +2 53 ... XXX with a large-ish table with a lot of redundancy in it, we could avoid having to back up A in Y, mask part off, then reload it from Y again
lda nusize,x ; +4 57 ... XXX this may not be necessary if we're happy to use 2 bits worth of data to set the player data read position... could give back 6 cycles
sta NUSIZ0 ; +3 60
^--------- XXXXXXXXX do this right where do we _arctan
; if deltay > deltaz, this bit of the platform isn't visible
lda deltay
_absolute
cmp deltaz
bmi platrenderline1 ; its okay, continue on
beq platrenderline1 ; its okay
lastline (as itself)
Y is the currentline
tmp2 -- gap between lines
enemydata -- offset into enemybird sprite data
; Y gets the distance, which we use to figure out which size of line to draw
lda view,x ; get the line width of what's there already
and #%00011111 ; mask off the color part and any other data
cmp perspectivetable,y ; compare to the fatness of line we wanted to draw
... sprite framebuffer data needs to be drawn after the platform data as it doesn't use the same bits to indicate distance
... which is a bitch because the platform drawing code is carefully tuned to use up all remaining time
... make it use the same bits so it can go first?
... the 5 low bits are width in platform entries in the framebuffer; could move the two width bits to the top of those five bits and z-buffering might kind of work
... that would need to be tuned, but that could be done
... we already have an if/else thing to decide which number to use for this field based on the actual deltaz
... smaller number for the lower five bits is closer; larger is further away; that's opposite of what we're doing right now with the sprite size bits, but that can be fixed
... have the timer go off early so some time is left for drawing enemies?
trapwrite 96 ... .drawenemies2 put $E3 in there, %11100011
... then 9.plot_up2 replaces that with $B3. bah.
... shorting the timer is starting to look attractive.
... when we're really close, both P0 and P1 using the same data mirrored could be drawn next to each, maybe; that would probably involve dealing with width before the start of the frame
... alternate between enemybird1 / enemybird2 at some frequency
... move more setup stuff to reset() to perhaps reclaim a scanline for processing. setup stuff could be merged into 'scanline1'
... maybe visit every scanline just in case we have to clip and shut off data... though this seems to be working pretty well as is
... sprite hoovers a bit above the platform it's on
... and the ground
... really need a bird flying away from the player (same direction) and one flying towards him/her (opposite direction)
... or else make the bird change directions and fly towards/away from us depending on whether we're above them
playerdata
playerdatahi <- enemybird1 or 2... XXX set this up near startofframe0
... enemy isn't flapping worth a damn. why is that?
... why does it take me multiple flaps to get off of a platform?
... working around this for now with large flap_y and flap_z values
XXX set a more reasonable enemy color than purple
.... time passes....
XXX 04_runtime.pl needs corrections for how much time it has to work with
not all of the cycles during vblank etc are available... TIM64T gets 121 then 40 (with 17 for drawing enemies)
121*64 = 7744+2560=10304, but the last one of each don't count... worst run was 8900
modify the test to simulate INTIM
07_timer.pl and 12_timedrawenemies.pl both already do some stuff with it
INTIM raeds can be cleaned up, and collision, momentum, bird rending done together
is collision testing working?
there's a test for it I think so maybe but nothing is hooked up to it
oh yeah, collision lets you stand on a platform
XXX timer isn't checked often enough, not by a long shot.
XXX better strategy might be to hard-code along with the level data how many steps ahead we can safely look, and just never do more than that, then do other chores, then wait on timer.
scott@fluffy:~/projects/2600/newbies$ perl 07_timer.pl
# fetching timer with 65 left on it at platnextline curplat=0 deltaz=9 lastline=47
# fetching timer with 62 left on it at unknown location curplat=0 deltaz=8 lastline=47
# fetching timer with 61 left on it at platnextline curplat=0 deltaz=8 lastline=46
# fetching timer with 58 left on it at unknown location curplat=0 deltaz=7 lastline=46
# fetching timer with 57 left on it at platnextline curplat=0 deltaz=7 lastline=45
# fetching timer with 54 left on it at unknown location curplat=0 deltaz=6 lastline=45
# fetching timer with 53 left on it at platnextline curplat=0 deltaz=6 lastline=44
... and so on.
# fetching timer with 2 left on it at .plathypot3 curplat=8 deltaz=37 lastline=46
# fetching timer with 2 left on it at .plot9 curplat=8 deltaz=37 lastline=46
# fetching timer with 2 left on it at platnextline0b curplat=8 deltaz=37 lastline=46 <--- only works now because it finishes its work with 2(*64) on the clock still.
XXX wrapping around the world isn't graceful. we can't see past the end. this would be hard to fix. probably don't want to try.