Load order and overrides
How the game decides which mod wins, and how to change the base game without editing it.
Every enabled mod is loaded, in order. When two mods provide the same thing, the one later in the load order wins. That single rule is how you change the base game: you never edit ul_Base, you ship a file that replaces or extends one of its files, and put your mod below it.
The load order
Mods/LoadOrder.txt holds one line per mod, folder_name|1 (enabled) or folder_name|0 (disabled), top to bottom:
textul_Base|1
ul_Pregnancy|1
ul_Health|1
yourname_nightlife|1
yourname_test|0
- The game writes this file; players reorder and toggle mods in the Mods panel of the pause menu. You can also edit it with the game closed.
- A newly discovered mod is enabled and appended at the end, so a freshly installed mod overrides what came before it.
- Shipped modules are discovered before
Mods/, so on a fresh install they sit on top. ul_Baseis locked: it is always first and cannot be disabled.- A mod deleted from disk disappears from the file the next time it is written.
What "wins" means, per kind of content
Not everything is replaced the same way. Some content is keyed by an id, some by a file path, and a few JSON files merge field by field.
| Content | Identified by | A later mod… |
|---|---|---|
Scenes (.ulscene) |
File name, without folder or extension | replaces the whole scene |
Actions (.ulaction) |
ACTION_UNIQUEID |
replaces the whole action |
Stats (.ulstat) |
STAT_ID |
replaces the whole definition |
Quests (.ulquest) |
QUEST_UNIQUEID |
replaces the whole quest |
History events (.ulhistory) |
id |
redefines the event type completely |
Majors (.ulmajors) |
Major name | replaces that major |
| Images, meshes, animations | Path relative to Images/, Meshes/, Animations/… |
replaces the file |
| Cities | City name | replaces the city |
Map/amenities.json |
Venue tag | merges: only the fields you write change |
Map/player_panel.json |
Stat id | adds to stats, removes what you list in remove |
Map/city_styles.json |
Style name | replaces that style |
Map/vehicles.json |
Vehicle id | replaces that vehicle; traffic merges per field; left_hand_cities adds |
Look profiles (.ullook) |
Venue tag (tag / tags) |
merges: patches only the fields it sets |
Lua libraries (Lua/*.lua) |
Nothing: every file runs | runs after, so it can wrap or overwrite earlier globals |
Activities (.ulactivity) |
Activity id | adds ids or replaces them |
Examples
Replace a base scene. ul_Base has Interactions/leading_to_scenes/ask_out.ulscene. Your mod ships Scenes/ask_out.ulscene: the folder does not matter, the name does, and yours now runs instead.
Rebalance an action. Copy the .ulaction, keep its ACTION_UNIQUEID, change what you want. Yours replaces it entirely, so copy every field you want to keep.
Change one venue's opening hours without copying the whole file:
json{
"amenities": {
"bakery": { "open": 5, "close": 13 }
}
}
Saved as Map/amenities.json in your mod, this changes the bakery's hours and leaves every other field, and every other venue, as it was.
Retexture something. A mod that ships Images/Health/virus.png replaces ul_Health's icon of the same relative path.
This is why the base game keeps its content in files you can shadow instead of lists in code. Opening hours, map icons and venue roll weights are all things we could have hardcoded; because they are files, "change the bakery's hours" is a four-line mod.
Namespaces
Anything identified by name lives in one namespace shared by every mod. Two unrelated mods that both ship date_start.ulscene replace each other; the log says so ('date_start' from ul_B replaces the one from ul_A), and mod/name (ul_A/date_start) still reaches the replaced one, in RunSceneScript, SCENE_ALWAYS or a quest step.
Prefix what you create:
| Thing | Good | Risky |
|---|---|---|
| Mod folder | yourname_nightlife |
nightlife |
| Scene file | ynl_bouncer.ulscene |
bouncer.ulscene |
| Action / stat id | ynl_order_shot, ynl_drunk |
order_shot, drunk |
| Lua global table | Nightlife |
Config, Utils |
| Story global, person var | ynl_met_bouncer |
met_bouncer |
Only reuse a name on purpose, when you mean to replace something.
Only .ulscene files are scenes. Your libraries, routines and HUD scripts (.lua) live in their own folders and never clash with a scene name.
Depending on another mod
When your mod uses another mod's content (its stats, its Actor: methods, its globals):
- List it in
MODULE_REQUIREMENTS. Your mod then only loads while that one does (the Mods list says Blocked and why otherwise), and the game keeps it below that one in the load order. - For a soft dependency, guard the calls instead, so your mod degrades rather than breaks when the other one is missing:
luaif Game:isModEnabled("ul_Health") then
Actor:infect("flu")
end
A soft dependency (extra content when the other mod is present) is that check without the requirement line.