Map Editor Documentation

Mods

What a .sosmod package is, the two sample mods line by line, applying a mod in single player, multiplayer and by link, dependencies, and exporting one from The Forge.

Page 16 of 22

A map is a playable scenario: terrain, placed units, players, triggers. A mod is a portable package of changes that applies on top of a map: data overrides, triggers, custom sounds and 3D model references, with no terrain and nothing placed. One balance mod can be played on every map; one map can be played with or without it.

A mod is a single JSON file with the extension .sosmod.

What is in a .sosmod

{
  "$schema": "https://shardsofstone.com/schemas/v1/mod-package.json",
  "formatVersion": 2,
  "id": "sos_balance_ironclad",
  "name": "Ironclad Balance Patch",
  "version": "1.0.0",
  "author": "Shards of Stone",
  "description": "",
  "minEngineVersion": "0.3.0",
  "dependencies": [],
  "defOverrides": { },
  "triggers": { },
  "sounds": { },
  "models": { }
}
FieldRequiredMeaning
idYes1–64 characters: lowercase letters, digits, _ and -, starting with a letter or digit
nameYesDisplay name
versionYesMAJOR.MINOR.PATCH. Anything else is a warning, and breaks version ranges in dependencies
authorYesWho made it
descriptionNoShown with the mod
formatVersionNoWhich version of this file format it uses. Absent means 1; current is 2
minEngineVersionNoThe oldest game version that can load it
dependenciesNoOther mods that must be applied first, see below
defOverridesNoData overrides
triggersNoA trigger script
soundsNo{ "id": "https://…" or "data:…" } for playSound
modelsNo{ "key": "https://…" or "data:…" }, referenced as "modelUrl": "mod:<key>"
tags, category, homepage, createdNoMetadata

Unknown top-level fields are rejected by the JSON Schema. A package with no overrides, triggers, sounds or models is valid but gets a warning, since it does nothing.

Size. A package can be at most 20 MB, and a single embedded data: URI at most 5 MB. Host larger models and sounds on an https:// server and reference them by URL instead.

The two sample mods

Both ship with the game in public/mods/, so you can read them, validate them and play them.

sos_balance_ironclad

A small balance patch that shows each kind of change:

  • Patches dwarf_ironguard to 70 HP and 4 armour, and goblin_brawler to cost 55 gold. The brawler patch is { "cost": { "gold": 55 } }, and because objects merge deeply, its lumber, stone and oil costs are untouched.
  • Clones a new upgrade, dwarf_tempered_plate, from dwarf_attack_1: +1 armour for ironguard and royal guard, researched at the barracks for 125 gold and 25 stone.
  • Appends that upgrade to the barracks' research list with { "researches": { "$append": ["dwarf_tempered_plate"] } }, so it appears without replacing the barracks' existing research.
  • Patches a hero: borin gets statOverrides.hp of 100.

sos_frost_warden

A content mod that adds a unit, and depends on the first mod:

  • "dependencies": [{ "id": "sos_balance_ironclad", "version": "^1.0.0" }].
  • Models: two entries in models, frost_warden_body and frost_warden_anims. (They point at the runesmith's own model files on the game's CDN, so the sample works anywhere; your mod would point at your own.)
  • A sound: frost_warden_cry, a URL to an .mp3.
  • A spell clone: frost_warden_glacial_bolt from rune_blast, 45 damage, 30 mana, on the q hotkey.
  • A unit clone: frost_warden from dwarf_runesmith, 60 HP, 180 gold, with "modelUrl": "mod:frost_warden_body" and a spells patch that removes the runesmith's spells and prepends the glacial bolt.
  • Trainable: the runic library's produces gets { "$append": ["frost_warden"] }.
  • A trigger: on map initialisation, once, show "The Frost Wardens have answered the call…" and play frost_warden_cry.

Applying a mod

A mod is applied when a custom map is launched. It is never baked into a map you save.

  • The Mod picker. The map browser and the multiplayer lobby's custom-map panel have a Mod control: Load .sosmod to pick a file, Clear to remove it. The chosen mod stays active for the browser tab.
  • A link. /play?customMap=<map>&mod=<id> or /play?communityMap=<id>&mod=<id> loads the mod from /mods/<id>.sosmod on the site. That only works for mods hosted on the site, such as the two samples: /play?customMap=tower-defense-showcase&mod=sos_balance_ironclad.
  • The validator. /tools/validator can test a mod directly: paste it, and Test in Game launches it on a blank map.
  • An embed. A page embedding the game can send a mod with its map; see Web APIs.

Mods only apply to custom maps. The campaign and ordinary skirmish are never modded.

In multiplayer

Only the host needs the mod. The host's game resolves the mod and its dependencies, merges them into the map, and sends the merged map to everyone along with a checksum of the map and the mod's id and version. Every player's game checks that checksum before the match starts, and again at the start signal. If anything differs, the match does not start, and the message says Map integrity check failed with both checksums, rather than the match desyncing later.

Guests see a read-only Mod: name vversion line in the lobby.

How a mod merges into a map

Mods apply in order: dependencies first, then the mod itself, each on top of the result so far.

  • defOverrides. Entries are matched by id within each kind. A mod entry for an id the map already overrides is applied after the map's patch, as if both patches ran in sequence. If the mod gives that id a different baseId, the mod's entry replaces the map's entirely.
  • triggers. Triggers and regions are matched by id; variables (vars), functions and hashtables by name. A mod entry with the same id or name replaces the map's whole entry; anything else is added, and the map's other entries are kept.
  • sounds and models merge by key, the mod winning.

Dependencies and versions

A dependency is { "id": "...", "version": "..." }. The version accepts:

RequirementMatches
1.2.3Exactly 1.2.3
^1.2.01.x.x, at least 1.2.0 (for 0.x, the same minor)
~1.2.01.2.x, at least 1.2.0
>=1.2.01.2.0 or anything newer
*Any version

When a mod launches, its dependencies are loaded from /mods/<id>.sosmod. A missing dependency, a version that does not match, or a cycle refuses the launch with a message naming the problem. The validator reports the same things before you ship. Run it over several files at once (npx tsx tools/validate.ts a.sosmod b.sosmod) and it checks them against each other.

minEngineVersion is compared with the game's version. An older game refuses the package with "This package needs game version X or newer".

See Compatibility & Versioning for how versions should move when you change a mod.

Making a mod in The Forge

  1. Build the changes on a test map: data overrides in the Data module (F7), triggers in the Trigger module (F6).
  2. File → Export Standalone Mod (.sosmod)… writes a package of the map's data overrides, triggers, sounds and models. The id comes from the map name (lowercased, other characters turned into _), with version 1.0.0 and author Forge Modder.
  3. Open the file in a text editor and set id, name, version, author and description properly. Add dependencies and minEngineVersion if you need them.
  4. Validate it: npx tsx tools/validate.ts my_mod.sosmod, or paste it into /tools/validator.

The export takes the map's whole trigger script, regions included, because triggers reference regions by id. Region coordinates come from your test map, so a mod whose triggers use regions only makes sense on maps laid out the same way. When the mod is applied, a region with the same id on the target map is replaced by the mod's copy. (The trigger script is only exported when it has at least one trigger or variable.)

To bring a mod's changes into a map you are editing, use File → Import Standalone Mod (.sosmod)…. It merges the package's data overrides, triggers, sounds and models into the map by the same rules, so mod:<key> model references keep working in the saved map, in Test Map and when published.

Sharing a mod

There is no mod upload or mod gallery yet. Share the .sosmod file however you share files; players load it with Load .sosmod. Mods hosted in the game's own /mods/ folder, which today means the two samples, also work with ?mod=<id> links.

Next: Compatibility & Versioning.