;=============================================================================== ; PROPOSITION FOR THE DESIGN OF OVERWORLD SPRITES ;------------------------------------------------------------------------------- ; BORING PRELIMINARY JUSTIFICATION FOR DOING IT WEIRD. YOU CAN SKIP THIS IF ; YOU REALLY WANT BUT I RECOMMEND READING IT ANYWAY ;------------------------------------------------------------------------------- ; Lui37's overworld sprites thing works way differently than either anything in ; any of the overworld spritetools and uses coding stuff way differently than ; daiyousei. ; ; Lunar Magic's custom overworld sprites thing basically assumes you will have ; a system for custom sprites that is entirely separate from the original smw ; one. This makes sense, since Lui's patch does it that way. Also the original ; smw one has a bunch of weird restrictions (seriously look at the lm dialog). ; ; Since we basically *have* to implement a system separate from smw's and will ; probably have to a fair bit of rewriting to make Lui37's sprites work no ; matter what (even just for stuff like shared subroutines being different) ; I figure we can take the opportunity to basically design the overworld sprite ; system from the ground up. ; ; Some assumptions I am operating on for the design of the system proposed here: ; 1. We don't care if custom overworld sprites play nice with original smw ; overworld sprites. ; Basically I think this one is something that undergirds Lui37's sprites ; anyway. What this allows us to do is use new tables for the sprites, ; with no special way to do something like check for collision between ; a smw sprite and a custom sprite. ; If this assumption turns out to be false, it might still be viable to just ; use rewrites of the original game sprites and insert them like custom ; sprites. Since the original overworld sprites are mostly really simple, ; I don't think that would be a huge endeavor. ; ; 2. People are willing to learn a new-ish system to write overworld sprites, ; so it's not a big deal if it's not very similar to level sprites. ; This assumption is something I think we get because people probably don't ; expect writing overworld sprites to be similar to writing level sprites ; anyway, so the fact that they have to learn something new to write them ; isn't really a big shocker. ; The question is how much they are willing to learn, and if what I am ; proposing is within that limit. ; ; I think these assumptions are justified but if you disagree with either please ; tell me. ;------------------------------------------------------------------------------- ; HOW I PROPOSE WE DO THIS. THIS IS THE IMPORTANT SECTION OF THIS DOCUMENT. ; IF YOURE READING IT THIS IS WHAT YOURE HERE FOR DONT SKIP IT ;------------------------------------------------------------------------------- ; Overworld sprites have the advantage that level sprites not being anywhere ; to mess things up, so we'll use $14c8+ for their data. ; ; This design is basically 100% oriented toward speed and programmer convenience ; since we aren't doing anything with huge gameplay impacts. So get ready to ; bikeshed I guess. ; ; Design Proposal 1 ; --- ; Rather than using incontiguous tables like SMW did, we will use sprites in ; something more like the actual C sense of "struct". So for each sprite, ; there will be one byte with the sprite number, followed immediately by its ; init flag, followed immediately by its X position, etc. ; This is in contrast to the SMW way of doing things where you have the ; X position for one sprite, then the X position for the next, etc. ; ; So basically in high-level language terms we change from ; `sprites.posX[x]` -> `sprites[x].posX` ; ; Design Proposal 2 ; --- ; We also change the way tables are indexed a little bit. ; Instead of having ; `lda $14c8,x` ; where X = sprite index ; we have something like ; `lda $00,x` ; where X = $14c8+sprite index. ; This requires X/Y to be 16-bit at basically all times within custom overworld ; sprites. ; ; In high-level language terms we change from using an array and index for ; sprites to using a pointer: ; `sprites[x].posX` -> `(*sprite).posX` ; ; This change is so that we can use `lda $xx,x` instead of ; `lda $xxxx,x`, which is a decent speedup (1 cycle on most operations). ; ; These are the biggest changes. I hope somebody who, unlike me, is good at ; explaining things can get a better explanation of this across. I feel like ; it *shouldn't* be hard to explain but if nobody does a good job the changes ; will never take. ; ; Other Design Notes ; --- ; Speeds will be 16 bits. The low byte will be the fractional part, and the ; high byte will be the integer part. ; Positions will be 24 bits. The lowest byte fractional, the upper two bytes ; integral. ; ; Timers are 16-bit which allows them to go a lot longer than the 8-bit ; timers for level sprites. ; ; Right now each overworld sprite's data in memory is 33 bytes, which is ; so close to being a power of two that I almost want to try to combine ; some things. ; ; Technically, the contiguous layout of sprite tables lets you use miscA-miscE ; as a 10-byte table for whatever you want. ; I might make sprites bigger just so that that would be a bigger table. ; You could use that table to do something like store the positions of a few ; particles or something. ; ; I am thinking of adding something to indicate how tall a sprite is. ; I am not sure if Z-position is the bottom of the sprite or the top. ; (Either way the height is useful-ish) ;=============================================================================== ;------------------------------------------------------------------------------- ; how the main dispatch might look ;------------------------------------------------------------------------------- OwcMain: rep #$31 ldx.w #!owc_start .loop: lda !owc_num,x sta $00 adc $00 txy tax lda.l DYS_DATA_OWC_MAIN_PTRS,x sta $00 sep #$20 lda.l DYS_DATA_OWC_MAIN_PTRS+2,x sta $02 pha : plb tyx phk : pea.w .retp-1 jml.w [!DP|$00] .retp: rep #$21 txa : adc.w #!owc_size : tax cpx.w #!owc_end bcc .loop .end: rtl ;------------------------------------------------------------------------------- ; example subroutines ;------------------------------------------------------------------------------- ; replace the byte in A with 0 if positive, $ff if negative ; (i.e. sign-extend the byte) macro dys_sxb() and #$80 : beq + : lda #$ff : + endmacro ; update the sprite's position without gravity %dys_ssr(owc_Translate) ; pos x rep #$21 lda !owc_spdX,x adc !owc_posXF,x ; load overlaps with low byte of !owc_posX sta !owc_posXF,x sep #$20 lda !owc_spdX+1,x %dys_sxb() adc !owc_posX+1,x sta !owc_posX+1,x ; pos y rep #$21 lda !owc_spdY,x adc !owc_posYF,x sta !owc_posYF,x sep #$20 lda !owc_spdY+1,x %dys_sxb() adc !owc_posY+1,x sta !owc_posY+1,x ; pos z rep #$21 lda !owc_spdZ,x adc !owc_posZF,x sta !owc_posZF,x sep #$20 lda !owc_spdZ+1,x %dys_sxb() adc !owc_posZ+1,x sta !owc_posZ+1,x rtl ; update a sprite's position with gravity %dys_ssr(owc_Move) jsl owc_Translate rep #$20 lda !owc_spdZ,x sec : sbc #$0010 ; subtract $0.1 ; terminal velocity of -$40 = $c0.00 bpl + cmp #$c000 : bcc + lda #$c000 + sta !owc_spdZ,x sep #$20 rtl ; position a sprite so it is always at least above the plane Z=0, ; return carry set if it is touching that plane %dys_ssr(owc_CollideZeroPlane) rep #$20 lda !owc_posZ,x bne .nonZero sep #$21 rtl .nonZero: cmp #$8000 : bcs .resetPos sep #$20 rtl .resetPos: stz !owc_posZ,x sep #$21 stz !owc_posZF,x rtl ;------------------------------------------------------------------------------- ; defines ;------------------------------------------------------------------------------- !owc_start = $14c8 !owc_count = 11 ; SCRIPT_NONPTR !owc_size = $21 ; SCRIPT_NONPTR !owc_end #= !owc_start+(!owc_count*!owc_size) ; SCRIPT_NONPTR !owc_num = $00 ; SCRIPT_NONPTR !owc_flags = $01 ; SCRIPT_NONPTR !owc_posXF = $02 ; SCRIPT_NONPTR !owc_posX = $03 ; SCRIPT_NONPTR !owc_spdX = $05 ; SCRIPT_NONPTR !owc_posYF = $07 ; SCRIPT_NONPTR !owc_posY = $08 ; SCRIPT_NONPTR !owc_spdY = $0a ; SCRIPT_NONPTR !owc_posZF = $0c ; SCRIPT_NONPTR !owc_posZ = $0d ; SCRIPT_NONPTR !owc_spdZ = $0e ; SCRIPT_NONPTR !owc_xByte1 = $10 ; SCRIPT_NONPTR !owc_timeA = $11 ; SCRIPT_NONPTR !owc_timeB = $13 ; SCRIPT_NONPTR !owc_timeC = $15 ; SCRIPT_NONPTR !owc_miscA = $17 ; SCRIPT_NONPTR !owc_miscB = $19 ; SCRIPT_NONPTR !owc_miscC = $1b ; SCRIPT_NONPTR !owc_miscD = $1d ; SCRIPT_NONPTR !owc_miscE = $1f ; SCRIPT_NONPTR