Yeah, as you start adding more and more "sections" of scanlines, it becomes more and more time consuming for the SNES to process. Adding to $01B0 is only required since a horizontal level is $01B0 pixels tall.
Advanced Documentation and ASM Code Library
Is there a more easier way to know what certain values to raise or lower to avoid? It gets confusing, as I started on to put $0030 and just guess
For stimulating more posts here, I decided to post some codes that I have.
Note that they're supposed to work only with Asar and all of them should be compatible with SA-1 unless stated.
But seriously, this thread can be extremely useful for all SMW ASM coders. I'm tired of searching for code from SMWDisC and from other sprites and blocks D:
1. "long" version of branches. Useful if you don't want to make your code ugly if some branch get out of range.
2. Toggle/XOR carry flag:
3. Store/Add/Subtract/Compare 32-bit numbers. (Thanks Alcaro for some help). Assuming that you're using 16-bit A.
4. Play victory theme. Call %victory() to make Mario walk. Call %victory() AND %victory2() to make Mario don't walk. Note that the code assumes that you're using AddmusicK.
SA-1:
5. Easy "execute" pointer. I got tired of boring table setup and since executeptr is rather slow, I created a macro to make them easier and neater to read:
diff is how many bytes to the jump shift from the table. It's supposed to be a negative table. Useful if A doesn't goes from 0. For example, if A always starts from 1, use -2.
jump is the label/address to return after jumping.
Of course the label jumped should return with RTS.
Example:
6. (SA-1 only) Invoke SA-1 macro:
Pretty self-explanatory. Example:
7. Status Bar RAM address to VRAM address. Useful if you want to convert a status bar address ($0EF9) to VRAM direct, for editing the properties (palette,priority,x/y flip) of status bar on NMI for example.
8. Find OAM slot. Useful for uberASM codes. Should work in both level and overworld. Note that it may have weird effects if you don't use (and enable) NMSTL:
SA-1:
That's all.
Note that they're supposed to work only with Asar and all of them should be compatible with SA-1 unless stated.
But seriously, this thread can be extremely useful for all SMW ASM coders. I'm tired of searching for code from SMWDisC and from other sprites and blocks D:
1. "long" version of branches. Useful if you don't want to make your code ugly if some branch get out of range.
Code
macro jeq(branch) bne ?skip jmp <branch> ?skip: endmacro macro jne(branch) beq ?skip jmp <branch> ?skip: endmacro macro jcc(branch) bcs ?skip jmp <branch> ?skip: endmacro macro jcs(branch) bcc ?skip jmp <branch> ?skip: endmacro macro jpl(branch) bmi ?skip jmp <branch> ?skip: endmacro macro jmi(branch) bpl ?skip jmp <branch> ?skip: endmacro macro jvc(branch) bvs ?skip jmp <branch> ?skip: endmacro macro jvs(branch) bvc ?skip jmp <branch> ?skip: endmacro
2. Toggle/XOR carry flag:
Code
macro xoc() bcc ?set clc bra ?done ?set: sec ?done: endmacro
3. Store/Add/Subtract/Compare 32-bit numbers. (Thanks Alcaro for some help). Assuming that you're using 16-bit A.
Code
macro cmp32(a,b) lda <a>+2 cmp <b>+2 bne ?l lda <a> cmp <b> ?l: endmacro macro add32(a,b) lda <a> clc adc <b> sta <a> lda <a>+2 adc <b>+2 sta <a>+2 endmacro macro sub32(a,b) lda <a> sec sbc <b> sta <a> lda <a>+2 sbc <b>+2 sta <a>+2 endmacro macro set32(a,b) lda <b> sta <a> lda <b>+2 sta <a>+2 endmacro
4. Play victory theme. Call %victory() to make Mario walk. Call %victory() AND %victory2() to make Mario don't walk. Note that the code assumes that you're using AddmusicK.
Code
macro victory() lda #$ff sta $1493 sta $0dda lda #$03 sta $1dfb endmacro macro victory2() dec $13c6 endmacro
SA-1:
Code
macro victory() lda #$ff sta $7493 sta $6dda lda #$03 sta $7dfb endmacro macro victory2() dec $73c6 endmacro
5. Easy "execute" pointer. I got tired of boring table setup and since executeptr is rather slow, I created a macro to make them easier and neater to read:
Code
macro exec(diff,jump) asl tax pea.w <jump>-1 jmp (?label-<diff>,x) ?label: endmacro
diff is how many bytes to the jump shift from the table. It's supposed to be a negative table. Useful if A doesn't goes from 0. For example, if A always starts from 1, use -2.
jump is the label/address to return after jumping.
Of course the label jumped should return with RTS.
Example:
Code
lda $3523 %exec(2,back) dw backup dw upload dw gfx1 dw gfx2 back: ;*other code*;
6. (SA-1 only) Invoke SA-1 macro:
Code
macro invoke_sa1(label) LDA.b #<label> STA $3180 LDA.b #<label>>>8 STA $3181 LDA.b #<label>>>16 STA $3182 JSR $1E80 endmacro
Pretty self-explanatory. Example:
Code
level105: %invoke_sa1(.sa1_code) RTS .sa1_code: PHB PHK PLB ;*code*; PLB RTL
7. Status Bar RAM address to VRAM address. Useful if you want to convert a status bar address ($0EF9) to VRAM direct, for editing the properties (palette,priority,x/y flip) of status bar on NMI for example.
Code
macro statusbar_vram(addr) if <addr> < $0F15 LDA.w #$5042+<addr>-$0EF9 else LDA.w #$5063+<addr>-$0F15 endif endmacro
8. Find OAM slot. Useful for uberASM codes. Should work in both level and overworld. Note that it may have weird effects if you don't use (and enable) NMSTL:
Code
FindOAM: LDY #$FC - LDA $02FD,y CMP #$F0 BNE + CPY #$3C BEQ + DEY DEY DEY DEY BRA - + RTS
SA-1:
Code
FindOAM: LDY #$FC - LDA $62FD,y CMP #$F0 BNE + CPY #$3C BEQ + DEY DEY DEY DEY BRA - + RTS
That's all.
Oh man. Seeing these macros makes me want to do asm again.
I own a community of TF2 servers!
ASMT - A new revolutionary ASM system, aka 65c816 ASseMbly Thing
SMWCP - SMW Central Presents a Product- tion long name
frog
http://esolangs.org/wiki/MarioLANG
I own a community of TF2 servers!
ASMT - A new revolutionary ASM system, aka 65c816 ASseMbly Thing
SMWCP - SMW Central Presents a Product- tion long name
frog
http://esolangs.org/wiki/MarioLANG
Yeah. You know what would be cool? Some kinda of macro library for SMW that can be downloaded and gets updated regularly. And then maybe some kind of IDE for asar that can read this library and lets you find functions easily. Kinda like like the standard library of C++ or like .NET Framework in C#.
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
Originally posted by RPG Hacker
Yeah. You know what would be cool? Some kinda of macro library for SMW that can be downloaded and gets updated regularly. And then maybe some kind of IDE for asar that can read this library and lets you find functions easily. Kinda like like the standard library of C++ or like .NET Framework in C#.
Technically, it's pretty easy to do and anyone can do it, as asar has an "include" directive (and "includefrom", if I'm not mistaken). So, we just have to arrange the macros in a file and done. Of course, asar could be changed a little bit so the macro library can be used by any code. Kinda similar to io library in x86 assembly.
Yeah, but it doesn't have a good search function. And first we need such a huge library, anyways (preferably with a huge, detailed documentaiton).
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
This is a behavior algorithm I created. It was inspired by something HuFlungDu mentioned about his SMWCP2 bosses, but it wasn't based off any of his code (which I never saw anyway). Basically, this chooses an attack or other behavior from a pool of possible ones, and the longer the sprite goes without doing a particular one, the more likely it is that that one will come up next.
!R1 and !R2 should be single-byte free RAM addresses, and !T should be a table in free RAM that is as long as the total number of different behaviors you want to select from. For instance, if you have 6 possible behaviors, this should be 6 bytes. I used part of the RAM at $1BA3 when I was testing it, since as far as I know, that table does nothing outside of Mode 7 levels and should be usable as temporary free RAM. Also, each byte of !T should be initialized to 00, and both !R1 and !R2 should be initialized to the total behavior count (so if you have 6 different ones, put #$06 here). I haven't used this in any real sprites yet, but I ran it through a test sprite, and it seemed to work fine. If anyone has any suggestions for improving it, though, feel free to mention them. (Also, I do have a version with comments, but I left them out of it here because they were misaligned.)
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
Code
ChooseBehavior: PHX LDA !T INC STA $00 LDA !R2 DEC JSR RangedRandomRt STA $01 LDX #$01 LDY #$00 .Loop LDA $01 CMP $00 BCC .Break LDA $00 SEC ADC !T,x STA $00 BCS .UseLast INX INY CPY !R1 BCC .Loop .UseLast LDY !R1 DEY .Break LDA #$FF STA !T,y STY $02 LDX #$00 .Loop2 INC !T,x INX CPX !R1 BCC .Loop2 LDX #$00 TXA .Loop3 SEC ADC !T,x BCS .SetMax STA !R2 INX CPX !R1 BCC .Loop3 BRA .NotMax .SetMax LDA #$FF STA !R2 .NotMax PLX LDA $02 RTS
!R1 and !R2 should be single-byte free RAM addresses, and !T should be a table in free RAM that is as long as the total number of different behaviors you want to select from. For instance, if you have 6 possible behaviors, this should be 6 bytes. I used part of the RAM at $1BA3 when I was testing it, since as far as I know, that table does nothing outside of Mode 7 levels and should be usable as temporary free RAM. Also, each byte of !T should be initialized to 00, and both !R1 and !R2 should be initialized to the total behavior count (so if you have 6 different ones, put #$06 here). I haven't used this in any real sprites yet, but I ran it through a test sprite, and it seemed to work fine. If anyone has any suggestions for improving it, though, feel free to mention them. (Also, I do have a version with comments, but I left them out of it here because they were misaligned.)
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
Code
;Determine which side of the block mario is touching 2, by GreenHammerBro. ;Unlike the previous version, this one uses $7E:009A (player X position touching ;the block), rather than using $7E:0077 (player blocked status, when touching ;solid objects). Making it compatable with horizontally moving layer 2 blocks ;or making it behave $25. MarioSide: REP #$20 ;>begin 16-bit mode LDA $9A ;\the block position AND #$FFF0 ;/ CMP $94 ;\if block is right of mairo (if mario is hitting the SEP #$20 ;|left side), then branch to left side. BPL left_side ;/(end 16-bit mode) ;right_side: ;[right side code here] RTL left_side: ;[left side code here] RTL
Code
;Trigger if moving against the side of the block, by GreenHammerBro. ;Not to be confused with triggering if touching the side of the block, ;like the muncher or spikes from smw, this code will only run if mario ;is forced into or moving towards the block by either X speed or if ;mario's X position has been incremented/decremented towards (by ;"wind" or "conveyor belt") the side. If mario isn't moving against ;the side, it will do nothing, reguardless if touching the side or ;not. MarioSide: REP #$20 ;\If mario's block hitbox is not at least a LDA $9A ;|pixel overlapping the block's hitbox, AND #$FFF0 ;|then return. SEC ;| SBC #$000E ;| CMP $94 ;| BPL Return ;| CLC ;| ADC #$001A ;|> this means #$0C if starting at #$00 CMP $94 ;| BMI Return ;| SEP #$20 ;/ ;[Insert your code here] Return: SEP #$20 RTL
Code
;Fixed multiplication routine (the original did do X*(Y+1) rather than X*Y). ;EDIT: found and fix a glitch where if $02 is #$00, it multiplies $00 by #$01 ;instead. So make sure you check if $02 is #$00/#$0000 before executing this ;routine. ;input: ;$00 (8/16-bit) = 1st multiplicand (assumes this is 1 if 0). ;$02 and $04 (8/16-bit) = 2nd multiplicand ;Output: ;A = product ExampleInput: REP #$20 LDA XXXX ;\1st multiplicand STA $00 ;/ LDA YYYY ;\2nd multiplicand STA $02 ;| STA $04 ;/>Prevent 1 extra addition BEQ .Zero ;>If 2nd multiplicand = 0, make result 0 JSR Multiply ;>Execute multiplication BRA .SkipZero ;>And don't replace result .Zero LDA #$0000 ;>Load as zero result. .SkipZero ;[some codes here] ;>Use "A" register for product RTS/RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Multiply: ;\multiplication subroutine STA $04 ;| .Loop LSR $02 ;| BEQ .end ;| BCC .Next ;| CLC ;| ADC $00 ;| .Next ASL $00 ;| BRA .Loop ;| .end ;| CLC ;| ADC $00 ;| SEC ;|\remove 1-extra multiplication. SBC $04 ;// RTS
EDIT: superseded by this (both are unsigned):
Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 16bit * 16bit Multiplication ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Argusment ; $00-$01 : Multiplicand ; $02-$03 : Multiplier ; Return values ; $04-$07 : Product ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MathMul16_16: REP #$20 LDY $00 STY $4202 LDY $02 STY $4203 STZ $06 LDY $03 LDA $4216 STY $4203 STA $04 LDA $05 REP #$11 ADC $4216 LDY $01 STY $4202 SEP #$10 CLC LDY $03 ADC $4216 STY $4203 STA $05 LDA $06 CLC ADC $4216 STA $06 SEP #$20 RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 16bit * 16bit Multiplication SA-1 version ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Argusment ; $00-$01 : Multiplicand ; $02-$03 : Multiplier ; Return values ; $04-$07 : Product ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MathMul16_16: STZ $2250 REP #$20 LDA $00 STA $2251 ASL A LDA $02 STA $2253 BCS + LDA.w #$0000 + BIT $02 BPL + CLC ADC $00 + CLC ADC $2308 STA $06 LDA $2306 STA $04 SEP #$20 RTS
Edit: fix the "Trigger if moving against the side of the block" glitch where if placed on the leftmost edge of level.
Give thanks to RPG hacker for working on Asar.
Here's some little code I developed: Division routine.
Code
; ; Use: ; REP #$20 ; LDA.w #$aaaa ; STA $00 ; LDA.w #$bbbb ; STA $02 ; PHB ; PHK ; PLB ; JSR Divide ; PLB ; ; At any moment, you'll want a SEP #$20 ; ; $04 : Quotient (16-bit) ; $06 : Remainder (16-bit) ; Y : Error Flag (divided by zero) Divide: LDY #$00 STZ $04 STZ $06 LDA $02 BNE .Continue INY RTS .Continue LDX #$0F .Loop ; \ CPX #$00 ; | For i=15...0 BMI .EndLoop ; / LDA $06 ; \ ASL A ; | R <<=1 STA $06 ; / LDA $00 JSR NewGetBit ORA $06 STA $06 LDA $06 CMP $02 BCC .Next LDA $06 SEC SBC $02 STA $06 ;LDA.w #$0001 JSR NewMultiplyBit ORA $04 STA $04 .Next DEX JMP .Loop .EndLoop LDY.b #$00 RTS NewGetBit: PHX PHY LDY.b #$00 PHA TXA ASL AND.w #$00FF TAX PLA AND.w Look_Table,x BEQ + INY + TYA PLY PLX RTS NewMultiplyBit: PHX TXA ASL AND.w #$00FF TAX LDA Look_Table,x PLX RTS Look_Table: dw $0001,$0002,$0004,$0008,$0010,$0020,$0040,$0080 dw $0100,$0200,$0400,$0800,$1000,$2000,$4000,$8000
Sprite slot debugger.
Shows the slots that are occupied and unoccupied on HUD, useful to tell of all the slots are filled.
please uploate it here
Edit: actually it starts at different slots depending on the sprite memory.
Give thanks to RPG hacker for working on Asar.
Shows the slots that are occupied and unoccupied on HUD, useful to tell of all the slots are filled.
please uploate it here
Edit: actually it starts at different slots depending on the sprite memory.
Give thanks to RPG hacker for working on Asar.
So, where do I begin...
This is more or less useless, or at least not as usefull as it could be by making it display less information on purpose.
First and formost, any person who'd want to debug their sprite slots would probably just use the RAM display of snes9x debugger. It's a lot easier than going about inserting code.
As for the code itself.
Why do you STZ all at the beginning? And why do you only store 1 if the slot is occupied?
There are only 00-0C different values for $14C8, that is if nothing stores garbage there.
So instead of doing all that you could just loop over the table and store it to the status bar:
That way you can not only tell if the slot is occupied but alos what state that sprite is in. But as I said, Anybody who'd want that information would just go use the real debugger.
And seeing as that itself is more or less just a simple loop, there is no real need to put it in the library... unless Alcaro decides otherwise.
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
This is more or less useless, or at least not as usefull as it could be by making it display less information on purpose.
First and formost, any person who'd want to debug their sprite slots would probably just use the RAM display of snes9x debugger. It's a lot easier than going about inserting code.
As for the code itself.
Why do you STZ all at the beginning? And why do you only store 1 if the slot is occupied?
There are only 00-0C different values for $14C8, that is if nothing stores garbage there.
So instead of doing all that you could just loop over the table and store it to the status bar:
Code
LDX #!sa1_slots-1 ; init X - LDA $14C8,x ;\ get sprite state STA $0EF9,x ;/ to status bar DEX BPL - ; x still positive? -> loop
That way you can not only tell if the slot is occupied but alos what state that sprite is in. But as I said, Anybody who'd want that information would just go use the real debugger.
And seeing as that itself is more or less just a simple loop, there is no real need to put it in the library... unless Alcaro decides otherwise.
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
This is a routine I created for simulating spritesets with more but smaller GFX files, similar to what Yoshi's Island does. The advantage it has over SMW's existing spriteset system is that it is much easier to mix spritesets, because there are 8 GFX files of size 1 KiB instead of 2 GFX files of size 4 KiB. (It only handles the second GFX page, which would normally be SP3 and SP4.) JSR to this in uberASM's game mode 13 init. The GFX file number list is optional; it is not necessary for the routine to function, but it can be used in other things, such as the custom sprites themselves, to do as YI does and change the tilemap depending on which GFX files are loaded where. (Set the define to whatever free RAM address you want as long as it is at least 16 bytes long; I used $7FA300 in my test ROM.) Also, here is a patch that will remap all sprite tiles (or at least most of them? I might have missed a few...) to match the new tilemaps.
(Edit: Updated post with note about the other decompression routine and added a link to the sprite remap hex edit patch.)
You will also need these supplementary routines for decompressing and uploading the GFX files, if you aren't using them already. In fact, now that I think about it, why aren't these in the library already? They have already proven useful for quite a number of things. The define here is not optional this time, but again, set it to anything big enough. I used $7F1500 in my test ROM, since $7F1500-$7F3FFF would be the same size as SMW's normal decompression buffer at $7EAD00 when combined with Lunar Magic's ASM hacks. (And if you're wondering why I didn't just use $7EAD00 then, it's because Lunar Magic—rather foolishly—also uses that space for ExAnimation data, so using it as a decompression buffer after that gets loaded will cause any animation in that level that uses the extra animated tile space to glitch up.)
Alternatively, you can just use $0FF900, as Vitor Vilela pointed out in the following post.
I would actually like people to test this routine if they can. It seemed to work fine when I tested it, with the proper settings (make sure to have one of the alternate decompression routines enabled), but I'm not sure. It's not really worth making a patch out of...I was going to, but then I found out it could be done just with uberASM.
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
(Edit: Updated post with note about the other decompression routine and added a link to the sprite remap hex edit patch.)
Code
!RAM_SpriteGFXList = $7FA300 SpriteSetHandler: PHP REP #$30 LDY $010B LDA LevelSpriteSet,y AND #$00FF ASL : ASL : ASL : ASL TAY LDX #$0000 .Loop LDA SpriteSetGFXList,y STA !RAM_SpriteGFXList,x JSR DecompressGFXFile TXA XBA EOR #$7E00 JSR UploadVRAMData INY : INY INX : INX CPX #$000E BCC .Loop PLP RTS LevelSpriteSet: db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 0-F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 10-1F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 20-2F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 30-3F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 40-4F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 50-5F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 60-6F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 70-7F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 80-8F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 90-9F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels A0-AF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels B0-BF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels C0-CF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels D0-DF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels E0-EF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels F0-FF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 100-10F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 110-11F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 120-12F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 130-13F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 140-14F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 150-15F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 160-16F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 170-17F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 180-18F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 190-19F db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1A0-1AF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1B0-1BF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1C0-1CF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1D0-1DF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1E0-1EF db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; levels 1F0-1FF SpriteSetGFXList: dw $0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087 ; spriteset 00 dw $0080,$0081,$0082,$0083,$0088,$0089,$008A,$0087 ; spriteset 01 dw $0080,$0081,$0082,$008B,$008C,$008D,$008E,$008F ; spriteset 02 dw $0080,$0090,$0091,$0092,$0093,$0094,$0095,$0096 ; spriteset 03 dw $0080,$0081,$0082,$0083,$0099,$009A,$009B,$00A5 ; spriteset 04 dw $0080,$0081,$0082,$0083,$009C,$009D,$009E,$009F ; spriteset 05 dw $0080,$0081,$0082,$0092,$00A0,$00A1,$00A2,$00A3 ; spriteset 06 dw $0080,$0081,$0082,$0083,$0099,$00A7,$00A4,$00A5 ; spriteset 07 ; dw $007F,$007F,$007F,$007F,$007F,$007F,$007F,$007F ; spriteset 08 ;... ; dw $007F,$007F,$007F,$007F,$007F,$007F,$007F,$007F ; spriteset FF
You will also need these supplementary routines for decompressing and uploading the GFX files, if you aren't using them already. In fact, now that I think about it, why aren't these in the library already? They have already proven useful for quite a number of things. The define here is not optional this time, but again, set it to anything big enough. I used $7F1500 in my test ROM, since $7F1500-$7F3FFF would be the same size as SMW's normal decompression buffer at $7EAD00 when combined with Lunar Magic's ASM hacks. (And if you're wondering why I didn't just use $7EAD00 then, it's because Lunar Magic—rather foolishly—also uses that space for ExAnimation data, so using it as a decompression buffer after that gets loaded will cause any animation in that level that uses the extra animated tile space to glitch up.)
Alternatively, you can just use $0FF900, as Vitor Vilela pointed out in the following post.
Code
!DecompBuffer = $7F1500 DecompressGFXFile: PHY PHX PHP REP #$30 CMP #$0032 BCC .GFX00to31 CMP #$0080 BCC .UploadReturn CMP #$0100 BCS .ExGFX100toFFF .GFX80toFF AND #$007F STA $8A ASL CLC ADC $8A TAY LDA $0FF94F STA $06 LDA $0FF950 STA $07 BRA .FinishDecomp .UploadReturn PLP PLX PLY RTS .GFX00to31 TAX LDA $00B992,x STA $8A LDA $00B9C4,x STA $8B LDA $00B9F6,x STA $8C BRA .FinishDecomp2 .ExGFX100toFFF SBC #$0100 STA $8A ASL CLC ADC $8A TAY LDA $0FF873 STA $06 LDA $0FF874 STA $07 .FinishDecomp LDA [$06],y STA $8A INC $06 BNE .NoCrossBank SEP #$20 INC $08 REP #$20 .NoCrossBank LDA [$06],y STA $8B .FinishDecomp2 LDA.w #!DecompBuffer STA $00 SEP #$20 LDA.b #!DecompBuffer>>16 STA $02 PHK PEA .Ret1-1 PEA $84CE JML $00B8DC .Ret1 PLP PLX PLY RTS UploadVRAMData: PHY PHP SEP #$10 LDY #$80 STY $2115 STA $2116 LDA #$1801 STA $4300 LDA.w #!DecompBuffer STA $4302 LDY.b #!DecompBuffer>>16 STY $4304 LDA $8D STA $4305 LDY #$01 STY $420B PLP PLY RTS
I would actually like people to test this routine if they can. It seemed to work fine when I tested it, with the proper settings (make sure to have one of the alternate decompression routines enabled), but I'm not sure. It's not really worth making a patch out of...I was going to, but then I found out it could be done just with uberASM.
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
You don't need that huge routine for decompressing GFXs anymore, just set $00-$02 to output buffer, set A to GFX number in 16-bit mode and JSL $0FF900, like:
[do something with your gfx here]
GitHub - Twitter - YouTube - SnesLab Discord
Code
STZ $00 REP #$20 LDA #$7EAD ; buffer = $7EAD00 STA $01 LDA #$0080 ; deoompress ExGFX80.bin JSL $0FF900
[do something with your gfx here]
GitHub - Twitter - YouTube - SnesLab Discord
Well, NMI isn't disabled during game mode 13, and since $0FF900 uses scratch RAM that is also used by NMI (why? Why, FuSoYa?!), it can't really be used here without the (small, but possible) risk of something exploding.
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
Originally posted by imamelia
(And if you're wondering why I didn't just use $7EAD00 then, it's because Lunar Magic—rather foolishly—also uses that space for ExAnimation data, so using it as a decompression buffer after that gets loaded will cause any animation in that level that uses the extra animated tile space to glitch up.)
There's nothing foolish about conserving RAM. Further, the game already does the same thing for the overworld's animated tiles.
Originally posted by imamelia
Well, NMI isn't disabled during game mode 13, and since $0FF900 uses scratch RAM that is also used by NMI (why? Why, FuSoYa?!), it can't really be used here without the (small, but possible) risk of something exploding.
Imamelia... $0FF900 uses the exact same RAM as the code you just posted. A little less in fact, since LM's doesn't need to use $06.
Originally posted by FuSoYa
There's nothing foolish about conserving RAM. Further, the game already does the same thing for the overworld's animated tiles.
Originally posted by imamelia
(And if you're wondering why I didn't just use $7EAD00 then, it's because Lunar Magic—rather foolishly—also uses that space for ExAnimation data, so using it as a decompression buffer after that gets loaded will cause any animation in that level that uses the extra animated tile space to glitch up.)
There's nothing foolish about conserving RAM. Further, the game already does the same thing for the overworld's animated tiles.
Well, it's a good idea in theory, but it means you can't use the buffer while a level is running without screwing up ExAnimation, unless that level just uses the original GFX or the uncompressed GFX files (which, admittedly, are usually what I use). (Incidentally, on the subject of the overworld, I wonder if some of those tables could be moved to $7FC800 or something...)
Originally posted by FuSoYa
Imamelia... $0FF900 uses the exact same RAM as the code you just posted. A little less in fact, since LM's doesn't need to use $06.
Originally posted by imamelia
Well, NMI isn't disabled during game mode 13, and since $0FF900 uses scratch RAM that is also used by NMI (why? Why, FuSoYa?!), it can't really be used here without the (small, but possible) risk of something exploding.
Imamelia... $0FF900 uses the exact same RAM as the code you just posted. A little less in fact, since LM's doesn't need to use $06.
...Huh. That's true. I think the code I posted originally came from one of edit1754's patches...I wonder why he didn't just use $0FF900, then? I really should try to push that routine to its limit to see if I can figure out how far it will go before breaking when NMI hits. Or better yet, just make interrupts preserve everything properly. I vaguely recall someone making a patch to rewrite NMI to make it more efficient...maybe that would be worth looking into again? And actually, now that I think about it, does Lunar Magic have any such code for uploading the decompressed data to VRAM as well?
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
Originally posted by imamelia
Well, it's a good idea in theory, but it means you can't use the buffer while a level is running without screwing up ExAnimation, unless that level just uses the original GFX or the uncompressed GFX files (which, admittedly, are usually what I use).
I think you'll find that the number of people that use a decompressed ExAnimation file vastly outnumber the ones that want to do their own decompression outside of level/overworld load. And when you want to do both, the amount of RAM used is the same. So better that the ExAnimation file is there than taking up other free RAM elsewhere.
As usual, you have to look beyond your own case to determine whether something is really a good idea or not.
Originally posted by imamelia
(Incidentally, on the subject of the overworld, I wonder if some of those tables could be moved to $7FC800 or something...)
The first part of that is used by the overworld to store layer 1. Beyond it might be free though.
Originally posted by imamelia
I wonder why he didn't just use $0FF900, then?
His patch was originally made before LM 1.70, which was when LM made it's own routine more accessible.
Originally posted by imamelia
I really should try to push that routine to its limit to see if I can figure out how far it will go before breaking when NMI hits. Or better yet, just make interrupts preserve everything properly. I vaguely recall someone making a patch to rewrite NMI to make it more efficient...maybe that would be worth looking into again?
You may find this one useful: http://www.smwcentral.net/?p=section&a=details&id=5775
Although if you have time, it might be worth looking through NMI to locate the game code that's using scratch RAM when the current game frame hasn't finished processing (as fixing it directly may be more compatible with other patches than editing code near the start of the NMI routine like the patch above). It's something I had thought of looking into before, but it's not an issue I've run into myself so it wasn't much of a priority.
Originally posted by imamelia
And actually, now that I think about it, does Lunar Magic have any such code for uploading the decompressed data to VRAM as well?
Nothing meant for general use.
Originally posted by FuSoYa
Although if you have time, it might be worth looking through NMI to locate the game code that's using scratch RAM when the current game frame hasn't finished processing (as fixing it directly may be more compatible with other patches than editing code near the start of the NMI routine like the patch above). It's something I had thought of looking into before, but it's not an issue I've run into myself so it wasn't much of a priority.
From what I can tell, there are multiple such routines. $00A488 uses them, but so does $00A390, and there might be others.
----------------
I'm working on a hack! Check it out here. Progress: 64/95 levels.
Originally posted by imamelia
but so does $00A390
...eh? That's the tile animation DMA code. Remember you only want to look for NMI code that will run if $10 is non-zero. When it's 0 it should be fine for NMI to use scratch RAM, as it means the game is done processing the current frame and is waiting in a loop for NMI to do its thing.