Hooking Into Game Systems
Adding a building or a trait is one thing. Making it do something interesting means reaching into the running game - reading a faction's gold, checking a character's traits, changing a settlement, reacting when things happen. This page is about that surface: how your AngelScript talks to the live game, and how it talks to your own UI.
This follows on from AngelScript; read that first if you haven't.
The objects you'll work with
The game world is made of a handful of core object types, and once you have a reference to one you can walk to the rest. The main ones:
| Type | Is | Reach it from |
|---|---|---|
AFaction | A faction / player | StrategyGameplay::PlayerFaction, or another object's owner |
UPerson | A character | A faction's court, a settlement's governor, an event's subject |
APopulationCentre | A settlement | A faction's holdings, a province, the map |
AArmy | An army | A faction's forces |
APowerBloc | A power bloc | Faction relationships |
The one you'll reach for constantly is the player's faction:
AFaction PlayerFaction = StrategyGameplay::PlayerFaction;
From a faction you can get almost anywhere - its settlements, its characters, its diplomatic relationships, its treasury.
Faction components
A faction's behaviour is split across components, each owning one domain. When you want to change something about a faction, you go through the relevant component:
| Component | Owns |
|---|---|
EconomyComponent | Treasury, income, resources |
DiplomacyComponent | Relations, treaties, opinions |
CharacterComponent | The faction's people |
CourtComponent | The ruler's court and appointments |
LogisticsComponent | Supply |
RebellionComponent | Unrest and revolt |
FoederatiComponent | Foederati / subject tribes |
FormationComponent | Army formation templates |
So changing a faction's formations means going through PlayerFaction.FormationComponent, adjusting its money through PlayerFaction.EconomyComponent, and so on. This is also your guide to where to hook: if your content is about the economy, the economy component is where the relevant methods and events live.
Settlement modifiers
The cleanest way for content to affect a settlement is through its modifiers, rather than mutating raw values. You saw this in the Bakery example - it registers a named food-production modifier when built and removes it when destroyed:
PopulationCentre.Modifiers.FoodProduction.Set(n"Bakery", Name, 1.35f + Level * 0.30f);
// ...later...
PopulationCentre.Modifiers.FoodProduction.Remove(n"Bakery");
The name key (n"Bakery") means your modifier is tracked separately from everyone else's.
Reacting to the game: overrides and lifecycle
Content hooks into the game mostly through override methods that the game calls, things like - OnAdd / OnRemove for a building, CanBeGained / CanBeLost for a trait, OnInteractionComplete for an interaction, and the option-effect callbacks for an event. Once you implement the hook, the game invokes it.
That keeps your logic where it belongs and means you rarely need to write anything that runs every tick. If you find yourself wanting a per-frame update, it's worth checking whether there's a lifecycle hook that already fires at the moment you care about.
Persistent, campaign-specific state
Because content is discovered by class, your mod's own AngelScript classes are the natural home for any state your mod needs. State that lives on game objects - modifiers on settlements, traits on characters, treaties between factions - is saved and loaded with the game automatically, because it's part of those objects. The best pattern for remembering something across the campaign is to attach it to the relevant game object (a modifier, a trait, a faction relationship).
For campaign-wide values that don't belong to any one object, the map's exported Info.json carries the scenario's starting profile (see The World Editor), and anything dynamic you track should hang off the game objects that own it so it travels with the save.
Talking to your own UI: bridge actions
If your mod ships a custom screen (Mod Screens), AngelScript and the UI talk over a bridge. Your UI calls a named action; a UBridgeAction class on the script side handles it, does the work, and returns a response. This is the same mechanism the base game's entire UI runs on.
A bridge action is just a class with an ActionName and an ExecuteNative override:
UCLASS()
class UDeleteFormationTemplateAction : UBridgeAction
{
default ActionName = "game.delete_formation_template";
UFUNCTION(BlueprintOverride)
FBridgeActionResult ExecuteNative(const FBridgeNativeValue& Payload)
{
FDeleteFormationTemplateRequest Request;
if (!UBridgeNativeBuilder::NativeValueToStruct(Payload, Request))
return UBridgeAction::Failure("Invalid request");
AFaction PlayerFaction = StrategyGameplay::PlayerFaction;
UMilitaryFormationTemplate Template =
FormationTemplateBridge::ResolveTemplate(Request.TemplateId);
PlayerFaction.FormationComponent.RemoveFormationTemplate(Template);
FDeleteFormationTemplateResponse Response;
Response.Deleted = true;
return UBridgeAction::SuccessNative(
UBridgeNativeBuilder::StructToNativeValue(Response));
}
}
The ActionName - here "game.delete_formation_template" - is the string your UI calls, it's worth namespacing your mod's actions to keep them from colliding. The incoming Payload gets turned into a typed struct with NativeValueToStruct, the work happens in the middle by reaching into the game (through PlayerFaction.FormationComponent in this case), and then you build a response struct and return it with SuccessNative, or bail out with Failure if something was wrong.
Actions can also push to the UI without being asked, by sending a bridge event:
UBridgeAction::SendNativeBridgeEvent("ui.sidebar_event",
UBridgeNativeBuilder::StructToNativeValue(Payload));
On the UI side, your React code calls the action with bridgeCall(name, payload) and listens for pushed events with onBridgeEvent(name, handler). Those two halves - the UBridgeAction here and the bridgeCall there - are the whole conversation between your gameplay logic and your interface.
Next
- Build the UI that calls these actions - Mod Screens (WebUI)
- Switch off base content your mod replaces - Disabling & Overriding Content