Modding Special Eras

Modding Guide
3 Nov 2022, 1:51 p.m.

Special eras are one of the features that I introduced in the co-op and conquest update in August. These work by temporarily changing the rules of the game, and may also have a victory condition, where an empire can be rewarded for ending the era early.

Like pretty much everything in the game, these are data-driven, so you can add new ones by modding. Here's how.

(This post assumes that you know how Airships mods work. If you want an introduction to basic modding, check out this article first.)

Play in Airships progresses through a series of eras, which slowly change the game balance, decreasing the unrest from empire size, and increasing base research and the number of spies available. Each era has a chance to be a randomly chosen special era, which accumulates over time, so that while not every era is special, you will definitely get some special ones. You can see this information in StrategicEras in the game data. Of course, you can also mod this, changing the tempo and balance of the overall game if you wish.

Special eras are stored as EraModifiers in the game data. There is also always a bonus of the exact same name, which is active while the era is active. (So whenever you create a new EraModifier, create a Bonus with the same name.)

It's probably a good idea to open eraModifiers.json with your text editor so you can see concrete examples of what this article is about.

You can also download and read the example mod that adds one new EraModifier.

Here's a very simple EraModifier, Age of Plenty:

{
    "name": "AGE_OF_PLENTY",
    "pattern": 12,
    "eraIcon": { "src": "ui", "x": 80, "y": 384 },
    "eraImg": { "src": "bountiful.jpg" }
},

So apart from the name, we want a 16x16 icon for the era, a 400x300 image for the announcement dialog, and a background pattern for the dialog. (The patterns are numbered 0-24 and can be found in data/images/patterns.png. You can also leave out this value, but it's prettier if you have a suitable pattern!)

There are also three strings in en.properties associated with this modifier:

bonus_AGE_OF_PLENTY=Age of Plenty
age_desc_AGE_OF_PLENTY=An age of bountiful harvests.
age_fx_AGE_OF_PLENTY=+15% income\nDouble fleet resupply speed

So that's the name of the era, a prose description of what's happening, and a list of gameplay effects. (\n is a new line character.)

But how does this actually do anything? By being a bonus! As you may know, bonuses can have all kinds of gameplay effects in the game. For example, the AGE_OF_PLENTY bonus is used in the EmpireStat value for city income:

{
    "name": "CITY_INCOME_PERCENTAGE_BONUS",
    "value": {
        "base": 0,
        "deltas": {
            "EXTRA_INCOME": 15,
            "AGE_OF_PLENTY": 15,
            "LONG_WINTER": -15,
            "LONG_SUMMER": -10,
            "AGE_OF_STORMS": -10,
            "GREATER_CULT": 15,
            "AUTARKY": 5,
            "TEA": 5
        }
    }
},

There's a lot of EmpireStats that bonuses can modify - here's a full list. They can also unlock city upgrades, modules, and armour and change their stats.

Here's some examples of what an EraModifier could do via bonuses:

  • Decrease the reputation required to start coronation to 70.
  • Double the local defence budget of cities.
  • Eliminate the reputation cost of breaking truces.
  • Make fires nigh on impossible to put out.
  • Double the unrest of cities not connected to the capital.
  • Unlock a new city upgrade that can only be built during the era.
  • Make Suspendium Chambers produce double lift.
  • Allow everyone to train dragon riders.
  • Unlock a new part of the tech tree.

(Note that unfortunately, two mods that replace the same EmpireStat will conflict with each other, so you have to be a bit careful with that.)

So that's the basics for EraModifiers. But they can also do a lot more, creating what are basically time-limited events for empires to participate in.

Spawning City Upgrades

You can spawn city upgrades at the start of an era, using the following fields:

  • eraStartSpawnUpgrade - The CityUpgradeType to spawn.
  • eraStartSpawnNumUpgrades - How many to spawn. The game will try to distribute them evenly.
  • doNotSpawnUpgradeInEmpiresWithBonus - Empires with this bonus won't get any of the upgrades in their towns or cities.

By default, those upgrades will survive the end of the era, but you can also use an era reward (see below) to remove them.

Spawning a Monster Nest

Using eraStartSpawnNest, you can spawn a single monster nest at the start of the era, which can be used to create a "boss monster", such as the pirate king in the age of piracy.

Expeditions

Expeditions let empires send a group of ships to investigate stuff, gaining a random reward upon return.

To enable expeditions, provide a list of rewards in the field "expeditions". The field is also bonusable, so you can provide different sets of rewards depending on what kind of empire sends the expedition.

To give the player an idea of how large a group of ships they should send to get a good outcome, use the fields expeditionLowRewardsBoundary, expeditionMediumRewardsBoundary, expeditionHighRewardsBoundary, and expeditionVeryHighRewardsBoundary.

So for example, if the total value of the ships sent is between expeditionMediumRewardsBoundary and expeditionHighRewardsBoundary, the tooltip will state "Expedition Potential: Medium".

Rewards

Rewards are used both for expedition outcomes and for what happens when an era ending is triggered. They are the same data structure that is used for monster nests. They should have a name, a title, and an image. And they can also have the following fields:

  • money - Money gained.
  • rep - Reputation gained.
  • research - Research points gained. These are applied to the current research, if one is active. Otherwise they are applied to the next research topic chosen.
  • bonus - A bonus to permanently grant.
  • tech - A technology to grant.
  • supplies - Supplies to give to the fleet that unlocked this reward. (Only meaningful for monster nest rewards.)
  • specialConstructionName - Name of a ship or landship to give to the fleet that unlocked this reward. These should be placed in a bonusConstructions folder in the mod. (Only meaningful for monster nest and expedition rewards.)
  • numSpecialConstructions - Number of special constructions to grant, 1 by default.
  • startEraModifier - Start a new EraModifier.
  • endsEraModifier - If this is the current era modifier, end it.
  • destroyAllUpgrades - Destroy all City Upgrades of this name.

There are also some fields that control which reward is picked from a list of possibilities for monster nest and expedition rewards. Note that the game never picks rewards that have no effect, such as ones that grant a bonus that an empire already has. Try to have a fall-back reward that is always valid.

  • spawnWeight - Relative chance that this reward is chosen.
  • onceOnly - This reward can only be given once.
  • requires - Require this bonus.
  • requireResearch - Research must be possible. So if the tech speed is set to No Research, this reward won't be picked.
  • requireMonsters - The game must have monsters, so monster nest density must not be set to None.
  • requireToggle - Require that a specific game feature is toggled on. The names of the available toggles as of this writing are: REPUTATION, DIPLOMACY, CORONATION, ALLIANCE_VICTORY, SUPPLY, and AUTORESOLVE.
  • minWinningFleetCost - Only used for expedition rewards. The expedition fleet must have at least this total cost.
  • maxWinningFleetCost - Only used for expedition rewards. The expedition fleet must have at most this total cost.

Using minWinningFleetCost and maxWinningFleetCost you can make it that larger fleets give better rewards.

Since rewards can both grant and require bonuses, you can use this to tell stories that unfold over multiple expeditions. See AGE_OF_MONSTERS for an example.

Bonusable Descriptions and Effects

Normally, the era modifier description and effects are the strings age_desc_X and age_fx_X, but if you want empires with specific bonuses to have different text, you can use the bonusable values "desc" and "effectsDesc" to specify strings. For example, empires with the REVOLUTION bonus get a different text and info for the Age of Unrest:

"desc": { "base": "age_desc_AGE_OF_UNREST", "REVOLUTION": "age_desc_AGE_OF_UNREST_revolution" },
"effectsDesc": { "base": "age_fx_AGE_OF_UNREST", "REVOLUTION": "age_fx_AGE_OF_UNREST_revolution" }

End Conditions

Last but not least, EraModifiers can have end conditions. When they are met, the era ends. Empires then receive rewards (or punishments) based on who triggered the end condition.

Here are the fields for the possible end conditions:

  • eraEndsWhenControllingUpgrades - When set to true, the era ends when the upgrades spawned at the start are all controlled by one empire.
  • eraEndsWhenClearingNest - When set to true, the era ends when the nest spawned at the start are is defeated by an empire.
  • eraEndsWhenUpgradesBuilt - A CityUpgradeType. The era ends when enough of them have been built, with the empire that built the most being the one that triggers the era end.
  • eraEndsWhenProportionHasUpgrade - Used to determine how many upgrades need to be built to end the era. The number of upgrades is the number of cities x eraEndsWhenProportionHasUpgrade. (This applies even if the upgrades are town upgrades.)
  • eraEndsWhenResearched - A technology. The first empire to research it is the era ender.

End Rewards

When an era end condition is triggered, empires receive a reward based on whether they were the one to trigger the end condition, their bonuses, and the bonuses of the empire that triggered the end condition.

A concrete example: Age of Piety spawns three Holy Sites at the start. Once an empire controls all three holy sites, the era ends, but what exactly happens depends on the empire. A normal empire gains 20 reputation. But if it's Cultists, they instead gain the Greater Cult bonus, a massive permanent increase to income and industry, and the holy sites are destroyed:

"eraEnderReward": {
    "base": {
        "name": "pietyVictory",
        "title": "pietyVictoryT",
        "rep": 20,
        "img": { "src": "temple" },
        "endsEraModifier": "AGE_OF_PIETY"
    },
    "WORM_EYE_CULT": {
        "name": "pietyVictoryCult",
        "title": "pietyVictoryCultT",
        "bonus": "GREATER_CULT",
        "destroyAllUpgrades": "holySite",
        "img": { "src": "cultists", "x": 0, "y": 0, "w": 400, "h": 300 },
        "endsEraModifier": "AGE_OF_PIETY"
    }
},

For the other empires that didn't manage to control the holy sites, there are four distinct outcomes based on whether they are cultists and whether the winner is a cultist:

"eraNonEnderReward": {
    "base": {
        "base": {
            "name": "pietyOtherVictory",
            "title": "pietyOtherVictoryT",
            "rep": -5,
            "img": { "src": "temple" },
            "endsEraModifier": "AGE_OF_PIETY"
        },
        "WORM_EYE_CULT": {
            "name": "pietyOtherVictoryOtherCult",
            "title": "pietyOtherVictoryOtherCultT",
            "rep": -5,
            "destroyAllUpgrades": "holySite",
            "img": { "src": "cultists", "x": 0, "y": 0, "w": 400, "h": 300 },
            "endsEraModifier": "AGE_OF_PIETY"
        }
    },
    "WORM_EYE_CULT": {
        "base": {
            "name": "pietyOtherVictoryCult",
            "title": "pietyOtherVictoryCultT",
            "rep": -20,
            "img": { "src": "temple" },
            "endsEraModifier": "AGE_OF_PIETY"
        },
        "WORM_EYE_CULT": {
            "name": "pietyOtherVictoryBothCult",
            "title": "pietyOtherVictoryBothCultT",
            "destroyAllUpgrades": "holySite",
            "img": { "src": "cultists", "x": 0, "y": 0, "w": 400, "h": 300 },
            "endsEraModifier": "AGE_OF_PIETY"
        }
    }
}

Note that eraNonEnderReward is a nested bonusable value. The first level is determined by the bonuses of the empire the reward applies to, and the second by the bonuses of the empire that ended the era.

Testing

Once you've added a new EraModifier, you can test it using the "Start Age" cheat option. Note that the game needs to be unpaused for the age to actually start. (And yes, all the cheats in the game started out as tools for testing the game.)

Conclusion and Example Mod

Putting this all together, you can create special game eras that provide variety to gameplay by changing the way the game works and giving the player interim goals. As an example of this, here's a mod that adds an Age of Schism, during which the Trilunar Church breaks into three competing sects you can try to reunite - or destroy, if you're cultists.

As always, if you have any questions about this post, feel free to comment below, and if you need help with modding, hop on the Discord and ask!