Snake's Pit of ASM (and Other Stuff)

I’ve been sitting on this for way too long, but I’m finally putting a little time to releasing it.

Support Rework Rework

That’s right. My own Support Rework from about 2 years ago is such a mess of me sneezing asm code around that I felt it necessary to rewrite it in C. While the older version was a little buggy, the new version has been behaving nicely in my own working project. Anyway, I’m proud to finally release it.

Features include all from the original version plus:

  • EIGHT unique support levels. That’s right. Eight. Should anyone use eight support levels? I don’t know I’m gonna wizard’s creed my way out of that one. If you don’t want that many you can have fewer. (I only use three lmao)
  • Enhanced stat screen drawing. I’ve gotten better at custom drawing routines, and I’ve made the stat screen look nicer. This also includes @HyperGammaSpaces’s chadly support R text system which looks GREAT. Thank you, Gamma, for developing that!
  • This is a C hack! Old support rework was all written in thumb, making it pretty error prone. This source should look much cleaner.
  • The hack is fairly separate from base conversations now. They work well together, and if you want base conversations, use the version that comes with Support Rework Rework. Otherwise, no sweat!
  • The utility macros (for modifying unit support data via events) should be easier to use now.
  • There is support for the Skill System talk bubble to appear if there is a viewable support convo in a chapter.
  • Probably more stuff? tbh I “finished” this a while ago and just now touched it up for release. Shoutouts to @Alaric for nudging me to release this!
I suppose that the instructions for using this hack will be similar to before, but I'll reiterate them

So you wanna use Support Rework Rework. Great! These instructions are going to be long not because the system should be difficult to use but moreso because I want to provide as much documentation on how to use it as I can.
You’re going to want to download the entire Support Rework Rework folder from my link in the OP and include SupportRework.event in your buildfile.
The first thing that this file does is include SupportReworkDefinitions.event, a file that defines various macros and such. Some of these macros are used in events to control support data. If necessary depending on the layout of your buildfile, you can include this file earlier in your buildfile.
This definitions file defines values for your various support levels. The example levels given are

#define CSupport 0
#define CPSupport 1
#define BMSupport 2
#define BSupport 3
#define BPSupport 4
#define AMSupport 5
#define ASupport 6
#define APSupport 7

representing C support, C+ support, B- support, etcetera. Change these as you see fit. These are just silly examples. Just make the IDs between 0 and MaxSupportLevelVal inclusive and unique. Speaking of MaxSupportLevelVal, define that to be your highest support level. I’ll get to the rest of the things in this file later. You don’t need to touch them.
Back in SupportRework.event, the SupportLevelNameTable is a table indexed by support level (remember the definitions we just discussed?) with each entry as a pointer to a string that represents that support level. You shouldn’t need to touch anything else in this file.

I’ll talk about externalish hacks next.
Firstly, Support Rework Rework supports easy integration with Base Convos. Refer to my post about that hack for instructions on how to use it. SupportReworkDefinitions.event defines a single additional base conversation macro, baseSupport(Character1,Character2,Level), where the first two parameters are the character IDs of the two supporters, and Level is the support level the conversation should try to raise to. If the current support level is not one less than the current level (or nonexistent if the level to raise to is 0), then the conversation will not be viewable. If you DON’T want to use base convos, that’s perfectly fine. Just comment out the #include "CBaseConvos/BaseConvos.event" line in SupportRework.event.
The next external hack that’s relevant is my prep screen hack which makes editing the prep screen main menu a lot less painful. I discuss what needs to be done there in the base conversation hack post. (It’s just incorporating a CSV and making an edit iirc). This is only relevant if you are using base conversations. Otherwise just ignore this.
Finally, a small hack to the CHARASM event handler is included that makes CharacterBasedEvents-based support conversations work. It just makes it such that a character event usability routine returning 2 makes the conversation usable without making any other checks.

Support Rework Rework supports support-by-support defining of stat bonuses just like the older version but hopefully in a cleaner way. You’ll define the values you want in SupportReworkBonusTable.event.
This is a (nonindexed) list of support entries. Start an entry with the entry(char1,char2) macro, then fill in your support level bonuses with the support(level,... stats) macro. There are a couple examples in the file to start you off.

Uh what else… all that’s left is controlling supports via events I think.
Okay there are three ways to control support data:

  • Adding base conversations to prep screens to allow players to increase supports there
  • Adding “talk conversation-like” support conversations to allow players to increase support levels mid-chapter
  • Manually changing support data via events

For base conversations, you can simply use the aforementioned baseSupport macro, and a default event will be used. This is the simplest way to do this. If you’d like, you can also use a custom event for extra modularity. Writing custom base conversation events is discussed in that hack’s post. To make it a “support” convo, you can just call one of the event macros that I will discuss shortly. For the usability of the conversation to match generic support convos, use usability(SupportBaseConvoUsability|1), characters(Character1,Character2), and supportLevel(Level). You’ll also likely want textGetter(SupportBaseConvoMenuTextGetter|1). If you know what you’re doing, feel free to make your own custom alternatives to these generic functions!
Next, talk conversations. I’ve designed the system to make support conversations function just like mid-chapter talk conversations. Whenever you want the player to be able to increase a support, use one of the SupportConvo macros defined in SupportReworkDefinitions.event in CharacterBasedEvents. If you provide just a text ID for the last parameter, a generic event will be used to play the text then increase the support level. If you choose to pass in an event, it will play that event instead. This should be pretty straightforward.
Finally, you can pretty easily change support data. Macros to do so are also in SupportReworkDefinitions.event for use in event scripts with descriptions. I think these are pretty straightforward as well. I think these should work pretty well, but let me know if you hit unexpected behavior with these. IncreaseSupport and SetSupport will make a new support if one doesn’t already exist. If you try to add a support with max supports or if you try to increase a max level support, nothing should happen.

Small note: Any character ID of 0xFF is interpreted by the system as representing whoever is in the first character struct. This was useful to me, and I left it in because why not.

Oh. Last thing is stat screen stuff. I’ve hooked into the vanilla function that draws supports to… well draw the new supports. In your modular stat screen, you should just need to call that vanilla function (it should be in MSS defs) to draw supports. What I use for page 4 RText is included. (Thanks again to gamma for the support RText system!)

That should be about it I think. Let me know if anything weird happens, and have a nice day!


Thank you so much Snakey for your amazing ASM hacks!

1 Like

I’m gonna release a tool that I forgot to release.

Don’t like manually defining arbitrary custom IDs? Just want your definitions to be sequential and unique? No? Yes? Don’t care? Then put your hands together for :drum::drum::drum::drum::drum:


This is a small tool that takes lists of strings that you want to be defined and gives them all unique, sequential IDs. I find this especially useful for defining a lot of custom items, classes, characters, animations, etc where I really don’t care what the ID is, but I do care that the ID isn’t shared with some other item, class, character, animation, etc.

This tool should be easy to use I hope

This was written in Python, and as always get it from the link in the OP.

For an example on how I abuse extensively use this script, feel free to check out my working project github:

This was designed to play nicely with TableManager, my CSV assembler, which doesn’t care what IDs actually are. What I find quite nice to do (I’m totally not biased I didn’t create this system or anything) is let Enumerate hand out arbitrary IDs to all my shit, have TableManager work exclusively with definitions, then use definitions elsewhere. I think this is a much cleaner method than manually defining IDs personally.

The command line arguments for this are:

enumerate (inputfile) (outputfile) (optional -c flag to delete output flag on error)

The input file I’ll get to in a sec. The output file will contain a huge list of #define YourDefinition 0xDefinitionIDs that you can simply include.
Now the input file is a file where you list things you want to be definitions.

I'll just give a straightforward example as to how it should look.
Jasper 0x01

This inputted will output

#define Jasper 0x01
#define Derek 0x02
#define Val 0x03
#define Helmer 0x04
#define Baret 0x05
#define Walter 0x06
#define Vicar 0x07

That’s the basic idea.

You can restart numbering like
Jasper 0x01
Helmer 0x10

and this will produce

#define Jasper 0x01
#define Derek 0x02
#define Val 0x03
#define Helmer 0x10
#define Baret 0x11
#define Walter 0x12
#define Vicar 0x13

There are a couple other directives I’ve got for ya. You can .include files to start a new numbering system. If you .avoid value1 value2, numbering will… well avoid assigning definitions between those values inclusive.

An example with avoid:
.avoid 0x03 0x05
Jasper 0x01

This will produce

#define Jasper 0x01
#define Derek 0x02
#define Val 0x06
#define Helmer 0x07

You can line comment with @ or // just the same. If you have overlapping IDs within the same file, the program will throw an error. Whitespace lines are ignored.

I think that’s about it. It’s a small script, and I’m open to suggestions for improvements and additions.

Hope this makes someone’s life easier. Enjoy! :+1:

Fast edit: I’ve also just reorganized my opening post now that there are more links accumulating there.


TSA is SO SCARY like what even IS it? How do I deal with it? What do you MEAN width and height - 1? Flips? What’re those? Ew icky. Why is the palette even bitpacked in there if BgMap_ApplyTsa lets you use different palettes wtf?!?
Yeah that’s how I feel about TSA too. It’s weird and confusing and a pain unless you have…


That’s right. You can use Tiled to generate TSA now. This is a long time coming, and I’m excited to release it. It’s really easy; all you need is an image of the tilesheet you’re basing your TSA on and tmx2tsa.exe. It’s that simple.

How to: Make epic custom tile-based UI

Okay so this is an executable with the following command line signature:

tmx2tsa (input.tmx) (ouput.dmp) (optional -p palette ID, default 1 since that seems to be what most UI uses) (optional -c filepath to compress.exe if you want it to be compressed)

After running, just #incbin the dmp!

When opening a new .tmx file to start, be sure that your tile width and height are both 8.

So normally we use Tiled in hacking for chapter maps, right? The "tiles" we use for chapter maps are NOT the same as "tiles" in the general sense.
  • In general for the GBA, a tile is a square of 8x8 pixels that is rendered to tile VRAM and displayed on a BG map by tile ID. TSA is for ordering these tiles.
  • In the chapter map sense, a tile is a square of 2x2 tiles (so 16x16 pixels), so when creating chapters, your settings are 16x16 per tile.

Just be sure that you have 8x8 per tile when using this tool. I hope this clears up confusion.

Anyway, I think the only other setting that matters in here is the Orthogonal setting. Set your width and height accordingly. Each other setting is arbitrary.

Next, I’m going to assume that you have an image of the tile sheet that you want to use. If someone requests it, I can include how I get this image.

Import this tile sheet as a tileset again with 8x8 tiles. From then on, it’s just like making a chapter map! PROTIP: On my Tiled setup at least, press X and Y on your keyboard to horizontally and vertically flip the tile you’re currently placing! Another fun thing is that Tiled updates your tile sheet in real time if you’re making edits to it, so this works well for fancy custom tiles as well. Don’t leave empty space I guess… I think that’s it. Once you’re finished with your tiles, run tmx2tsa on it, and your TSA is good to go!

Wait so what exactly is TSA again?

Someone please correct me if I’m wrong in this section.
I’ve been told that TSA stands for Tile Squaroid Assembly. Weird but whatever everyone calls it TSA. It is a ROM data structure that tells the game what tiles go where. Generally that’s really it.

It seems to often be used for UI, so let’s take that as an example. Say you want to display a UI blue box. First, you would load the tile sheet that you would use in tmx2tsa to tile VRAM and load the palette. (I believe most of the time there’s a single function that does both of these for you.) Your graphics are loaded in the form of tiles, but now you need something that actually renders the tiles. That’s where TSA comes in. I have the C structure signature of TSA as

struct Tile
	u16 tileID : 10;
	u16 horizontalFlip : 1;
	u16 verticalFlip : 1;
	u16 paletteID : 4;

struct TSA
	u8 width, height;
	Tile tiles[];

The structure begins with a width byte and a height byte. The structure represents a rectangle on the screen where you want to render the tiles. The X and Y positions are completely irrelevant to the structure itself, but width and height are… but these are actually width-1 and height-1. Don’t ask me why. The rest of the structure is an array of tiles (each tile is a short). The tiles run from left to right and bottom to top. Again don’t ask me why. Each tile is bitpacked where the bottom 10 bits refer to the tile ID, the next bit is for horizontal flip, the next is for vertical flip, then the top 4 bits are for palette ID.

See how this could be a headache to deal with?

You would then call BgMap_ApplyTsa to refer to your TSA and set your tile references to the BG map. (Actually you’d almost certainly set your tile references to the BG map buffer then have to enable BG sync but whatever.)

I’ve most recently made a little bit of custom UI for world map things. If you’d like an example on how I use it, I invite you to check there. Here’s what I was able to whip up for an edit to the world map text box!

Hope to see a bunch of new custom TSA out there! Have a nice day :wave:


I’ll believe it when I see it for myself. :stuck_out_tongue:
But seriously, this is very cool. Will massively help with UI development.

But I do have a question, and feel free to correct me if I’m being obtuse and didn’t see it somewhere. But does this tool generate compressed TSA, or uncompressed TSA?

I’m glad you asked. It does both! Without the -c parameter, the executable will output uncompressed TSA. If you do pass -c file/path/to/compress.exe, the output will be lz77 compressed.



It’s a buildfile-friendly average statter. This program will take data straight from your class and character CSVs and predict a unit’s stats at a certain class and level.

Here are some example screenshots of the script in action

This is running a “wrapper” batch script that actually calls the executable. I’m running from the command line, but you can also double click the batch script just the same.
The program will prompt you for some input information and output the average stats.

The prompting should be pretty user friendly I hope.

Plenty of extra options to play with including handling promotions.

You can also have the program run a number of simulations instead of generating average stats. The program will report the average stats of all simulated units and report standard deviations, letting you know how much certain stats on individual units vary!

You can also use argparse flags to skip the prompt. If you don’t include necessary parameters, you’ll be prompted for them. Use ./predict -h to see these flags!

How to: Actually know how your units will turn out instead of just sneezing stats around

As always, get everything you need from my download link in the OP.

Like I said, the program reads data straight from your class and character CSVs, so it needs some way to be able to know where your CSVs are and what columns and rows to grab stats from. This is performed through an options file which requires one-time setup.
Notice that I’ve been using a wrapper batch script instead of directly calling the executable. That’s because the first parameter of the executable is the filepath to this options file. The batch file then passes in its own parameters into the program.

The default filename for the options file is (in the same directory as the batch script and program) PredictorOptions.s. This can be changed in the batch script. With this options file, whitespace is ignored, and you can line comment with @. Your lines should look like the following:


A column name of just 0 will represent a column of all 0 data! This is useful… for example… how characters have no movement stats? Use ‘0’ for the character movement base and growth column names in that case. The order of the stats is arbitrary but should be kept consistent.
An example options file is included.

Now you can use the script. Here are the option flags (and how to view them):

There are only three required inputs: The character name, the starting class, and the target level. The character’s starting level field in the character table is used for starting level. If you do not supply these required inputs, you’ll be prompted.
Any character and class IDs are searched by row name. If I want to refer to Jasper and Cavalier, I can do this only because my row names for that character and that class are exactly Jasper and Cavalier. This is designed to play nicely with TableManager.
The rest of the parameters are optional (and if you are prompted for any required parameters, you’ll be prompted for these as well).
--TARGET_CLASS (class name) indicates that you want to promote to the defined class. Set a promotion level with --PROMOTION_LEVEL (level). Default is 10.
--TARGET_LEVEL (level) is the ending simulation level (promoted if a promotion is desired).
If --SIMULATION_COUNT (count) is not defined, average statting as you’d expect will be used. If it IS defined, then the defined number of simulated units will be generated, and their average stats will be displayed along with standard deviations for each stat.
--round rounds average stats.
If --generic is used, then the unit is treated as generic. Class growths are used instead of character growths.
--table_help outputs help for the table options file, and --verbose is really for debug.

I’ve written this mostly for myself, and this is how I would want my own tool to behave. I’m open to feedback and requests, though. I hope someone makes good use of this. Have a nice day!

Edit: Thanks to @Huichelaar for reporting: I’ve also fixed a bug in TableManager associated with improper output with certain options.


Okay one more thing and I’ll stop spamming my own thread. :stuck_out_tongue:

Before I’d been using a single Google Drive folder to contain all of my shit, but this time with tmx2tsa's release, there’d been a problem. Google thought it was a virus! (Bold of Google to figure I’d be able to write malicious code :roll_eyes:) I’m honestly not sure why this script was stopped and not any others? tmx2tsa is by far my shortest piece of software, and all of the other .exes (as far as I know) uploaded fine.

I didn’t see a solution that involved sticking with Google (lmao the request staff revision link was a 404), so I’ve switched to Github. The new repository link is in the OP, so go ahead and use that for now on. I’ll be scouring the thread and removing any links elsewhere as well.

I didn’t and don’t intend to embed viruses in my few .exes that I’ve released. Use them, and they won’t hurt your computer. If you’re not comfortable with that, it’s perfectly okay. I include the source, and you can run the script or compile it yourself if you like.

tldr Google is mean to me :pensive: Have a nice day!



Would it be possible to define a custom terminator to lists using TableManager? I’ve run into lists which put values in fields --which are otherwise 0 in regular entries-- in their vanilla terminators.

Of course it’s possible to specify these fields in the nightmare module. In the csv file, one could leave them as 0 for all entries, and put in the terminator value (often 0xFF or something similar) for the terminator. It just fills the spreadsheet with not so interesting data.

1 Like

That’s a good idea! What do you think a good format would be on the user side for declaring what the terminator should be for relevant lists?

Bit ugly, but maybe something like the last line in this?

CSV Character/BattleQuotes.csv
  TABLE BattleQuoteTableLABEL Character/BattleQuotes.nmm
  TERMINATOR FFFF0000000000000000000000000000

Where each two hex digits represents a byte. It’d be nice to have full control over what the terminator looks like, because vanilla terminators can differ.

1 Like

That’s what I was thinking, except in my mind there would be spaces in between each byte :thinking:
Either way this looks like something I’d be happy to implement sooner or later.

1 Like

Perhaps I’m missing/not understanding something, but for the support rework rework, what would you say is the recommended way to carry support chains over to the next chapter if you didn’t get them? And is there a default way to make unlocking supports still require points to do?

Essentially, can you recreate the FE9/FE12 support system with this tool?

Carrying over supports into the next chapter isn’t something that the system is designed to do. Right now all it does for chapter usability is make the conversation viewable on the chapter you specify.
If you want FE9 supports, I think you should be able to do this by making the conversation available in every chapter it could possibly occur in. This wasn’t the implementation I had in mind when designing the system, but I think it should work.
There is no support for support points, though. The system lets you choose support timing by chapter, not by point growth.

1 Like