Quantcast
Channel: nesdev.org
Viewing all articles
Browse latest Browse all 746

Human-Readable SMB Levels

$
0
0
Hello, just wanted to share some recent work on my SMB meta disassembly and get thoughts on how usable something I've put together is.

So one of my goals in setting out on this was to ensure as much of the data as possible is defined in terms of constants that draw from the real layout of the code. This means that derived values like object assignments for mappings would derive their numerical constants directly from the placements of labels in code, stuff like that. The referenced disassembly for all of this is here: https://gitlab.com/segaloco/smb/

Well, I've started working this stuff up for levels and landed on something that honestly wasn't part of the plan but is kinda nice:

Code:

courses_data_overworld_6:.word(COURSE_AREA_LEDGE_TREE|COURSE_BG_MNT_BUSH|COURSE_FG_MASK_1|COURSE_TIMER_SETTING_1|COURSE_DATA_ENTER_POS_B0_A|COURSE_DATA_FG_NONE).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_4|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_5).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_5|COURSE_OBJ_C_BLOCK_Q_A).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_6|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_7|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_9|COURSE_DATA_POS_X_C|COURSE_OBJ_PIPE_VERT_B|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_8|COURSE_DATA_POS_X_6|COURSE_DATA_NEW_PAGE|COURSE_OBJ_PIPE_VERT_B|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_E|COURSE_OBJ_PIPE_VERT_B|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_9|COURSE_DATA_NEW_PAGE|COURSE_OBJ_PIPE_VERT_A|COURSE_DOWNPIPE_MASK|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_6|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_C_HIDDEN_ONE_UP).word(COURSE_DATA_TYPE_C|COURSE_DATA_POS_X_5|COURSE_OBJ_A_PIT|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_D|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_3).if.defined(SMB).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_E|COURSE_OBJ_C_BLOCK_Q_A).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_8).elseif.defined(VS_SMB).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_C_BLOCK_Q_A).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_1|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_7).endif.word(COURSE_DATA_TYPE_C|COURSE_DATA_POS_X_6|COURSE_OBJ_A_PIT|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_B|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_E|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_E|COURSE_OBJ_C_BLOCK_COIN).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_4|COURSE_DATA_NEW_PAGE|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_1).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_5|COURSE_OBJ_C_BLOCK_ITEM_C).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_A|COURSE_OBJ_C_BLOCK_Q_B).if.defined(SMB).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_D|COURSE_OBJ_C_BLOCK_Q_A).elseif.defined(VS_SMB).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_D|COURSE_OBJ_C_BLOCK_Q_B).endif.word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_D|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_6|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_1).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_9|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_3|COURSE_DATA_POS_X_0|COURSE_DATA_NEW_PAGE|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_4).word(COURSE_DATA_TYPE_C|COURSE_DATA_POS_X_1|COURSE_OBJ_A_BLOCK_QHI|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_1|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_2).word(COURSE_DATA_TYPE_F|COURSE_DATA_POS_X_6|COURSE_OBJ_B_STAIRS|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_C|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_8|COURSE_DATA_POS_X_D|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_9|COURSE_DATA_POS_X_E|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_A|COURSE_DATA_POS_X_F|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_1).word(COURSE_DATA_TYPE_F|COURSE_DATA_POS_X_4|COURSE_DATA_NEW_PAGE|COURSE_OBJ_B_STAIRS|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_8|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_4).word(COURSE_DATA_TYPE_C|COURSE_DATA_POS_X_9|COURSE_OBJ_A_PIT|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_B|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_4).word(COURSE_DATA_POS_Y_8|COURSE_DATA_POS_X_C|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_3).word(COURSE_DATA_POS_Y_9|COURSE_DATA_POS_X_D|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_A|COURSE_DATA_POS_X_E|COURSE_OBJ_FLOORCOL|COURSE_OBJ_DIM_1).word(COURSE_DATA_POS_Y_9|COURSE_DATA_POS_X_3|COURSE_DATA_NEW_PAGE|COURSE_OBJ_PIPE_VERT_B|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_8|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_2).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_A|COURSE_OBJ_C_BLOCK_Q_B).word(COURSE_DATA_POS_Y_7|COURSE_DATA_POS_X_B|COURSE_OBJ_BRICKROW|COURSE_OBJ_DIM_1).word(COURSE_DATA_POS_Y_9|COURSE_DATA_POS_X_3|COURSE_DATA_NEW_PAGE|COURSE_OBJ_PIPE_VERT_B|COURSE_OBJ_DIM_2).word(COURSE_DATA_TYPE_F|COURSE_DATA_POS_X_5|COURSE_OBJ_B_STAIRS|COURSE_OBJ_DIM_9).word(COURSE_DATA_TYPE_D|COURSE_DATA_POS_X_6|COURSE_DATA_NEW_PAGE|COURSE_DATA_TYPE_D_MASK|COURSE_OBJ_D_POLE).word(COURSE_DATA_TYPE_F|COURSE_DATA_POS_X_A|COURSE_OBJ_B_CASTLE|COURSE_OBJ_DIM_7).byteCOURSE_DATA_END
This is SMB world 1-1 decomposed into a number of preprocessor symbols. While my intention was to make it such that you can easily add and remove objects without messing up indexing, a happy side effect is you can read down that list and essentially plot out the level, it's not a formidable wall of binary data, but rather a human-readable description of the level object layout.

I've also written a tool to take a description of a level, as ".word" directives for ca65, and convert it into this format: https://gitlab.com/segaloco/misc/-/blob ... gobj_dec.c

Naturally since these are defined in my code, this tool isn't immediately applicable to decoding levels for use with other diassemblies.

In any case, I thought I'd share this in case folks have thoughts, ideas on how to extend the concept, etc. Note I haven't touched the actors yet but that'll probably follow a similar process, the data format is something comparable with packed bits for different fields. Also is anyone aware of somewhere these formats are documented thoroughly? While I was starting work on this part I found some docs concerning this format but for the All-Stars version of the game that aren't entirely applicable to the original 8-bit version. If not I wanted to offer to draft up some more formal notes for...wherever SMB hackers go look for their information.

Thanks for any feedback/thoughts!

Statistics: Posted by segaloco — Thu Jun 27, 2024 11:28 am — Replies 2 — Views 114



Viewing all articles
Browse latest Browse all 746

Trending Articles