Tutorial:Submodding
Originally written by Cataph
If you’re a modder, one of the most frequent comments next to romantical proposals (YMMV) will be “SFO/Radious/CTT/Lucky/yomama compatibility when”. Many modders don’t have an interest in making a submod simply because they don’t know and play a given overhaul and wouldn’t know how to balance it anyway.
So, what if it could be you making that submod? Or maybe you just want to make X mod work better with Y. Be the submodder you want to see in the world!
A few things first.
WHAT IS A SUBMOD?
Basically, an optional plugin designed to make mod X work or work better with mod Y, thanks to this mod Z. A user that wants to use X and Y together will download mod Z and keep all three enabled.
Can a submod be a standalone? Well, yes, but it wouldn’t be a submod then, would it? Besides, it’s normally a dick move to take mod X and fully reupload it with a few differences. Plus, it’s 90% never necessary and we’re going to see why.
Ok, but can I just edit a mod and keep it to myself? Sure, keep in mind that you should rename the pack into something else to avoid automatic updates to overwrite what you changed.
WHY IS A SUBMOD?
I need you to focus.
HOW IS A SUBMOD?
Fine, thank you. About how it’s made, we don’t necessarily need mod X and Y to make sweet love to each other but only you, bloke with a basic knowledge of RPFM and TW modding.
WHAT DO?
Ok, as a basic example let’s say we want a compatibility submod between the Sea Patrol mod and a fictional 2x unit size mod, so we want to grab whatever lines define unit numbers in the former and multiply those by 2. Daring.
First thing we open the first mod as a reference, then we create a new pack for the submod. We’ll call it seapatrol_yourname_unitsize.pack. (more on naming later, but sit tight)
Upon viewing the db of Sea Patrol we see a whole lotta tables.
Since I am a bloke with basic knowledge of RPFM and TW modding, I know that unit sizes are in main_units.
Thus, in the submod I’ll import said table/s by right click>Add…>Add from Packfile, find the pack, find the table and double click it. Close the add from packfile panel and we’re good to go, we have Sea Patrol’s main_units in our shizzle. We go in there and edit the numbers we want to change, in this case we select any num_men that is not a hero/lord’s, right click, apply math as {x}*2 and done. Done? No, some of those units may be cavalry, so we need to adapt the number of mounts too. We import land_units as well and do the same thing on num_mounts. In the rarer case that there’s a multi-chariot unit, we leave mounts alone and multiply num_engines in land_units.
PRIORITY
But it’s a submod, and we want to make sure we’re overriding the original mod’s values. No, not with load order on the mod manager, and incidentally you shouldn't touch that and you should use KMM.
We currently have two tables, we select those table fragments (in this case, called “AK_seahelm”) and we rename them to take priority according to this alphanumerical order:
! # $ % & ‘ ( ) + , – ; = @ 0-9 a-z [ ] ^ _ ` { } ~ Where “!” wins over “a”.
Usually, adding a “!” in front does it. But we also want to make clear what submod this is for. Right click> Rename> type !{x}_unitsize, which will become “!AK_seahelm_unitsize”.
Note: DO NOT leave the table names as is, or you’ll crash. DO NOT leave a number as last character or it might glitch and crash anyway.
Aaaand, done! Now this submod of only two tables will correctly override unit sizes for a specific mod. Yeah, any non-vanilla key will be red in here, since you don’t define those in your pack, but no worries, it’s a submod that is designed to exist with the mod that actually has those keys.
In the possible case you need at some point to override parts that don't answer to table priority, like images or variants or whole script files, you might want to name the entire pack with a prefix that wins priority over the original mod. For example, again, “!AK_seahelm_unitsize”. Considering you don't want users to manually change load order, this makes sure that by alphanumerical order you're already overriding the og mod. Notice that you can't change a pack's name after you've uploaded it to the workshop.
Now, like with any mod we make a PNG icon and upload if we want to share it publicly. If you upload it on the workshop, add mods X and Y as required by clicking on Add/Remove Required Items. This will prompt a user to go and fetch those required mods as well. Most of them will somehow ignore it and crash, but at least you tried.
ADDENDUM: ETIQUETTE
By most accounts, a clean submod like the above doesn’t really need permission since you’re not stealing anything. However, you should still ask as good courtesy, and it can’t hurt to still let the og author know as they may link it in description, let you know about required changes, etc.
It’s also good practice not to add donation links to a submod.
ADDENDUM: UPDATING
It should be your interest and responsibility to stay up-to-date with the original mods as soon as you have time. For example if you’re submodding a unit mod and you see the ‘parent’ mod has updated with balance changes, some key changes or new units, you should definitely hear a couple bells ringing.
Sometimes the parent mod changes a few keys and then you might even crash until you update.
SUBMODDING EXAMPLE: TRANSLATION
In most cases, translating a mod is a simple case of grabbing all of that mod's loc files (text db) and following what we've seen so far. So, make sure you only have the parts you need, remove the rest, rename your loc with a prefix that gives them priority. Then, start grinding at the actual translation work in those loc tables.
There may be some fringe cases where there is text on images or inside scripts. As we mentioned, you might need priority over the whole pack in terms of naming. It also gets trickier changing the text on a picture, and you might want to contact the other fellow if you need to translate a text that is directly embedded in a script. Ask if there's a way to avoid you having to grab the entire script, which is normally a bad idea.
ADVANCED SUBMODDING: BALANCE OVERHAULS
The submodder should also be the one who is familiar with the overhaul they’re adapting a mod for. If you are at a loss about how to tweak some things, definitely consider asking one of the two original modders (depending on the kind of question) for advice on how to proceed. For example, “this unit is weird and I’m not sure what role it should keep”.
Can't be much more specific about this because there are so many possible moving parts that you need to change, starting with unit stats to their place on new recruitment buildings. Staying up-to-date is particularly important in this kind of mod.
UNIQUE NUMERICAL IDs
In some tables, each line has a unique numerical id in front of it (or sometimes way off like in unit_special_abilities). That’s specific for each line, and it works like other important keys like those in land_units or main_units, as in there can only be one line about that key or num id.
Why am I saying all this? Because if in your submod you happen to need to add some lines in, for example, building_units_allowed, you’ll need your own unique num ids to make them work proppa. Pick any number below 2 billions and something and make sure they never repeat. This is important, do not continue off the num ids from the mod you’re submodding or you’ll cause issues at some point.
ADVANCED SUBMODDING: STICKY TABLES
Some tables and related features are slightly more complicated to submod. For example, you want to remove a unit from a certain building level. Easy, go in building_units_allowed again. Remember those unique ids? Keep that exactly intact (so it still refers to that specific line from the original mod or vanilla line) and change the building to something that has no chance of being available, such as wh2_dlc12_dummy_nuclear_ruins_0
or change the unit instead to a unit that is completely unavailble as well for anybody who has access to the given building. You could change both to be sure, but it's more confusing down the line.
Until WH2, you could have typed random gibberish in the building key to better track your changes (e.g., add "_removed" to building keys), but in WH3 that causes a crash as both fields need to be valid.
The underlying logic is that you're hijacking a precise data line (due to the unique id, numerical or not) and telling it to do something impossible.
Harder example: I really don’t want any of these units to have the new-fangled Edgelord Deluxe passive ability, which is added by this mod. Cool, that means I can kill that ability from existence without it ever affecting anything else. We do that by:
- grabbing its line from unit_abilities, we make it hidden in UI.
- grabbing its line from unit_special_abilities, we make it a passive (boolean). Make sure you remove any activated projectile/bombardment/summon etc from here too.
- grabbing its line in special_ability_to_special_ability_phase_junctions. Change the phase to a new special_ability_phase that we created and that does absolutely nothing. There, done. The ability still exists, but does nothing and is invisible. In my own private jargon this is called a pillow. Again, notice that you’re neutering this ability for any unit that happens to get it.
This currently doesn't really work in WH3 and I really hope they fix that because it's a serious problem.
Even harder example: I want this unit to not have the Regeneration passive ability. Oooh, that’s a vanilla ability, isn’t it? We can’t just dumpster it. Either we tolerate it or…
ADVANCED SUBMODDING: DEPENDENCY MANAGER
This is a RPFM feature. USE WITH CAUTION, as it's essentially a data coring method.
We enable it by right clicking on the packfile itself in tree view (not on a table, not on anything else, literally the very first line in tree view), Open>Open Dependency Manager. We add a line as if it was a table (ctrl+shift+A) and type EXACTLY the pack name of the mod we want to override. As in “AK_seahelm.pack”. From this point onwards, everything we do in the submod under identical paths will completely override content from the parent mod no matter the load or table order for stuff with the same name. Example, I can import a table, not change its name and completely delete its content. This would normally crash, but not with DepManager.
I said use this with caution because if you do this you REALLY need to stay up-to-date with the og mod. For example, you can remove the line that gives unit A the Regen passive, and it will work. However, any further update from the parent mod in that table won’t take place unless you also mirror it. Again, this is normally not remotely required and you should steer clear of it because it’s just as bad as leaving a vanilla table called “data__”.
Additionally, this will auto-enable the linked mod as soon as it’s in data/ as if it was a movie pack. As such, you don’t want to do this unless you’re doing a submod that already requires that linked mod. Because having stuff popping up even when you’ve disabled a mod is the worst.
ADVANCED SUBMODDING: BACKGROUND TABLES
Let's say we aren't doing a submod whose only purpose is changing unit size for that other mod, but it's our own standalone mod A and we're doing some compatibility stuff to make it work better with B, without needing a separate submod C that requires both. For example, we want something from B in A, if B is also enabled. Sometimes we can do that without C.
Let's say I add some new units in A, and mod B adds fancy officers to all units. Officers are connected to the unit in db/land_units, but if we just pasted B's officer key in there, A would go boom if B is not enabled. We don't want that, and we may not want to force people to use B. So we paste that officer key there, replacing A_blank_record, but we also check what table that key relies on by hovering on its top (title, header, whatever), which is... db/land_units_officers. Without it, that officer key is going to go boom, because it's not a tolerant key, at all, to the point that even a non-existant officer needs an actual key called A_blank_record, which does exist.
What we do is create land_units_officers, add that officer key under key, keep personality location as front or rear (honestly don't know if that crashes if left blank, don't care), but we leave the officer 1 etc columns empty. IMPORTANT: we rename this table fragment with something like zzzzz_mod_a_mod_b. Notice the zeds? Keep those in mind.
So, what is this doing? It's telling the unit that it's going to use that officer group, but it's got nothing in it, no actual officers (battle_personalities). By using our mod A without B, the game finds an empty box for this officer, shrugs, and doesn't replace unit models with any officer personality. The game moves on without crashing, because that key exists. Basically, we created another blank record, but this very specific one gets filled in when B is enabled.
Remember those zeds? They are there so that our blank record gets overridden by B's table (which we assume has a higher alphabetical priority than a bunch of zeds, unless B's author is not trying hard enough). Keep in mind that if B's author ever changes those officer keys you won't crash, but you'll still need to adapt because your blank record would stay blank.
This can be done in a bunch of situations, but you'll need some specific knowledge of how specific contexts work. You could want to use this method to nerf some effects from mod B, in which case you might need more than one background table (the zzzzz boys), including db/effects, which by itself does absolutely nothing, but using an effect key that doesn't exist in there will go kaboom.
ADVANCED SUBMODDING: SCRIPTS
Uhh, sorry, not my field, but generally speaking trying to change or override a script cleanly is highly specific to what the script does and how it's written, in other words whether you can snipe the specific function you want to change or if you have to grab the whole thing.
Some scripty fella should probably add more tips here.