Yeah, we talked a little bit about this earlier, and I think it'd be a nice project, so I'd like to claim it, as long as you're okay with some generalization -- i.e., a more general meter, but it'd definitely include some stock code to work with P-switches at least.
Posts by Fernap
Fernap's Profile → Posts
Ok, great -- started working on it; would you mind marking it as claimed? Thanks!
In the mean time, this thread has instructions on how to correct this.
(restricted)
Completed Player following P Switch Meter, which has been approved here
File Name: | Custom Volcano Lotus |
Submitted: | by Sonikku |
Authors: | Sonikku |
Tool: | PIXI |
Type: | Standard |
Dynamic: | No |
Disassembly: | No |
Includes GFX: | Yes |
Description: | This is a custom Volcano Lotus sprite that has a number of pre-set configurations. The projectiles have been converted to Cluster Sprites, which allow up to 20 to be on screen at any given time, rather than the 8 the default Volcano Lotus allows. This sprite can be used as an outright replacement to the original sprite, or as a supplement to it. The Extra Byte can be set to force it to be upside-down. Due to the way the projectile works, it feels more natural than the existing one. Different behaviors can be achieved with settings to the Extension field, including allowing them to be sideways! NOTE: The projectiles utilize a 20-byte RAM table in $7E0F5E, along with all other cluster sprite tables. If you use custom resources which occupy this RAM table, you must change the sprite or those resources accordingly. Update History: -- v1.1 (1/8/2022) - Fixed some minor collision issues. Updated "ClusGetDrawInfo" routine to work slightly better. |
Tags: | cluster, fire plant, volcano lotus, volcano plant |
Screenshots: | ![]() ![]() ![]() |
- Lunar Magic 3.31
- Pixi 1.32
- SA-1 Pack 1.40
- Snes9x 1.60, Bsnes-plus 05
Unfortunately, I have to reject this submission for a number of issues that popped up during testing. It's otherwise a very very nice sprite, and I'd really love to see it get resubmitted.
Major issues:
- There are several shared routines that use lookup tables. These must be accessed either by long addressing (
LDA.l TableName,x
) or by absolute addressing, but setting/restoring the DBR in the routine -- a PHB : PHK : PLB
/ PLB
pair surrounding at least the area which accesses the table (with a normal LDA TableName,x
). Otherwise, values will be (and there have been a couple reports of this already) read from the wrong bank if the routine gets placed in a different bank than the code where it's called from.- You've included a LoseYoshi.asm shared routine which conflicts with the preexisting one in Pixi. Since you aren't using it, it can just be removed. (This wouldn't have been cause for rejecting on its own since it's a trivial fix). Why not just use Pixi's built-in version, anyway?
- On lorom, 3 regular lotuses (with 12 pollen on screen at once) with one extra sprite on screen was enough for slowdown. Even with just 2 lotuses/8 pollen, I could experience a little slowdown, especially so with a couple extra sprites running around. And just 1 fast, stream, or alternating lotus with nothing else on screen could cause slowdown. While I understand that there are fundamental limits to how much can be processed per frame, there's a lot of room for optimization here (more concrete thoughts on that below) that would make this a lot more usable with lorom.
- The alternating pattern doesn't work on lorom (but oddly, it does on SA-1). All the projectiles just shoot in the same direction instead of varying directions.

- There are OAM conflicts between the lotus projectiles and the sparkles from Mario having a star (ditto the glitter effect from collecting a coin) causing some of the projectiles to disappear while the star is active. This one may be a bit infeasible to fully resolve due to OAM table usage, but it's probably worth looking into at least.
Minor issues:
- The "Act Like" should probably be $99, the sprite number of the regular Volcano Lotus.
- The pollen should probably erase itself (or just skip its interaction check) on level end; it won't hurt Mario directly, but it will knock him off Yoshi if it makes contact.
Suggestions:
Here are just a couple general suggestions that aren't issues, but could help end users a bit.
- It's great that you've got the .json file filled out, but including an entry for every possible combination might be a bit overkill (I think there were 36 in total). Having a list that long can clutter someone's list of custom sprites and make it a bit hard to find what they're looking for perhaps. Maybe just one for each direction and leave it up to the user to set the extra byte themselves. Again, just an idea. And either way, it's helpful to modify the mouseover tooltip to at least match what shows up in "add sprite" window -- currently it just gives "volcano lotus".
- Since it seems that people are meant to add to (and modify) the existing list of behaviors, it might be good to document things a little more thoroughly. Like how using
DefaultPattern
only works for 4 projectiles; how the different timing values are used; what's passed and returned if someone wants to make their own pattern; etc.Ideas for optimization:
This isn't exhaustive, and some of the things listed here will have much more or less of an impact than others, but it's just a quick rundown of some of the things I happened to notice while glancing at the code:
1) The way you read values from the
BehaviorPointer
table could be made more efficient. It's certainly a bit more tedious to specify, but having separate tables with the value for each pattern sequentially removes the need for having to switch the index registers between 8 and 16 bit all the time. Alternatively, there's a small enough amount of data that you can probably just stash everything into unused sprite tables at init time, in which case, changing table types wouldn't really even matter. This would also remove a lot of the restoring of X to the sprite index that you have to do in a lot of places (and I noticed some saves/restores that weren't even necessary).2) You're using a lot of shared routines, which is good practice to save space when they're being called from multiple places, but they do introduce some extra overhead, especially when they're written generically, with arguments and results placed in specific spots. But you don't seem to be calling these from multiple places, and you're often wasting cycles by placing arguments and fetching return values that could be streamlined. Some of them are less important (like
%LoseYoshi()
, which gets called rarely), but some have the potential to be called many times per frame, and that little extra overhead can really add up.3) There are plenty of little optimizations that can be made. For example, I noticed
LDA $02 : ASL : STA $02
. This can simply be replaced by ASL $02
(as long as you don't need the result in the accumulator, which seemed to be the case here).File Name: | Wiggler Unrestrictor v1.0 |
Submitted: | by lx5 |
Authors: | lx5 |
Tool: | Asar |
Requires Free Space: | Yes |
Bug Fix: | No |
Featured: | No |
Description: | This patch lets the user decide how many wigglers are supported on screen at any given time. It also makes them not reliant on sprite header 0A in order to work, meaning that you could use them with NMSTL or SA-1 Pack without issues. Small, uninteresting note for SA-1 Pack users: The header feature is going to be added by default in future SA-1 Pack versions (1.41), unless you want to modify the wiggler limit you can ignore this patch. |
Tags: | wiggler |
Screenshots: | ![]() |
- Lunar Magic 3.31
- SA-1 Pack 1.40
- Snes9x 1.60, Bsnes-plus 05
- Asar 1.81
Notes:
Rejecting this due to a bug when you set
!wiggler_amount
to 5 or greater. Returning with an index of at least 4 to the main routine will cause it to read past the ends of the tables at $02EFEA
and 02EFEE
, causing the wiggler to use an unintended block of RAM as the segment buffer. In particular, setting a max of 6 wigglers (on lorom) will hit Map16 data, and using a long enough level will cause something like
to appear.
Other than that, everything looked okay. Changing sprite header worked well, which is certainly nice to be able to do.
Summary: | Removed Bouncing Paragoomba RNG |
Description: | This patch makes the waiting time before a Winged goomba bounces again constant and not RNG. |
Tags: | bouncing paragoomba, goomba, rng, winged goomba |
Code: | !bounce = $50 Org $018D96 ;|\ remove Winged goomba rng LDA #!bounce ;|| constant RNG Vanilla Get a random number of frames (#$50-#$7F) to wait before hopping again. NOP #6 ;|/ |
Submitted: | by Maw |
Hi and thanks for submitting this -- paragoomba RNG removal would definitely be a handy tweak to have -- but I have to reject it for one main issue.
First, per the submission guidelines:
Quote
3. Tweaks may not add any new defines.
Use only those defines that appear in the base tweak patch header. Use parameters to include user-configurable values.
Use only those defines that appear in the base tweak patch header. Use parameters to include user-configurable values.
In particular, here, the bounce time value should be configurable as a tweak parameter, rather than as a define.
Also, as some less important side notes: if you're going to replace code with a bunch of NOPs, you might as well include a branch around it. Also, the RNG value for the paragoomba is a bit weird -- there's a 50% chance of getting a value from $50-5F and a 50% chance of getting a value from $70-7F -- this might be worth noting in the description.
Summary: | Removed HoppingFlame RNG |
Description: | This patch makes the stun time and the Y-speed of a HoppingFlame constant. |
Tags: | hoppingflame, rng |
Code: | !Stuntime = $2F !Yspeed = $D0 org $018F38 ;|\ If the stun timer is one, then make it hop. LDA #!Stuntime ;|| constant value Vanilla The flame has just landed set the stun timer to a random number #$1F-#$3F. NOP #6 ;|/ org $018F50 ;|\ Y Speed LDA #!Yspeed ;|| constant RNG Vanilla; Give it a random Y speed #$D0-#$DF. NOP #6 ;|/ |
Submitted: | by Maw |
I'm rejecting this for the same main reason as for the previous paragoomba submission -- namely that configurable values should be tweak parameters rather than defines.
But also just as important for this example is that you haven't completely removed the randomness in the flame's behavior. Immediately after setting the sprite's Y speed, the game uses the most recent RNG value to determine if it should face Mario. But since this value probably isn't being updated, it'll likely just be reusing the same value every hop, resulting in a flame that never turns, or always turns, depending on what was left in there.
Finally, while combining all the different RNG values for the sprite into a single tweak certainly feels logical, after talking it over with others, I think it would be better to submit this as separate tweaks for each RNG value instead. That will require some care to make sure the pause timer and face direction both work individually. You'd probably need to leave the RNG call in there, but just not use it in both cases. And for the face-player check, I'd assume that you want to give options for both "never face player" or "always face player".
One additional suggestion (not required certainly) is that it might be a little more user-friendly to let the user specify jump speed as a positive value, and simply negate it in the tweak code, so the user doesn't have to mess with that.
Edit: oh, and as before, it'll probably be helpful to include the original range of values in the description to help give some sense of what's appropriate to use.
Bit 1 clear or set (with the result being $00 or $02) tells the SNES graphics chip if the tile should be "small" or "large" respectively. The SNES supports any two sizes out of 8x8, 16x16, 32x32, and 64x64. However, SMW always uses 8x8 and 16x16, so "small" means 8x8, and "large" means 16x16.
If you want to make a 24x24 sprite, you have to use some combination of 8x8 and 16x16 tiles arranged in a way to get what you want. Exactly how will usually involve some sort of tradeoff -- number of OAM slots vs. space in the gfx file, etc.
For example, you could use a 16x16 tile in the upper left, and then pad that with 5 8x8 tiles to the right and below (in which case, you'd have mixed tile sizes and need to set them yourself). Or you could use 4 16x16 tiles that overlap (in which case, all the tiles would be 16x16, so you can let the Finish routine set them) -- note: here, the order you place them is important -- tiles in lower OAM slots will be shown on top of tiles in higher slots.
---
Edit: more stuff I forgot to add that addresses more of the question:
Generally, you'll be setting the tile size as you go, along with setting the tile number, properties, and x & y. If Y holds the OAM offset, then something like:
will set the current slot to 16x16. There may be some little optimizations you can do here, but that's the general idea. You'd do this for each tile (with
And then only at the end would you call
If you want to make a 24x24 sprite, you have to use some combination of 8x8 and 16x16 tiles arranged in a way to get what you want. Exactly how will usually involve some sort of tradeoff -- number of OAM slots vs. space in the gfx file, etc.
For example, you could use a 16x16 tile in the upper left, and then pad that with 5 8x8 tiles to the right and below (in which case, you'd have mixed tile sizes and need to set them yourself). Or you could use 4 16x16 tiles that overlap (in which case, all the tiles would be 16x16, so you can let the Finish routine set them) -- note: here, the order you place them is important -- tiles in lower OAM slots will be shown on top of tiles in higher slots.
---
Edit: more stuff I forgot to add that addresses more of the question:
Quote
and if i were to manually set the tile size using $0460,y how would I write that into the routine? its written in a way that sounds like i would write it like this.
Code
LDA #$00 ; Tile to draw - 1 LDY #$FF ; 16x16 sprite STY $0460,y JSL $01B7B3
Generally, you'll be setting the tile size as you go, along with setting the tile number, properties, and x & y. If Y holds the OAM offset, then something like:
Code
TYA LSR #2 TAY LDA #$02 STA $0460|!addr,y TYA ASL #2 TAY
will set the current slot to 16x16. There may be some little optimizations you can do here, but that's the general idea. You'd do this for each tile (with
STZ $0460|!addr,y
in the middle instead if this one is 8x8).And then only at the end would you call
%FinishOAMWrite()
.FYI, re: #2, I currently have a WIP of some very customizable turnblock bridges that would do what you're looking for and more:

However, while the movement code is done, the Mario interaction code isn't...and has proven to be...very difficult. So it's currently on the back burner, but one day perhaps I'll dust it off. It's also complicated enough that I'll probably need to write a simple frontend (like a web page and some javascript, or something along those lines) to actually do all the config setup.
(Edit: fixed with the embed, thanks!)

However, while the movement code is done, the Mario interaction code isn't...and has proven to be...very difficult. So it's currently on the back burner, but one day perhaps I'll dust it off. It's also complicated enough that I'll probably need to write a simple frontend (like a web page and some javascript, or something along those lines) to actually do all the config setup.
(Edit: fixed with the embed, thanks!)
As long as you don't care about any special effects (block disappearing in a puff of smoke with a sound effect, etc), then no special block is needed -- this is a perfect use case for LM's conditional direct map16 feature. The following UberASM:
(totally untested, I probably made a mistake somewhere). This will set the flag you've chosen if the player has less than the specified number of exits, and clear it if they have greater than or equal to it. It can either go into the level you want, or into global_code.asm (but then change the rtl to rts) if you want it available everywhere.
You can then put a solid block (act like 130 or whatever) into your level as direct map16, and then go to Edit -> Conditional Direct Map16, and enable it for the flag you've chosen. It will then be present if the player has less than the specified number of exits, and absent otherwise.
Or you can also have a block that acts like 25 (with a suitable graphic representing a passable door) along with a another block that acts like 130 with a graphic for a locked door that's exactly one page later in Map16 and tick the "Always show objects ..." option for Conditional DM16.
(NB: I'm sort of working on a much more general Conditional DM16 helper off and on that would do this and more, streamlining the process, but it's sort of back-burnered for a while).
(Edit: optimized the code a bit and fixed a typo I spotted)
Code
!ExitsNeeded = 10 ; Conditional DM16 flag will be set when current number of exits is less than this value !FlagNum = $00 ; which conditional DM16 flag to use ($00-7F) !Events = $1F02|!addr !FlagAddr #= $7FC060+(!FlagNum>>3) !FlagBit #= 1<<(!FlagNum%8) load: ldy #$00 ldx.b #14 .Loop: lda !Events,x beq .Next ; Kernighan's PopCount algorithm - iny sta $00 dec and $00 bne - .Next: dex bpl .Loop cpy.b #!ExitsNeeded bcc .SetBit .ClearBit: lda !FlagAddr and.b #(~!FlagBit) sta !FlagAddr rtl .SetBit: lda !FlagAddr ora.b #!FlagBit sta !FlagAddr rtl
(totally untested, I probably made a mistake somewhere). This will set the flag you've chosen if the player has less than the specified number of exits, and clear it if they have greater than or equal to it. It can either go into the level you want, or into global_code.asm (but then change the rtl to rts) if you want it available everywhere.
You can then put a solid block (act like 130 or whatever) into your level as direct map16, and then go to Edit -> Conditional Direct Map16, and enable it for the flag you've chosen. It will then be present if the player has less than the specified number of exits, and absent otherwise.
Or you can also have a block that acts like 25 (with a suitable graphic representing a passable door) along with a another block that acts like 130 with a graphic for a locked door that's exactly one page later in Map16 and tick the "Always show objects ..." option for Conditional DM16.
(NB: I'm sort of working on a much more general Conditional DM16 helper off and on that would do this and more, streamlining the process, but it's sort of back-burnered for a while).
(Edit: optimized the code a bit and fixed a typo I spotted)
Oh yeah, do that instead. I forgot there was a separate counter for it rather than having to count bits.
Originally posted by NopeContest
I see they are defined in his code though, should I just copy that part from his?
I see they are defined in his code though, should I just copy that part from his?
Yeah, I guess those just got missed...copy those in as they are above.
(restricted)
I guess I'll ask the first question. Does "existing SMW sprite" necessarily mean a vanilla sprite, or just anything that anyone has ever made for SMW?
Summary: | Disable Ducking |
Description: | This disables ducking only for player. It's enabled when riding. |
Tags: | disable, ducking |
Code: | org $00D600 db $A9,$00 |
Submitted: | by Nitrocell Inc. |
WIth this edit alone, Mario is still able to duck when underwater. I'd suggest searching the ROM map for "duck", which has some edits related to this already if you want to resubmit.
And not really the main reason for rejection, but you could have made an equivalent change several instructions earlier (changing the branch to be unconditional, as the edit in the ROM map advises).
And on a side note, if the change you're making is a full instruction like this one is, it's probably better to actually include the instruction ("lda #$00" in this case), rather than having it pre-assembled ("db $A9,$00") for readability sake. Of course, this isn't always possible, like when changing just a BEQ to a BNE for example, but in this case it would have been.