Overworld Data Format
LM-related information is accurate as of version 2.53.
- 1 Position Format
- 2 Layer 1
- 3 Layer 2
- 4 Sprites
- 5 Silent Events
- 6 Hardcoded Paths
- 7 Star Warps and Pipes
- 8 Exit Paths
- 9 Destruction Events
- 10 Level-Specific Data
- 11 Level Names
- 12 GFX Files
- 13 Palettes
- 14 ExAnimation Data
- 15 Message Box Text
- 16 Castle Destruction Text
- 17 Boss Sequence Levels
- 18 Music
- 19 Special World Changes
- 20 Miscellaneous
Layer 1 data often uses a format for a tile's position referred to here as "#$0SYX format". This is a format that is composed of the tile's X position mod 16 (X), Y position mod 16 (Y), and submap (S). Submaps are ordered as:
|Forest of Illusion||3|
|Valley of Bowser||4|
Keep in mind on submaps, the positions are offset from the way they appear in Lunar Magic. On all six submaps, subtract one from the X position (so the left-most column in LM is actaully on the right side). As an example, the position of Yoshi's Island 1 is #$0183 - submap 1, Y position 8, X position 4 (4 - 1 = 3).
Note that this submap offset also affects Layer 2 (subtract 2 from X, 1 from Y) and sprites (subtract #$10 from X, #$08 from Y).
The origin of this format isn't from any kind of index; instead, it's a combination of three addresses related to Mario's position: $1F11, $1F1F, and $1F21. As such, if you get a position from these addresses (or alternatively $1F17/$1F19), you won't have to account for the offset.
Layer 1 data is loaded to $7EC800 during gameplay. In an LM-modified ROM, $7FC800 also contains the high-byte of each tile.
To locate a specific tile there, use an index with the format
%-----YYX yyyyxxxx, where YYyyyy is the Y position of the tile and Xxxxx is the X position. On submaps, subtract 1 from the X position.
|$05D000||Tilemap for each individual Layer 1 tile. Four 8x8 tiles per tile, with two bytes per 8x8 (tile number, YXPCCCTT).||(read1($04DCC1)<<16)|read2($04DCBC)|
|$0CF7DF||Tilemap for the entire overworld, uncompressed. Loaded to $7EC800 during gameplay.||$0CF7DF|
|N/A||High bytes for the Layer 1 tilemap, compressed in LC_LZ21 format. Decompressed to $7FC800.||(read1($04D827)<<16)|read2($04D821)|
1 Or LC_LZ3 if the ROM uses it.
Layer 1 Events
Layer 1 events directly overwrite data in $7EC800.
|$04D85D||Location of the Layer 1 tile that each event reveals (#$0SYX format).||read3($04EDBE)|
|$04D93D||VRAM locations to write the data for each event.||read3($04EDB8)|
Note that only one tile can be revealed per event by these tables. To reveal more, silent events must be used.
The list of what tile reveals what can be found at $04DA1D (before tiles) and $04DA33 (after tiles). These also correspond to Lunar Magic's "reveal tile list".
Layer 2 data is stored in two compressed tables. They're decompressed to $7F4000 in an interleaved [tile number], [YXPCCCTT] format.
To locate a specific tile in the decompressed data, index the data with ((Y * 40) + X) * 2 for an X,Y position. On submaps, subtract 2 from X and 1 from Y.
|$04A533||Layer 2 tile numbers, compressed in LC_RLE1 format.||(read1($04DC79)<<16)|read2($04DC72)|
|$04C02B||Layer 2 tile YXPCCCTT, compressed in LC_RLE1 format.||(read1($04DC79)<<16)|read2($04DC8D)|
Layer 2 Events
Layer 2 events directly overwrite data in $7F4000. $0C8000 and $0C8D00 are decompressed to $7F0000 in an interleaved [tile number][YXPCCCTT] format.
|$04DD8D||Table of data for all the events. Four bytes per tile; the first two are the 'source' (index to $0C8000), and the second two are the 'destination' (index to $7F4000).||read3($04E49F)|
|$04E359||Indices to $04DD8D, indexed by event number. The number of tiles in any given event is determined by the difference from the next event's index (i.e. [event + 1] - [event]).||$04E3591|
|$0C8000||Tilemap (tile numbers) for the event tiles, uncompressed. The first x9002 bytes are the 6x6 tiles, while the next x400 are the 2x2.||read3($04EAF5)|
|$0C8D00||Tilemap (YXPCCCTT) for the event tiles, compressed in LC_RLE1. Has the same format as $0C8000 when uncompressed.||(read1($04DD4A)<<16)|read2($04DD45)|
To convert tile numbers in LM to indices in $0C8000, 6x6 tiles can be found as
#$24 * tileNum, while 2x2 tiles can be found as
(#$04 * tileNum) + #$0900*.
1 If Lunar Magic's overworld level expansion hijack is applied, this table is instead moved dynamically to
2 It should be noted that LM has an option to change this amount. To get the size in case it changed, use
Sprite data is stored in a table at $04F625 (even in an LM-edited ROM), with 5 bytes per sprite. The first byte is the sprite number, then the 16-bit X position, and then the 16-bit Y position. The submap offset still applies to sprites, as well; subtract #$10 from the X position and #$08 from the Y position when on submaps to account for this.
However, that there is no distinction for positions between the main map and submaps. When loaded into VRAM, only one tilemap is loaded at a time: either the main map, or all the submaps (a demonstration of the overlap can be seen here). So, every sprite position technically refers to two spots: one on the main map, and an equivelent location on the submaps. Because of this, most sprites are coded to only actually appear on one or the other.
Certain sprites, specifically the overworld ghosts and Yoshi's House smoke, do actually exist on both tilemaps simultaneously. Similarly, the fish and Koopa Kid sprites both spawn three sprites despite only taking up one entry in the table. A list of the table locations for these unlisted positions are below:
|$04FC1E||16-bit X positions for the two smoke sprites; the first is the main map, and the second is Yoshi's Island. This sprite can not be used on other submaps.|
|$04FC22||16-bit Y positions for the two smoke sprites; the first is the main map, and the second is Yoshi's Island. This sprite can not be used on other submaps.|
|$04F666||16-bit X offsets for the three submap ghosts from their main map counterparts. #$0001 will move the ghost one pixel right, #$FFFF will move it one pixel left.|
|$04F66C||16-bit Y offsets for the three submap ghosts from their main map counterparts. #$0001 will move the ghost one pixel down, #$FFFF will move it one pixel up.|
|$04FA2E||Low byte of the X position for the three overworld fish, indexed by the Layer 1 tile that spawns it (4E-50).|
|$04FA31||High byte of the X position for the three overworld fish, indexed by the Layer 1 tile that spawns it (4E-50).|
|$04FA34||Low byte of the Y position for the three overworld fish, indexed by the Layer 1 tile that spawns it (4E-50).|
|$04FA37||High byte of the Y position for the three overworld fish, indexed by the Layer 1 tile that spawns it (4E-50).|
|$04FB88||Low byte of the X position for the overworld Koopa Kids, indexed by the Layer 1 tile that spawns it (49-4B).|
|$04FB8B||High byte of the X position for the overworld Koopa Kids, indexed by the Layer 1 tile that spawns it (49-4B).|
|$04FB8E||Low byte of the Y position for the overworld Koopa Kids, indexed by the Layer 1 tile that spawns it (49-4B).|
|$04FB91||High byte of the Y position for the overworld Koopa Kids, indexed by the Layer 1 tile that spawns it (49-4B).|
As a sidenote, the main overworld sprite data is only read a single time on titlescreen load, then never again.
As of Lunar Magic v2.50, a second sprite table exclusively made for custom sprites has been added. Unlike the original table, this one does not have a fixed size; you can have up to 24 custom sprites per submap. This table can be found with
The first part of the data is 16-bit indices to each submap's data, in the standard submap order (for a total of 14 bytes). The second part is the actual sprite data. Each sprite has 4 bytes associated with it:
|Custom Sprite Data Format|
|xnnnnnnn yyyXXXXX hhhhhYYY eeeeeeee|
|XXXXXx||X position (in 8x8s, relative to either 0,0 or 2,41).|
|YYYyyy||Y position (in 8x8s, relative to either 0,0 or 2,41).|
|hhhhh||Height. Determines how "far above the ground" the sprite should appear.|
Lunar Magic does nothing with this table outside of allowing you to edit it, however, so the data currently serves no purpose until a tool implements it.
"Silent" events are LM's name for a special set of Layer 1 and Layer 2 event data that plays no sound effects or fade effect. Additionally, however, they don't update VRAM, and as such don't appear on-screen until the tile is reloaded. Because of this, they're mainly intended for tiles that are supposed to appear offscreen or in another submap.
The original game and Lunar Magic take two different approaches to this data, however. The original game has a table of the events associated with each offscreen event tile; once the event is found, the index for it is then used as the index to all other related tables. Lunar Magic instead changes this to use a 'divider'-like table of indices for each event, with the difference between one event's index and the next's determining the number of tiles used by it.
|$04E8E4||The original game's indexing system. Contains event numbers associated with an offscreen tile, with the index for the event used as an index to the below tables. One event can have multiple entries.||N/A|
|N/A||Lunar Magic's indexing system. Contains 16-bit indices to the below tables; the number of tiles per event is determined by the difference between the current event's index and the next.||read3(read3($04E9F8)+$0D)|
|$04E910||Indicates whether the tile is on Layer 1 (#$00) or Layer 2 (#$01).||read3(read3($04E9F8)+$34)|
|$04E93C||16-bit locations of each tile, as direct indices to the Layer 1 tilemap at $7EC800 or Layer 2 tilemap at $7F4000.||read3(read3($04E9F8)+$28)|
|$04E994||16-bit tile number to use. For Layer 1 tiles, this is just the tile number as normal; for Layer 2, it's the tile's index in $0C8000.||read3(read3($04E9F8)+$22)|
Hardcoded paths are special Layer 1 paths that aren't displayed or editable by Lunar Magic. They function by temporarily overwriting the Layer 1 tile Mario is walking on until he eventually reaches a level tile.
|$049078||Translevel numbers that have hardcoded paths. #$FF indicates Chocolate Island 2's pipe (see $049082/$049084).|
|$04910E||Index table for each of the translevels at $049078 to the hardcoded path data.|
|$049086||Hardcoded path data. This consists of a list of all the Layer 1 tiles that Mario walks over, ending in a level tile.|
|$0490CA||Directions Mario moves on each of the tiles listed at in the hardcoded path data; the first value also determines the direction of the path from the original level tile. #$00 = up, #$02 = down, #$04 = left, #$06 = right.|
|$049082||16-bit X position of Chocolate Island 2's pipe, as a sprite position (i.e. Mario's position on it).|
|$049084||16-bit Y position of Chocolate Island 2's pipe, as a sprite position (i.e. Mario's position on it).|
Star Warps and Pipes
Star warps and pipes are combined under a set of tables. The source positions are the location of the warp's Layer 1 tile (00-1F), while the destinations are positions for Mario (in pixels, not tiles).
If a tile's position can't be found in the source tables, the warp/pipe won't function at all. The destinations can be anywhere.
|$048431||Two-byte values containing the source tile X position (first byte) and submap (second byte) for each warp.||read3(read3($04850A)+$14)|
|$048467||Two-byte values containing the source tile Y position (first byte) for each warp. Second byte is unused.||read3(read3($04850A)+$24)|
|$04849D|| 16-bit destination X position and submap for each warp, in the format
|$0484D3||16-bit destination Y position.||read3(read3($048567)+$19)|
Exit path data is spread across two 5-byte tables and a third 2-byte table. Note that positions in this table correspond to Mario's (i.e. sprite) position, not the tile's position.
|$049964||Exit path location table (where Mario enters). Order is the 16-bit Y position, 16-bit X position, and 8-bit submap.||read3(read3($049A36)+$11)|
|$0499AA||Exit path destination table (where Mario exits). Order is the 16-bit Y position, 16-bit X position, and 8-bit submap.||read3(read3($049A36)+$2C)|
|$0499F0||Extra exit path destination table (where Mario exits). This contains two bytes per path, for the destination tile's Y and X position respectively.1||read3(read3($049A36)+$48)|
1 Generally, this table is just the positions in $0499AA divided by 16. However, if Mario exits moving upwards or leftwards, you should subtract 1 from the Y or X position respectively before dividing.
Destruction events change castles, fortresses, and switch palace to an alternative tile after being beaten. In order for the destruction animation to occur, Mario must also be on a specified level tile at the time an event is beaten (although reloading the overworld will cause the tile to be destroyed anyway).
|$04E5B6||Locations of the levels with destruction events (#$0SYX format).||read3($04E69C)|
|$04E587|| VRAM locations to store the destroyed tiles for each event, written as the first two bytes of its stripe header (
|$04E5D6||List of events that activate a destruction. Only used on overworld load, for reloading previously-destroyed tiles.||read3($04E67C)|
Each translevel has an assigned event and normal/secret exit directions. In the original game, translevels themselves are not actually stored anywhere in the original ROM, and are instead assigned automatically as level tiles come up in Layer 1 data.
Once assigned, translevels for each Layer 1 tile are written to a table at $7ED000 and exit directions are written to a table at $7FD800. These tables are formatted the same way as the Layer 1 tilemap at $7EC800, so if you have the index to a level tile there, you can get its translevel and exit directions from the other two tables using the same index.
Lunar Magic, of course, changes translevels to be assignable on a tile-by-tile basis. It stores both the translevels and exit directions to a table at
(read1($04D808)<<16)|read2($04D803), compressed in the LC_LZ2 format (or LC_LZ3 if the ROM has it enabled). This data decompresses to $7ED000 as normal.
The data tables for the directions and event associated with that translevel, however, remain unmoved:
|$04D678|| Direction to move after beating a level, indexed by translevel. Formatted as |
|$05D608||Events triggered by each translevel.|
1 Technically, SMW parses directions for two additional exits, formatting this as
%aabbccdd. However, these exits can not be used without custom ASM, and Lunar Magic does not provide a method of editig them anyway.
Initial Save File Data
A number of details about a level are stored to $1EA2 during gameplay. Some of this data is automatically set once a save file is started, mainly for enabling certain paths between level tiles. The original game and Lunar Magic differ slightly in how this is done, however, as detailed in the table below.
Additionally, $1F11-$1F26 are also preset on file creation, for Mario/Luigi's initial positions.
|$009EE0||The original game's initial flag table. Each entry consists of two bytes: the first is the translevel to modify, and the second is the flags to set in $1EA2.|
|$05DDA01||Lunar Magic's initial flag table. Every translevel has a single byte, containing the flags to set in $1EA2.|
|$009EF0||Initial values for $1F11-$1F26.|
1 If Lunar Magic's overworld level expansion is applied, $05DDA0 is moved to $03BE80.
SMW uses a complicated name-lookup system, which involves splitting each level's name into three parts, which are then directed to a set of three offset tables. While it saves space, it's not particularly easy to work with.
|$049AC5||The level string table, indexed by the three offset tables. If the high bit of a byte is set, it indicates the last character in the string.|
|$049C91||Offset table A. If the first byte pointed to has the high bit set, this part is completely skipped.|
|$049CCF||Offset table B. If the first byte pointed to is #$9F, this part is completely skipped.|
|$049CED||Offset table C.|
|$04A0FC|| Assembly table for each level's name. Contains indexes to the offset tables in a 16-bit format: |
Lunar Magic logically scraps this system entirely, for a single large table at
read3($03BB57) containing every level's name (19 bytes per name).
SMW uses a system similar to the one use in levels, where it uses a table of lists containing the four GFX files for each submap.
However, it has all the maps use the same files, making it somewhat redundant. SMW doesn't normally reload GFX files when loading a new submap either (only on level exit), so having different files would likely cause broken graphics.
|$04DC02||Layer 1/2 GFX lists for each submap, for $00A92B.|
|$00A92B||Layer 1/2 GFX files (FG1-FG4) for each list. Overworld files specifically begin at $00A96F (lists 11-17).|
|$04A907||Sprite GFX files (SP1-SP4) for the whole overworld.|
Lunar Magic changes this to a single table containing all sixteen 16-bit ExGFX files for each submap, for 32 bytes total per submap. This table can be found at
(read1(read3($00A141)+$12)<<16)|read2(read3($00A141)+$09). The ExGFX files are ordered as:
Addionally, AN2 and LT3 contain some extra information in their high bytes:
|3||Enable Layer 3 Bypass|
|T||Enable Layer 3 Tilemap Bypass|
|DD||Layer 3 destination for file|
|SS||Layer 3 file size|
SMW stores the overworld palettes in a somewhat complicated way by assembling it in parts from a large palette table.
Colors themselves are stored in the standard 16-bit SNES RGB format (
|$00AD1E||Table of Layer 2 palette IDs for each submap, as values for indexing to $00ABDF.|
|$00ABDF||16-bit pointers to the palette table for each Layer 2 palette ID, starting at $00B3D8 (normal) or $00B732 (Special World passed).|
|$00B3D8||All the Layer 2 palette data (palettes 4-7, colors 1-7). Default order is Yoshi, main, Star, Vanilla/Bowser, Forest, Special.|
|$00B732||All the Layer 2 palette data (palettes 4-7, colors 1-7) after the Special World is beaten. Default order is Yoshi, main, Star, Vanilla/Bowser, Forest, Special.|
|$00B528||Layer 1 palette data (palettes 2-7, colors 9-F).|
|$00B58A||Sprite palette data (palettes 9-F, colors 1-7). Note that palette F is also used for animating the lightning effect.|
|$00B5EC||Layer 3 palette data (palettes 0-1, colors 8-F).|
Lunar Magic scraps this system in favor of a single table instead. This table contains all 14 512-byte palettes for the maps (7 normal, 7 special), and can be found at
ExAnimation data is stored in two parts, the first being the general animation information and the second being the individual animation information.
|General Animation Format|
|SS||Highest used animation slot, plus 1|
|EE||Which alternate GFX file the submap uses|
|CCcc||Which custom triggers start uninitialized, bitwise|
|IIii||Initial states for each custom trigger, when initialized|
|MMmm||Which manual triggers are initialized, bitwise|
|FF...||Frame numbers to initialize each of the specified manual triggers to|
|DDdd...||Indices to each animation slot's data1 (with #$0002 referring to the byte after this value)|
1 Indices are included up to the highest used slot. If a slot before that isn't used, its indice is 0000.
|Individual Animation Format|
|FF||Number of frames (-1)|
|DDdd||Tiles only: VRAM destination*|
|DD||Colors only: number of colors to animate (-1)1|
|dd||Colors only: palette destination|
|MMmm...||Memory address for each frame's tile/color data, or direct SNES RGB values when animating a single color|
1 The highest bit being 1 indicates the slot uses the sumbap's alternative GFX file.
Global ExAnimation data can be found with
read2(read3($048087)+$61) returns #$0000, the ROM has no global ExAnimation data.
The 24-bit pointers to each submap's ExAnimation data can be found with
read3(read3($048087)+$E1). If the second byte of the pointer is #$00, then that level doesn't have animation data.
Additionally, there's a 512-byte table at
read3(read3($048087)+$4A) that stores each submap's animation settings.
|P||Disable original game's level dot palette animation|
|T||Disable original game's tile animations|
|S||Disable LM's submap animations|
|G||Disable LM's global animations|
The fifth option in the animation settings, for disabling the original game's lightning palette animation, is a bitwise value at $04F709. With 1 indicating disable:
|f||Forest of Illusion|
|b||Valley of Bowser|
Message Box Text
The original game handles message box by searching a table of levels that actually use them.
|$05A590||Which translevels have message boxes. The high bit being set indicates message 2. The first 4 bytes are reserved for switch palaces, and the last (index x16) for Yoshi's House. If a message's level isn't found, index 0 is used by default.|
|$05A5A7||Indices to the start of each message's text at $05A5D9.|
|$05A5D9||All of the message box texts (tile numbers only). The high bit being set indicates a new line, and the 8th new line indicates the end of the message.|
Lunar Magic exchanges this system for a new one that skips the translevel table.
|$03BE801||16-bit indices to the data for each message. Indexed by ((level * 2) + message number) * 2.|
|read3($03BC0B)||The actual message data. For the most part, just raw tile numbers with 26 tiles per line, with the message ending after 8 lines. However, #$FE is used as a special value that prematurely ends the message's data.|
1If Lunar Magic's overworld level expansion is applied, $03BE80 will instead be moved dynamically to
read3($03BBD9). Furthermore, it will consist of 24-bit pointers directly to the data rather than 16-bit indices.
Castle Destruction Text
Castle destruction text is handled by SMW's general stripe image upload routine, with its data pointed to by the list at $0084D0 (indices #$21-#$C6). Each line of the message texts has its own pointer there, although the lines for each message are in reverse (i.e. the first pointer is line 8, second is line 7, etc.). The messages themselves are in the correct order, though. Lunar Magic dynamically moves them, though, so you should check the pointer rather than the data as a whole.
$0CBE85 (or wherever Lunar Magic moves it) is where the text data actually begins. This data are written in the standard stripe image format, including the full 4-byte header.
Boss Sequence Levels
Lunar Magic's 'boss sequence levels' list refers to levels that activate special events or scenes after the level's end. These aren't located in a single location, however, and instead are at several locations:
|$00C9A7||Translevel numbers that activate each castle destruction cutscene, starting with Iggy. The last byte, at index 7, corresponds to Front Door.|
|$00CA13||Translevel number for Back Door.|
|$04E660||Translevel number that causes an earthquake on the overworld after beating (level 18, Sunken Ghost Ship).|
|$00CA0C||Translevel number where defeating the boss activates the secret exit (level 13, Donut Secret House).|
The music for each submap is stored in a 7-byte table at $048D8A.
There's also a table at $048D74 that's worth noting. It contains the translevels (in 16-bit) that prevent the overworld music from loading after beating their boss, causing the overworld to be silent outside of sound effects.
Special World Changes
Lunar Magic's "Special World levels" list corresponds to a few different locations. Rather than actually being stored as a level number, the values at these locations are actually addresses, specically the address in $1EA2 that corresponds to the level (i.e. $1EA2 + the translevel number).
|$00AD2B||Translevel address (minus 1) that changes the overworld colors.|
|$02A986||Translevel address that changes green/red Koopas into blue/yellow Koopas.|
|$00AA74||Translevel address that changes sprite graphics for Koopas, Piranha Plants, and Bullet Bills.|
|$019826||Translevel address that prevents shells from displaying Koopa eyes (as part of the changed sprite graphics).|
|$01B9CD||Translevel address that changes the climbing net Koopa's animation slightly (as part of the changed sprite graphics).|
|$02A986||Translevel address that changes the enemy names in the credits (as part of the changed sprite graphics).|
The list of no-auto-move levels are at $04906C, as translevels in 16-bit.
The list of level tiles that automatically activate save prompts after beating are at $048F7F.
The list of level tiles that can be destroyed (i.e. switch palaces, castles, forts) are at $04E5A7. Their 'after' tiles are at $04E5AC (upper tile) and $04E5B1 (lower tile).