Monday, March 25, 2013

MetaSprite Routine Updated

001 .proc evalMetaSprites 002 003 ; metasprite Object in RAM format, one record: 004 ; should be organized as one array of each element 005 ; (example, if there are $10 records, the first $10 bytes are all Ypos 006 007 ; Ypos : byte 008 ; Attribute modifier : byte 009 010 ; vhbcxypp --- Attribute modifier byte (always) 011 ; |||||||| 012 ; ||||||++---- Sprite Colour toggle: EOR with metatile attribs 013 ; |||||+------ Y clipping bit 014 ; ||||+------- X clipping bit 015 ; |||+-------- Clipping or wrap : 0: clip sprites at screen edge, 1: allow wrap 016 ; ||+--------- Background priority bit 017 ; |+---------- Horizontal flipping toggle: EOR metatile attribs 018 ; +----------- Vertical flipping toggle: EOR metatile attribs 019 020 ; Metatile number : byte 021 ; Xpos : byte 022 023 ; -------------------------------------------------------------------------------------------- 024 025 ; metasprite format to define metasprite in ROM data: 026 027 ; xxxxxxxx --- Sprite X coordinate (if required) 028 ; yyyyyyyy --- Sprite Y coordinate (if required) 029 030 ; tttttttt --- Tile number (if required) 031 032 ; vhytxxpp --- Attribute byte (always) 033 ; |||||||| 034 ; ||||||++---- Sprite Colour 035 ; |||||+------ Tile number of next sprite (0: required, 1 : Tile number of this sprite + 1, skip if X control was LF) 036 ; ||||+------- Y position of next sprite (0 : required, 0 : unchanged) 037 ; ||++-------- X position of next sprite (01 : required, 00 : X pos of this sprite + 8, 038 ; || 10 : X pos of the first sprite, Y + 8 (CR/LF), 11 : Escape code for last sprite) 039 ; |+---------- Horizontal flipping 040 ; +----------- Vertical flipping 041 042 ; static 043 declareBSS 044 OAMoffset .byte 045 endBSS 046 047 ; temp use zeropage: 048 049 locals 050 sprModifier .byte 051 sprAttrib .byte 052 sprTile .byte 053 sprXpos .byte 054 sprYpos .byte 055 056 sprXbit8 .byte 057 sprYbit8 .byte 058 059 metaspritePointerLo .byte 060 metaspritePointerHi .byte 061 062 sprAdder .byte 063 sprXposStart .byte 064 mSpriteOffset .byte 065 endlocals 066 067 metaspritePointer = local::metaspritePointerLo 068 069 ; init: 070 ldy #::METASPRITE_COUNT 071 sty local::mSpriteOffset 072 073 074 ; skip reserved sprites 075 if lda M::OAMoffset < #::OAM_ROTATION_START 076 lda #::OAM_ROTATION_START 077 endif 078 079 sta M::OAMoffset 080 sta local::sprAdder ; use as temp: save OAMoffset 081 082 DoNextmetasprite: 083 084 085 ; loop through all entries and skip those with att = $FF 086 ; jump to OAM rotation and leave if no more entries 087 ldx local::mSpriteOffset 088 089 repeat 090 091 if dex == negative 092 jmp clearRemainingOAM 093 endif 094 095 mb a, local::sprModifier := mSpriteMemory[ x ]::att ; load Attrib/meta data which is modifier for all 096 097 until tay : iny != zero ; same as: until mSpriteMemory[ x ]::att <> #$FF 098 099 stx local::mSpriteOffset 100 101 mb local::sprYpos := mSpriteMemory[ x ]::yPos 102 mb local::sprXpos := mSpriteMemory[ x ]::xPos 103 sta local::sprXposStart 104 105 mb a, x := mSpriteMemory[ x ]::mTile ; load metatile number 106 107 ; get metatile pointer 108 mb local::metaspritePointerLo := metaspriteNumbersLo[ x ] 109 mb local::metaspritePointerHi := metaspriteNumbersHi[ x ] 110 111 ; from here, Y indexes into ROM data 112 ; first data is Xwidth, Yheight, Tile, and Attribs/command byte 113 114 ldy #0 115 116 ; --------- process width: 117 118 bit local::sprModifier ; copy b7 and b6 into N, V 119 120 if V set ; H flipping: 121 mb local::sprXpos := local::sprXpos + (metaspritePointer)[ y ] ; add width ( is stored 8 less than actual ) 122 sta local::sprXposStart 123 if carry set 124 mb local::sprModifier := local::sprModifier ^ # ( 1 << OFFSCREEN_XBIT ) 125 endif 126 endif 127 128 iny 129 130 ; --------- end width 131 ; --------- process height: 132 133 if lda local::sprModifier == N set ; V flipping: 134 mb local::sprYpos := local::sprYpos + (metaspritePointer)[ y ] ; add height ( is stored 8 less than actual ) 135 lda local::sprModifier 136 if carry set 137 mb a := a ^ #( 1 << OFFSCREEN_YBIT ) 138 endif 139 endif 140 141 iny 142 143 ; --------- end height: 144 145 ; set offscreen bits: 146 sta local::sprModifier 147 148 mb local::sprYbit8 := a >> 2 ; put Y 'bit8' into bit 0 local var (only bit0 matters) 149 mb local::sprXbit8 := a >> 1 ; put X 'bit8' into bit 0 local var (only bit0 matters) 150 151 ; ---------------- 152 153 mb local::sprTile := (metaspritePointer)[ y ] 154 iny 155 156 ldx local::sprAdder ; X now has OAMoffset 157 158 DoNextTile: 159 160 mb local::sprAttrib := (metaspritePointer)[ y ] ; read attrib and flags 161 iny 162 163 ; if both offscreen bits are clear OR No clipping mode is on 164 if local::sprXbit8 | local::sprYbit8 >> 1 == carry clear || local::sprModifier & #%00010000 165 166 mb OAM_SHADOW[ x + 2] := local::sprAttrib & #%11000011 ^ local::sprModifier 167 mb OAM_SHADOW[ x + 3] := local::sprXpos 168 mb OAM_SHADOW[ x + 0] := local::sprYpos 169 mb OAM_SHADOW[ x + 1] := local::sprTile 170 171 if x := x + 4 == zero 172 ldx #::OAM_ROTATION_START 173 endif 174 175 endif 176 177 sec ; sec carry to end making reg A hold #8 178 mb a := local::sprAttrib & #$F0 179 rol 180 asl 181 asl ; test bit 3, 2 as C, N 182 183 ; if X MODIFIER value is 00 or 01: 184 if C clear 185 asl ; A will have #8 186 if C set ; X MODIFIER IS 01 187 mb a := (metaspritePointer)[ y ] 188 iny 189 clc 190 endif 191 192 ; HERE. either way, carry clear 193 194 if { flagSet local::sprModifier, 6 } ; if bit6 (h mirror) 195 ; negate adder 196 mb a := a ^ #$FF 197 sec 198 endif 199 200 sta local::sprAdder 201 202 mb local::sprXpos := a +c local::sprXpos 203 204 ror 205 if a ^ local::sprAdder == N set ; if carry and adder sign are different: 206 inc local::sprXbit8 ; toggle offscreen bit 207 endif 208 209 else 210 if N clear ; X MODIFIER IS 10 ; 9615 cycles 211 212 ; this idea takes the same # of cycles as the clearer code: 213 ; ------------------------------------------------------- 214 ; asl ; reg A holds #8 215 ; and local::sprModifier 216 ; cmp #1 ; only bit8 could be set, copy it into C 217 ; rol local::sprXbit8 218 219 mb local::sprXbit8 := local::sprModifier >> 3 220 mb local::sprXpos := local::sprXposStart 221 222 lda #8 223 jmp Add8toYPos 224 endif 225 ; else: X MODIFIER IS 11: 226 stx local::sprAdder ; save OAM offset here 227 ;--------------- 228 jmp DoNextmetasprite ; if = 0 then bail and do next RAm based metasprite 229 230 endif 231 232 ; -----------END X pos 233 234 ; ----------- Y pos 235 236 ; load Ypos? Skip all this if not 0 237 if ! local::sprAttrib & #%00001000 238 239 mb a := (metaspritePointer)[ y ] 240 iny 241 242 Add8toYPos: ; jump here if CR/LF code 243 244 clc 245 if flagSet local::sprModifier ; if bit7 (v mirror) 246 mb a := a ^ #$FF 247 sec 248 endif 249 250 sta local::sprAdder 251 252 mb local::sprYpos := a +c local::sprYpos 253 254 ror 255 if a ^ local::sprAdder == N set 256 inc local::sprYbit8 257 endif 258 259 endif 260 ; -----------END Y pos 261 262 ; -----------check tile: 263 264 ; BIT4: check if 0: load tile, else use next tile 265 266 inc local::sprTile ; inc by default 267 268 if ! local::sprAttrib & #%00000100 269 mb local::sprTile := (metaspritePointer)[ y ] 270 iny 271 endif 272 273 ; -------end tile processing 274 275 jmp DoNextTile 276 277 ; -------------------------------------------------------------------------------------------- 278 279 clearRemainingOAM: 280 281 OAMnext = local::sprAdder ; alias 282 283 ; -------------------------------------------------------------------------------------------- 284 285 ldx OAMnext ; x holds start of next blank spot 286 287 ; take away blank spaces from total slots if we wrapped 288 if OAMnext <= M::OAMoffset 289 mb a := OAMnext - #::OAM_ROTATION_START 290 endif 291 292 mb a := a - M::OAMoffset ; bytes used 293 mb a := a >> 2 ; slots used 294 sta OAMnext ; use as temp, since this value is in reg X 295 296 mb y := #(64 - ( ::OAM_ROTATION_START / 4 ) ) - OAMnext ; total avaliable slots MINUS slots used 297 lda #$FF 298 299 cpy #00 300 while not zero do 301 302 sta OAM_SHADOW, x 303 mb x := x + 4 304 if zero 305 ldx #::OAM_ROTATION_START 306 endif 307 dey 308 endwhile 309 310 mb M::OAMoffset := M::OAMoffset + #::OAM_ROTATION_AMOUNT 311 312 rts 313 314 .endproc

Friday, March 22, 2013

MetaSprite Code

My current metasprite code. This is not complete and needs library and macro code. This is a test only, still to be implemented as a library/unit. (CA65 assembler with heavy macro usage.)
DEBUG = 1 .include "..\header\nes_constants.h" .include "..\header\CA65HL.h" .include "..\header\memory.h" .include "..\header\ppu.h" .include "..\header\function_macros.h" .include "..\header\ndxdebug.h" .include "..\header\graphics.h" OAM_ROTATION_START = 4 * OAM_ENTRY OAM_ROTATION_AMOUNT = 160 METASPRITE_COUNT = 5 * 4 ; 4 bytes per ; -------------------------------------------------------------------------------------------- ; -------------------------------------------------------------------------------------------- .scope scope_spriteTestSTATE timerTitle 1, "metaspriteeval" ; setup dynamic memory: .include "..\MEMCONFIG\MEMORY_CONFIG_spriteTestSTATE.inc" IdentifyState "spriteTestSTATE" ; end memory declareBSS localJumpVector .addr endBSS declareBSS mSpriteMemory yPos .byte ::METASPRITE_COUNT att .byte ::METASPRITE_COUNT mTile .byte ::METASPRITE_COUNT xPos .byte ::METASPRITE_COUNT endBSS ; -------------------------------------------------------------------------------------------- ; EXPORTS: .export spriteTestSTATE ; -------------------------------------------------------------------------------------------- ; IMPORTS: .import waitNMI .import writeToVRAMbuffer ; .import split, yield, killThread .importzp NMIdoVRAMupdate .importzp NMIdoOAM .importzp FrameCounter .importZP PadPressed .importzp PadNewPressed .import VramBuffer1Offset .import VramBuffer1 ; -------------------------------------------------------------------------------------------- .pushseg .segment "RODATA" Metatiles: ; hepler constants: X_CR = %00001000 X_DEFINE_PLUS8 = %00000100 X_DEFINE_NEXT = %00000000 X_LASTSPR = %00001100 Y_DEFINE_SAME = %00100000 Y_DEFINE_NEXT = %00000000 TILE_PLUS1 = %00010000 TILE_DEFINE_NEXT = %00000000 V_FLIP = %10000000 H_FLIP = %01000000 metaspriteNumbersLo: .byte <metasprite0, <metasprite1 metaspriteNumbersHi: .byte >metasprite0, >metasprite1 ; first byte only has attribute, and tile byte metasprite0: ; .byte X, Y, TILE, ATTRIB ; boo: 9 bytes .byte $80, X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_CR + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_CR + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_CR + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 0 .byte X_LASTSPR metasprite1: ; megaman: 13 bytes .byte $90, X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_CR + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_CR + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_PLUS8 + Y_DEFINE_SAME + TILE_PLUS1 + 1 .byte X_DEFINE_NEXT + Y_DEFINE_NEXT + TILE_PLUS1 + 1 .byte <-6, <-10, X_LASTSPR + 2 .popseg ; -------------------------------------------------------------------------------------------- .proc spriteTestSTATE ; init state: setSubState M::localJumpVector := #welcomeSTATE nameTableInit 0 .pushseg .SEGMENT "RODATA" palette0: .byte $3f,$00, 32 .byte $16,$0F,$05,$16,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F .byte $16,$0F,$20,$16,$16,$0F,$2C,$11,$0F,$0F,$30,$38,$0F,$0F,$0F,$0F .popseg call writeToVRAMbuffer, _a(palette0), #(32 + 3) setFlag NMIdoVRAMupdate ; init sprite RAM ldx #METASPRITE_COUNT lda #$FF repeat sta mSpriteMemory::att, x until dex == zero ; ; some test data: mb mSpriteMemory[ 0 ]::yPos := #128 mb mSpriteMemory[ 0 ]::xPos := #128 mb mSpriteMemory[ 0 ]::att := #%00000000 mb mSpriteMemory[ 0 ]::mTile := #0 mb mSpriteMemory[ 1 ]::yPos := #(128+50) mb mSpriteMemory[ 1 ]::xPos := #(15) mb mSpriteMemory[ 1 ]::att := #%00000000 mb mSpriteMemory[ 1 ]::mTile := #1 mb mSpriteMemory[ 2 ]::yPos := #(128+50) mb mSpriteMemory[ 2 ]::xPos := #(100) mb mSpriteMemory[ 2 ]::att := #%00000000 mb mSpriteMemory[ 2 ]::mTile := #1 mb mSpriteMemory[ 3 ]::yPos := #(128+30) mb mSpriteMemory[ 3 ]::xPos := #(50) mb mSpriteMemory[ 3 ]::att := #%00000000 mb mSpriteMemory[ 3 ]::mTile := #1 PPU_ON ; end init ; -------------------------------------------------------------------------------------------- LOOP: jsr waitNMI jsri M::localJumpVector jmp LOOP .endproc ; ---------------------------------------------------------------------------------------------- .proc welcomeSTATE setFlag NMIdoVRAMupdate puts 8,12, "WELCOME!" puts 2,13, "PRESS A FOR PRIORITY" puts 2,14, "PRESS B AND SEL FOR FLIPPING" puts 2,15, "PRESS START TO CHANGE SPRITE" puts 2,16, "PRESS START TO CONTINUE" if PadNewPressed & #BUTTON_START setSubState M::localJumpVector := #subfunctionSTATE endif rts .endproc ; -------------------------------------------------------------------------------------------- .macro addMspriteCoord coord, adder, attbyte, attbit mb coord := coord + adder if carry set mb attbyte := attbyte ^ #(1 << attbit) endif .endmacro ; -------------------------------------------------------------------------------------------- .macro subMspriteCoord coord, adder, attbyte, attbit mb coord := coord - adder if carry clear mb attbyte := attbyte ^ #(1 << attbit) endif .endmacro ; -------------------------------------------------------------------------------------------- .proc subfunctionSTATE declareBSS toggleX .byte toggleY .byte width .byte height .byte endBSS if PadPressed & #BUTTON_UP dec mSpriteMemory::yPos if ldx mSpriteMemory::yPos : inx == zero ; if = #$FF mb mSpriteMemory::att := mSpriteMemory::att ^ #%00000100 endif endif if PadPressed & #BUTTON_DOWN inc mSpriteMemory::yPos if zero mb mSpriteMemory::att := mSpriteMemory::att ^ #%00000100 endif endif if PadPressed & #BUTTON_LEFT dec mSpriteMemory::xPos if ldx mSpriteMemory::xPos : inx == zero ; if = #$FF mb mSpriteMemory::att := mSpriteMemory::att ^ #%00001000 endif endif if PadPressed & #BUTTON_RIGHT inc mSpriteMemory::xPos if zero mb mSpriteMemory::att := mSpriteMemory::att ^ #%00001000 endif endif if PadNewPressed & #BUTTON_A mb mSpriteMemory::att := mSpriteMemory::att ^ #%00100000 endif if PadNewPressed & #BUTTON_B mb mSpriteMemory::att := mSpriteMemory::att ^ #%10000000 if M::toggleY dec M::toggleY subMspriteCoord mSpriteMemory::yPos, M::height, mSpriteMemory::att, 2 else inc M::toggleY addMspriteCoord mSpriteMemory::yPos, M::height, mSpriteMemory::att, 2 endif endif if PadNewPressed & #BUTTON_SELECT mb mSpriteMemory::att := mSpriteMemory::att ^ #%01000000 if M::toggleX dec M::toggleX subMspriteCoord mSpriteMemory::xPos, M::width, mSpriteMemory::att, 3 else inc M::toggleX addMspriteCoord mSpriteMemory::xPos, M::width, mSpriteMemory::att, 3 endif endif if PadNewPressed & #BUTTON_START if mSpriteMemory::mTile = #1 dec mSpriteMemory::mTile mb M::width := #( 16 - 8 ) mb M::height := #( 32 - 8 ) else inc mSpriteMemory::mTile mb M::width := #(24 - 8 ) mb M::height := #(24 - 8 ) endif endif ldaPPUmaskBits staPPUmaskBits #MA_MONOCHROME, now startTimer 1 jsr evalMetaSprites stopTimer 1 ldaPPUmaskBits #<~MA_MONOCHROME staPPUmaskBits , now setFlag NMIdoOAM rts .endproc ; ---------------------------------------------------------------------------- .proc evalMetaSprites ; metasprite Object in RAM format, one record: ; should be organized as one array of each element ; (example, if there are $10 records, the first $10 bytes are all Ypos ; Ypos : byte ; Attribute modifier : byte ; vhbcxypp --- Attribute modifier byte (always) ; |||||||| ; ||||||++---- Sprite Colour toggle: EOR with metatile attribs ; |||||+------ Y clipping bit ; ||||+------- X clipping bit ; |||+-------- Clipping or wrap : 0: clip sprites at screen edge, 1: allow wrap ; ||+--------- Background priority bit ; |+---------- Horizontal flipping toggle: EOR metatile attribs ; +----------- Vertical flipping toggle: EOR metatile attribs ; Metatile number : byte ; Xpos : byte ; -------------------------------------------------------------------------------------------- ; metasprite format to define metasprite in ROM data: ; xxxxxxxx --- Sprite X coordinate (if required) ; yyyyyyyy --- Sprite Y coordinate (if required) ; tttttttt --- Tile number (if required) ; vhytxxpp --- Attribute byte (always) ; |||||||| ; ||||||++---- Sprite Colour ; ||||++------ X position of next sprite (00 : required, 01 : X pos of this sprite + 8, ; |||| 10 : X pos of the first sprite, Y + 8 (CR/LF), 11 : Escape code for last sprite) ; |||+-------- Tile number of next sprite (0: required, 1 : Tile number of this sprite + 1 ; ||+--------- Y position of next sprite (0 : required, 0 : unchanged, , skip if X control was LF) ; |+---------- Horizontal flipping ; +----------- Vertical flipping ; static declareBSS OAMoffset .byte OAMusedLast .byte endBSS ; temp use zeropage: locals mSprModifier .byte sprAttrib .byte sprTile .byte sprXpos .byte sprYpos .byte sprXbit8 .byte sprYbit8 .byte metaspritePointerLo .byte metaspritePointerHi .byte sprAdder .byte sprXposStart .byte mSpriteOffset .byte endlocals metaspritePointer = local::metaspritePointerLo ; init: ldy #$FF ; - 1 sty local::mSpriteOffset ; skip reserved sprites if lda M::OAMoffset < #::OAM_ROTATION_START lda #::OAM_ROTATION_START endif sta M::OAMoffset sta local::sprAdder ; use as temp: save OAMoffset DoNextmetasprite: inc local::mSpriteOffset ldx local::mSpriteOffset mb a, local::mSprModifier := mSpriteMemory[ x ]::att ; load Attrib/meta data which is modifier for all ; if att is $FF then last entry, rotate and clear remaining shadow OAM if tay : iny == zero jmp clearRemainingOAM endif mb local::sprYbit8 := a >> 2 ; put Y 'bit8' into bit 0 local var (only bit0 matters) mb local::sprXbit8 := a >> 1 ; put X 'bit8' into bit 0 local var (only bit0 matters) mb local::sprYpos := mSpriteMemory[ x ]::yPos mb local::sprXpos := mSpriteMemory[ x ]::xPos sta local::sprXposStart mb a, x := mSpriteMemory[ x ]::mTile ; load metatile number ; get metatile pointer mb local::metaspritePointerLo := metaspriteNumbersLo[ x ] mb local::metaspritePointerHi := metaspriteNumbersHi[ x ] ; very first tile we read attrib and tile only from metatile ROM data ; Y counts index into ROM data ldy #0 mb local::sprTile := (metaspritePointer)[ y ] iny ldx local::sprAdder ; X now has OAMoffset DoNextTile: mb local::sprAttrib := (metaspritePointer)[ y ] ; read attrib and flags iny ; if both offscreen bits are clear OR No clipping mode is on if local::sprXbit8 | local::sprYbit8 >> 1 == carry clear || local::mSprModifier & #%00010000 mb OAM_SHADOW[ x + 2] := local::sprAttrib & #%11000011 ^ local::mSprModifier mb OAM_SHADOW[ x + 3] := local::sprXpos mb OAM_SHADOW[ x + 0] := local::sprYpos mb OAM_SHADOW[ x + 1] := local::sprTile if x := x + 4 == zero ldx #::OAM_ROTATION_START endif endif ; -------------- X pos mb local::sprAdder := #8 ; add 8 by default mb a := local::sprAttrib & #%00001100 ; process bit 3,2 as 0 to 3 value: if a < #(2 << 2) ; 0 or 1: ; if offset needed: if a = #0 mb local::sprAdder := (metaspritePointer)[ y ] iny endif mb a := local::sprAdder if { flagSet local::mSprModifier, 6 } ; if bit6 (h mirror) ; negate adder mb a := a ^ #$FF + #1 endif sta local::sprAdder mb local::sprXpos := a + local::sprXpos ror if a ^ local::sprAdder == N set ; if carry and adder sign are different: inc local::sprXbit8 ; toggle offscreen bit endif else if a = #( 2 << 2 ) ; Reload metasprite X and Y position: mb local::sprXpos := local::sprXposStart mb local::sprXbit8 := local::mSprModifier >> 3 lda #8 jmp Add8toYPos endif ; else: stx local::sprAdder ; save OAM offset here ;--------------- jmp DoNextmetasprite ; if = 0 then bail and do next RAm based metasprite endif ; -----------END X pos ; ----------- Y pos ; load Ypos? Skip all this if not 0 if ! local::sprAttrib & #%00100000 mb a := (metaspritePointer)[ y ] iny Add8toYPos: ; jump here if CR/LF code if flagSet local::mSprModifier ; if bit7 (v mirror) mb a := a ^ #$FF + #1 endif sta local::sprAdder clc adc local::sprYpos sta local::sprYpos ror if a ^ local::sprAdder == N set inc local::sprYbit8 endif endif ; -----------END Y pos ; -----------check tile: ; BIT4: check if 0: load tile, else use next tile inc local::sprTile ; inc by default if ! local::sprAttrib & #%00010000 mb local::sprTile := (metaspritePointer)[ y ] iny endif ; -------end tile processing jmp DoNextTile ; -------------------------------------------------------------------------------------------- clearRemainingOAM: OAMnext = local::sprAdder ; alias ldx OAMnext txa mb a := a - M::OAMoffset ; bytes used mb a := a >> 2 ; slots used sta OAMnext ; use as temp, since this value is in reg X mb y := #(64 - ( ::OAM_ROTATION_START / 4 ) ) - OAMnext ; total avaliable slots MINUS slots used lda #$FF repeat sta OAM_SHADOW, x mb x := x + 4 if x < #::OAM_ROTATION_START ldx #::OAM_ROTATION_START endif until dey == zero mb M::OAMoffset := M::OAMoffset + #::OAM_ROTATION_AMOUNT rts .endproc ; -------------------------------------------------------------------------------------------- .endscope

Wednesday, February 13, 2013

Full Super Mario Bros. Disassembly Posted

I may still post about a subroutine now and then and try to explain in detail what is happening. I would like to present it in a more dynamic and/or interconnected and interactive way so the flow of the game logic can be observed easily, but for now, the complete disassembly is available here:http://www.romhacking.net/documents/635/

 Much thanks to doppelganger for the original work.

 Note the macro code and documentation are available here: http://www.assembla.com/spaces/ca65hl/wiki
It's still a work in progress at this time but there is some explanation as to how the macro 'language' works.