Views: 854,254,301
19 users online:  bebn legg, Charizard746, Connnnair, Devazure, DoodleMyNoodle, Infinity, LucasMegaStriker, MilkyMooer, MiracleWater,  Ninja Boy, PixusPanic, singlepat, smccraw, Sokobansolver, Steven, SwampMage, TickTockClock, westslasher2, ZMann - Guests: 55 - Bots: 64 Users: 47,143 (2,479 active)
Latest: rawros
Tip: ExAnimation also works on sprites!Not logged in.
Custom Block Programming Tutorial
Forum Index - SMW Hacking - SMW Hacking Help - Tutorials - Custom Block Programming Tutorial
Pages: « 1 »
Basic Custom Block programming tutorial
by lion (らいおん。 ◆AUJS9LQFD.)

Chapter 1: What are Custom Blocks?
In a nutshell, custom blocks are blocks whose behavior you code yourself through ASM. They’re nowhere near as versatile as custom sprites, but they’re still very useful when designing a stage.

“Ah, but I don’t know any ASM!”
Don’t worry; I’ve got just the thing.
Here is Ersanio’s basic ASM tutorial. It describes SNES ASM programming in a SMW context, it’s a good start for aspiring ASMers. Once you fully understand that, check out his intermediate ASM tutorial, which expands upon SNES ASM in a more general context; required for those wanting to dive fully into ASM!

If you want to make Julius-level sprites, you’ll need a good understanding of ASM won’t you? Ahaha!

“What do you use to insert them? I know PIXI is used for sprites…”
You use Gopher Popcorn Stew or GPS for short, a block insertion tool by p4plus2 created to improve upon smkdan’s BlockTool Super Deluxe. Telinc1 was a dear and has made a tutorial just for inserting blocks, should you need it.

“What do you code them with? Visual Studio?”
As explained in Ersanio’s tutorials, ASM is primarily coded within text editors. Notepad++ is an excellent choice. I personally use vanilla Notepad out of habit, but NP++ has more features aimed at programming accessibility. Nothing wrong with using IDEs like Visual Studio either!

Chapter 2: Programming 101
First off, head to the SMW Tools section of SMWC and download GPS. I’ve included a quick link up in the previous chapter, feel free to use it.

Now, here’s the following “ingredients” we’ll need:
  • A text editor or IDE. Again, vanilla Notepad will do, but a programmer-oriented environment like Notepad++ is recommended.
  • Gopher Popcorn Stew.
  • A clean SMW rom previously opened in Lunar Magic. I can’t help you find one directly; please use search engines like Google or DuckDuckGo for that. Avoid any exe files and shady websites, obviously! To make sure it’s clean, run it through JSRomClean.
  • The RAM map.
Unpack GPS in its own folder and place the ROM within it for later use.

Within the blocks folder, you’ll encounter a template.asm file. Open it with the text editor.

This contains, well, the template used for GPS’ blocks.

db $37
JMP MarioBelow : JMP MarioAbove : JMP MarioSide : JMP SpriteV
JMP SpriteH : JMP MarioCape : JMP MarioFireball : JMP TopCorner
JMP BodyInside : JMP HeadInside : JMP WallFeet : JMP WallBody






Chapter 2.1: The db Value
You’ll notice a little “db $37” at the top. This basically allows usage of extra offsets, which we’ll get to later.

db $37 activates the WallFeet and WallBody offsets, allowing you to run code when wallrunning on a block and touching a block with your body whilst wallrunning, respectively.

db $42 was added back in BlockTool Super Deluxe, allowing you to use TopCorner, BodyInside and HeadInside, allowing you to run code when Mario touches the upper corners of the block, when Mario’s lower half is within the block and when Mario’s upper half is within the block, respectively.

If you have db $37 set, you don’t need to set $42 as well, as $37 activates the Corner and Inside offsets as well. This code only needs to be set at the very start of the block, repeating it more than once is unnecessary.

Chapter 2.2: Offset How-To
Right below db $37, you’ll find the following block of JMPs.

JMP MarioBelow : JMP MarioAbove : JMP MarioSide : JMP SpriteV
JMP SpriteH : JMP MarioCape : JMP MarioFireball : JMP TopCorner
JMP BodyInside : JMP HeadInside : JMP WallFeet : JMP WallBody

These are the offsets. The way GPS and previous blocktools were programmed, when Mario interacts with a block in a certain way, it runs one of these JMP opcodes (or “JuMPs”) to run code.

Here’s which are loaded and when:
  • MarioBelow is loaded when Mario bonks the block from below.
  • MarioAbove is loaded when Mario steps on the block from above.
  • MarioSide is loaded when Mario touches the block from the sides.
  • SpriteV is loaded when a sprite, like an enemy for example, touches the block from the bottom or the top (vertical).
  • SpriteH is loaded when a sprite touches the block from the sides (horizontal).
  • MarioCape is loaded when Mario attacks the block with a cape spin.
  • MarioFireball is loaded when Mario attacks the block with a fireball.
  • TopCorner is loaded when touching the upper corners of the block, MarioAbove only runs the actual top of the block.
  • BodyInside is loaded when Mario’s lower half is within the block.
  • HeadInside is loaded when Mario’s upper half (or his whole when small Mario) is within the block.
  • WallFeet is loaded when Mario is wallrunning on the block.
  • WallBody is loaded when Mario touches the block while wallrunning.
Below the JMPs you’ll find a series of labels matching each JMP.






Underneath each of them is where the code is typed, with the RTL there signifying the end of the code. Never forget to place it or the code won’t end!

Also, if you’re only using one label, feel free to do rename the labels accordingly.

JMP Used : JMP Nope : JMP Nope : JMP Nope
JMP Nope : JMP Nope : JMP Nope : JMP Nope
JMP Nope : JMP Nope : JMP Nope : JMP Nope

	Your code to run when bonking the block from underneath goes here
	BRA +
	Your code to run otherwise goes here

This makes your block tidier and easier to read. Warning, you’ll have to rename each label, else you’ll get errors from the tool due to it looking for labels that don’t exist.

JMP Used : JMP Nope

Just this is no good.

JMP Used : JMP Nope : JMP Nope : JMP Nope
JMP Nope : JMP Nope : JMP Nope : JMP Nope
JMP Nope : JMP Nope : JMP Nope : JMP Nope

This is good. Do you understand?

Chapter 2.3: The Opcode Atlas
Basic opcodes (think of them like commands for a value or an address) used in block coding include the following:
  • LDA, LDX, LDY – The value and address loading opcodes. They load a value into the Accumulator, X and Y, respectively. Think “Load to Accumulator”, “Load to X”, “Load to Y”…
    • But heads up! Before using LDY make sure to preserve the previous Y value with PHY (Push current Y value) so as to not cause any conflict with the game’s code!
    • If you did use PHY and LDY, make sure to use PLY (Pull back previous Y value) before ending the code with RTL (Return to Label).
    • Within sprite-related offsets, the same above applies to X, as it contains the sprite's table index.
  • STA, STX, STY – The loading opcodes’ storing counterparts. While the loading opcodes temporarily load a value, to insert that value to an address, you need to store it with one of these opcodes. Think “Store A in” “Store X in” “Store Y in”.
    • One more heads up! If you simply use “STA $address”, you’ll be stacking the value to the address’ accumulator. To stack a value to x or y add ,x or ,y at the end, like so: “STA $address,x” “STA $address,y”.
  • STZ – The “Store Zero” opcode. A quick shortcut for when you want to set an address’ value to zero. It’s best to use this instead of “LDA #$00 STA $address”, just for space’s sake.
  • CMP, CPY, CPX – The comparison opcodes. Load an address first then load a value into one of these. Good for branching code. CMP compares the accumulator to its value, CPY compares the Y value, and CPX compares the X value.
  • BRA, BRL – The “branch always” opcodes. These skip ahead to a part of the code regardless. Their main difference is BRL is able to reach further away parts of the code (“Branch Long”). You’ll mostly just use BRA, however!
  • BEQ, BNE – “Branch if Equal” and “Branch if Not Equal”. These skip to a part of the code depending on whether the loaded address and comparison opcode before it had equal values or not.
    • Protip! Due to how they work “under the hood”, you can also use BEQ as a “Branch if Zero” opcode and BNE as a general purpose “Branch If Not-Zero” opcode.
  • BCC, BCS – “Branch if Carry Clear” and “Branch if Carry Set”. These skip to a part of the code depending on whether the Carry Flag is set or clear. Use these for greater than/less than comparisons. BCC is used for Num1 < Num2 and BCS for Num1 >= Num2.
  • INC, INX, INY – The incrementing opcodes. They increment the value of an address by 1 (INC incrementing the Accumulator, INX incrementing X and INY incrementing Y).
  • DEC, DEX, DEY – The PokéDex opcodes. Just kidding, it’s the decrementing opcodes. They work much like the above.
  • ADC, SBC – The addition and subtraction opcodes. They respectively add and subtract the value loaded in them to the value loaded before it. Use the storing opcodes to store it wherever you need.
    • One last heads up! Before using ADC and SBC make sure to clear (CLC) or set (SEC) the carry flag beforehand.
      LDA $value : CLC : ADC $value
      LDA $value : SEC : SBC $value
  • JSR, JSL – Jump to Subroutine and Jump to Subroutine Long. Use these to load subroutines within SMW’s code.
  • RTS – Return from Subroutine, ends the code in a label, returning to the block’s main code itself.
  • RTL – Return from Subroutine Long. Ends the code altogether.
Chapter 2.4: My First Block
Let’s start slow and begin with a simple block.

When Mario steps on a block, he turns into big Mario (or reverts if he’s fire/cape Mario).
Search the RAM map for the Player’s Power-up address and its values.

Here’s the answer sheet for you if you were unable to make the block.

After this, insert your block into a stage within Lunar Magic through the 16x16 Tile Map Editor and test it.

If you want a custom description for the block within LM, add
print "Your description"

to the very end of the .asm file after RTL, where "Your description" is your description of choice.

If you run into an error, GPS will notify you of the line and the error within, so pay attention to the results before closing the window.

Note: $98 through $9B only function correctly within Mario related offsets as they deal with the player's X and Y positions. To deal with the sprites' X and Y positions, call the sprite_block_position routine before using $98 through $9B.
Note 2: Be extremely cautious when altering address $1693's Y value ($1693,y) without preserving it beforehand, as that contains the block's Acts-Like setting.

Chapter 3: Immediately Call the Routines, Let’s Go!
You’ve noticed the routines folder haven’t you? Within this folder are GPS’ shared subroutines. Some routines are included within most blocks, which can inflate their size within the game tenfold. For ease of use, GPS supports the usage of macros to call routines from its routines folder rather than have you include it within the main .asm file.

To call a routine in GPS’ routines folder, simply type:

You’ll find notes on how to use each routine within its comments.
For instance, the “Change to another Map16 block” routine has:
;REP #$10
;LDX #!block_number
;SEP #$10

You can also code your own routines.
If you find a piece of code that's used multiple times across several blocks, split it to its own .asm file, put it in the routines folder and call it like you would any other routine.

I guess this is good enough?
If you have any suggestions to improve this tutorial or make it more accessible, please reply below. If you want to mirror this tutorial somewhere or translate it, go right ahead. I’d appreciate credit, but I’d appreciate more that people aren’t being left in the dark!

Special Thanks to FL4SHK, Koopster, Erik and Thomas for assistance and QA!

Have fun coding!
- lion

linkies | asm stuff :)

im gay and a lion. I AM VERY POOR PROGRAMMER !!! pixel art no hoper. transcriptions on a hot tin ear.

スヤスヤ・・・ (Art by 1UPdudes)
Pages: « 1 »
Forum Index - SMW Hacking - SMW Hacking Help - Tutorials - Custom Block Programming Tutorial

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.

Copyright © 2005 - 2020 - SMW Central
Legal Information - Privacy Policy - Link To Us


Follow Us On

  • YouTube
  • Twitch
  • Twitter


  • Super Mario Bros. X Community
  • Mario Fan Games Galaxy