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
Monday, March 25, 2013
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.
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.
Subscribe to:
Posts (Atom)