JackTheSpades / SpriteToolSuperDelux

A slightly updated version of Romi's sprite tool for Super Mario World hacking
https://www.smwcentral.net/
GNU General Public License v3.0
15 stars 22 forks source link

Pixi's readme

Build status CMake

PIXI is a tool to insert custom sprites into Super Mario World ROMs. It assembles using Asar, meaning TRASM sprites are not supported.

Periodically updated Windows (32 and 64 bit), Linux (64 bit) and MacOS (64 bit) builds can be found here.

A build for each commit can also be found in the Github CI artifacts here. Keep in mind that Github artifacts only last for 60 days, so if you're looking for an older version, you'll have to build it yourself.

If you're a developer looking to contribute to this project, please see the contribution guide.

If you are using a custom pixi build (read: with modification to either C++ code or asm code), do not report issues here unless you can prove said issues also happen on an unmodified official version of the tool, reported issues that derive from external coding modifications will be ignored and closed.

The changelog is available here.

The List File

Normal Sprites

To let the tool know which sprites you want to insert in which sprite slots, you have to open the file called "list.txt" or create a new one. In it, you define the sprites you want to insert into your ROM and the sprite number you want to give them. The format is as follows:

    id SPACE cfg_file

For example, a "list.txt" that should insert Blue.cfg to sprite number 00, Green.cfg to sprite number 01 and Shooter.cfg to C0 with Generator.cfg at D0 would look as such:

    00 Blue.cfg
    01 Green.cfg
    C0 Shooter.cfg
    D0 Generator.cfg

Keep in mind that the areas for sprites (00-BF), shooters (C0-CF) and generators (D0-DF) are fixed. If you want to insert a shooter, it has to be in the range of C0 to CF due to the sprite type's different coding.

Per-Level Sprites

The slots B0 to BF are special, in that if you assign a level to them, they will become per-level sprites. The sprite will only use the sprite slot between B0 and BF in that one specified level. Meaning you can assign sprite slot B0 of level 105 to a Thwomp and B0 of level 106 to a Hammer Bro if you wanted. Keep in mind this only holds true for slots B0 to BF. Do note that per-level sprites support at max 4 extra bytes. The format for per-level sprites looks as follows:

    level COLON id SPACE cfg_file

Here is an example of a "list.txt" file that inserts Blue.cfg and Green.cfg in the same slots as earlier, and then inserts Red.cfg and Yellow.cfg only for level 105, while Boo.cfg uses the same slot as Red.cfg but in level 106:

    00 Blue.cfg
    01 Green.cfg

    105:B0 Red.cfg
    105:B1 Yellow.cfg
    106:B0 Boo.cfg

or

    B0 Blue.cfg
    105:B0 Red.cfg

Note that the above is still perfectly valid, sprite B0 will behave like Blue.asm in any level except for 105, where it will take Red.asm properties and code instead. This is because since Pixi 1.3, slots B0-BF are not exclusive to per-level sprites anymore but they can be used by normal sprites aswell instead

Other sprite types

PIXI also has the ability to insert other types of sprites, such as cluster, extended, minor extended, bounce, smoke, spinning coin and score sprites. To insert these other types, you just have to change the list type within your list file. This is simply done by a type of headline with the all caps type followed by a colon. Valid headlines are: "SPRITE:" (default), "EXTENDED:", "CLUSTER:", "MINOREXTENDED:", "BOUNCE:", "SMOKE:", "SPINNINGCOIN:", "SCORE:" all without quotes. You probably won't need the SPRITE: header, since it's the default but it's there anyway. After that header, you can proceed to place sprites just like before, except they are taken from their respective directories. An example:

    00 Blue.cfg
    01 Green.cfg

    CLUSTER:
    00 flower.asm
    01 fish.asm

    EXTENDED:
    00 hammer.asm

    SMOKE:
    00 mysmoke.asm

Note that all sprites except normal sprites use the .asm extension, while normal sprites have .cfg/.json. Also keep in mind that shooters and generators are part of the SPRITE: group and are seperated by their slot.

Sprite Insertion

Opening pixi.exe

When opening pixi.exe by double clicking it, a window will open asking you for the location of your Super Mario World ROM. If the ROM is in the same folder as PIXI, you can simply type in its name, for example "My Hack.smc" and hit enter. Otherwise, you can use your mouse to drag and drop your ROM into PIXI's window and then hit enter to insert all sprites specified in the "list.txt" sprite list file explained above.

Using the Command Prompt

This option is for slightly more advanced users. To open a command prompt window, hold shift and right click the folder PIXI is in, then select "Open command window here".

The tool assumes a lot of default paths and files. You can change them when calling the tool from the command line interface by typing them as in the example below.

  Usage: pixi <options> <ROM>
  Options are:
  -d              Enable debug output
  --debug         Enable debug output
  -k              Keep debug files
  --symbols <symbols_type>       Enable writing debugging symbols files in format wla or nocash (Default value: <empty>)
  -l  <listpath>  Specify a custom list file (Default: list.txt)
  -pl               Per level sprites - will insert perlevel sprite code
  -npl            Same as the current default, no sprite per level will be inserted, left dangling for compatibility reasons
  -d255spl      disables 255 sprite per level support (won't do the 1938 remap)
  -w              Enable asar warnings check, recommended to use when developing sprites

  -a  <asm>       Specify a custom asm directory (Default asm/)

  -sp <sprites>   Specify a custom sprites directory (Default sprites/)
  -sh <shooters>  Specify a custom shooters directory (Default shooters/)
  -g  <generators>        Specify a custom generators directory (Default generators/)
  -e  <extended>  Specify a custom extended sprites directory (Default extended/)
  -c  <cluster>   Specify a custom cluster sprites directory (Default cluster/)
  -b  <bounce>    Specify a custom bounce sprites directory (Default misc_sprites/bounce/)
  -me <minorextended>     Specify a custom minor extended sprites directory (Default misc_sprites/minorextended/)
  -sc <score>     Specify a custom score sprites directory (Default misc_sprites/score/)
  -sm <smoke>     Specify a custom smoke sprites directory (Default misc_sprites/smoke/)
  -sn <spinningcoin>      Specify a custom spinning coin sprites directory (Default misc_sprites/spinningcoin/)

  -r  <sharedpath>        Specify a shared routine directory (Default routines/)
  -nr <number>          Specify a maximum number of shared routines (Default is 100, maximum is 310)

  -ssc <append ssc>       Specify ssc file to be copied into <romname>.ssc
  -mwt <append mwt>       Specify mwt file to be copied into <romname>.mwt
  -mw2 <append mw2>       Specify mw2 file to be copied into <romname>.mw2, the provided file is assumed to have 0x00 first byte sprite header and the 0xFF end byte
  -s16 <base s16>         Specify s16 file to be used as a base for <romname>.s16
                          Do not use <romname>.xxx as an argument as the file will be overwriten

  --onepatch                   Applies all sprites into a single big patch (Default value: false)
  --stdincludes <includepath>  Specify a text file with a list of search paths for asar (Default value: "<empty>")
  --stddefines <definepath>    Specify a text file with a list of defines for asar (Default value: "<empty>")
  --exerel                     Resolve list.txt and ssc/mw2/mwt/s16 paths relative to the executable rather than the ROM

  -no-lm-aux        Disables all of the Lunar Magic auxiliary files creation (ssc, mwt, mw2, s16) (Default value: false)
  -extmod-off       Disables extmod file logging (check LM's readme for more info on what extmod is) (Default value: false)
  -lm-handle <lm_handle_code>       Special command line to be used only within LM's custom user toolbar file. Available only on Windows.

MeiMei:

meimei is an embedded tool pixi uses to fix sprite data for levels when sprite data size is changed for sprites already in use.

That happens when you have a level that already uses a certain sprite and you change the amount of extra bytes said sprite uses.

Its options are:

  -meimei-off       Shuts down MeiMei completely
  -meimei-a     Enables always remap sprite data
  -meimei-k     Enables keep temp patches files
  -meimei-d     Enables debug for MeiMei patches - I recommend you turn this on if you wanna know what levels were edited and how.

They are all still considered pixi options by the way, so you would them the as any of ther other options above the MeiMei section.

Examples:

Features, additions and changes

If you are used to using Romi's SpriteTool, here is a quick rundown of old and new features that PIXI offers:

Extra Property Bytes

Extra Property Bytes (which are not Extra Bytes, or Extension Bytes, how Lunar Magic calls them), are a feature that was already present in Romi's Spritetool, they represent 2 bytes of data that can be defined in the .cfg/.json file and they will be set globally on that sprites' slot.

This means that if you have a sprite in slot 00 and you set the extra property bytes to 01 02, then every instance of that sprite in the game will have those bytes set to 01 02.

This feature is completely superseded by the Extra Bytes, which are pretty much superior in every way. However, for retro-compatibility purposes, they are still supported.

The second extra property byte ($7FAB34) also holds some extra information for some obscure features in the top 2 bits:

ov------

o: if this bit is set to 1, the sprite will run the MAIN code in any state (e.g. any value of $14C8) and will skip the corresponding vanilla code

v: if this bit is set to 1, the sprite will run both MAIN and vanilla code in any state (e.g. any value of $14C8)

Custom status handling

As most people know, Pixi relies on 2 print statements to tell the game what code to run in which state of the sprite.

Most importantly, state 08 will run whatever code is under the "MAIN" print statement and state 01 will run whatever code is under the "INIT" print statement.

All the other states will run the corresponding vanilla code, however, some bits in !extra_prop_2 can be set to activate certain functions. Setting bit 7 of that byte will make the sprite run its MAIN code in any state and it won't run the vanilla code, setting bit 6 will make it run both vanilla code and the custom MAIN. This is already explained above but repeated for clarity.

Since Pixi 1.2.16 you can have more control over other states that are not 08 and 01 by using new print statements crafted just for the occasion, valid print statements FOR NORMAL CUSTOM SPRITES are:

Common Errors

The vast majority of the time, xkas code will work just fine with Asar, the assembler that PIXI uses exclusively.

If you do get errors trying to use a sprite that worked fine in the xkas-based SpriteTool, here are some common sources:

JMP (label,x) or JSR (label,x)

Asar does not want to guess at the size of these instructions. You will have to append ".w" to the JMP/JSR instruction, to let Asar know that the pointers are 2 bytes in size (or a "word", hence the "w"). This would look like this corrected:

JMP.w (label,x) or JSR.w (label,x)

JMP $xxxxxx

xkas accepted the JMP $xxxxxx instruction, despite it technically not existing. JMP is intended to jump to addresses in the same bank as the instruction, but $xxxxxx (note the 6 bytes) points at an absolute place in the ROM. To fix this, change it to use the absolute JML command instead, like this: JML $xxxxxx

Faulty Math or Wrong Register size (inserts fine but crashes in-game)

xkas and Asar handle assembler math a little differently. If your sprite assembles fine but ends up crashing, this will often be the fault of them disagreeing on how to read a bit of math. Asar tries to go the logical route while xkas does its own thing.

If this happens to you, search for occurences of assembler math (such as LDA #$08+05^$FF or LDA #!define<<(!otherdefine\*8)) and specify the register size as before.

Usually this means appending ".b" to the instruction (for example LDA.b #!define<<(!otherdefine\*8)), but in other cases it might also be ".w" or ".l".

Sometimes the math arguments themselves have to be rewritten too, which might be a little harder.

If you can't figure it out yourself due to lack of ASM knowledge, feel free to ask on the SMWCentral forums.

incsrc/incbin file not found

Romi's sprite_tool handled the insertion of sprites slightly differently than PIXI. That is, it created a copy of the sprite in the main directory of the exe and then patched it, whereas PIXI just creates temp file which references the original sprite.

As a result, old sprites that use the incsrc or incbin command had to take the full path to the sprite into accound but PIXI doesn't.

Example:

  Romi:
  incbin "sprites/data.bin"
  PIXI:
  incbin "data.bin"

Aknowledgements

Maintainers