Welcome to the homepage for campaign scripting in Total War. Here you can find resources and guidance for the creation of scripts that will run in campaigns.
old episodic scripting interface - now obselete
If any of the links above are dead then launch a campaign in the game. The old-style episodic scripting interface and model hierarchy documentation are generated by code when a campaign is run.
|Relevant in Campaign|
The first script that is run when a particular campaign loads can be customised in the relevant record in the
campaigns table, in the
script_path field. By convention this is
From Warhammer onwards, all campaign scripts can be found in
data\script\campaign\ (as well as
data\script\_lib\, for library scripts related to campaign). This
data\script\campaign\ folder contains a number of subfolders, all of which may contain script files. Script files in those folders should contain functionality related to their location in the folder structure:
|Scripts potentially related to all campaigns in this project.|
|Scripts related to a particular campaign.|
|Scripts related to a particular faction in a particular campaign.|
For more information see the page about
The campaign script libraries are built on top of the raw interface provided by campaign to script and offer extensive support and extended functionality for campaign scripting. The main script object through which campaign calls are made is the
Other script objects exist in addition to the campaign manager, documentation for which can be found in the
Script Pages list in the navigation bar on the left-hand side of this page. The main script objects related to campaign are listed below:
|Central object that provides functionality shared across both campaign and battle, such as ui querying and event listeners.|
|Central interface object for campaign scripts. The main campaign game interface is accessed through this object.|
|Central campaign object providing functionality specifically related to the user interface.|
|Wrapper object provided functionality related to the declaring and management of missions.|
|Object interface for creating scripted cutscenes in campaign.|
|A mechanism for stopping progress in the game to allow one bit of script to play through to completion, such as some advice or a scripted tour.|
Unlike in battle, campaign scripts begin to load near to the start of the loading sequence. This is to allow scripts to be present while the save file (or startpos file) are loaded - the scripts can save values into the savegame when the game is saved and it is during the loading sequence that these values are read back out. Being loaded at such an early stage presents some complications, however, as the game model is not initialised until much later in the load sequence. If the script attempts to access or interrogate the game model before it's created then the game will crash. Care must be taken to ensure that this doesn't happen.
The standard script architecture put in place for each campaign attempts to ameliorate this issue by providing loading sequence processes with which callbacks to be registered. These registered callbacks will then be called at key points during the loading sequence when certain new elements of functionality become available.
campaign_manager:add_loading_game_callback to register a function to be called when the
LoadingGame event is triggered. This happens early in the load sequence, before the model is created. Scripts may load values in from the savegame at this point but may not access the model. Other methods of loading information from the savegame exist - see the
Loading Game section in the campaign manager documentation.
campaign_manager:add_pre_first_tick_callback to register a function to be called when the game and ui have been created. The campaign model may be queried after this point in the loading sequence. It is only at this point that the local faction can be identified and any faction-specific scripts loaded in.
campaign_manager:add_first_tick_callback or a related function (see the list available in the
First Tick section) to register a function to be called when time in the game first starts ticking. This event is triggered once loading is finished and the game becomes interactive.
The campaign model (and hence the campaign scripts) completely shut down when the game loads from campaign into battle. From the perspective of campaign script the load back into campaign after a battle is (nearly) indistinguishable from being loaded from a savegame.
The campaign model provides an interface of functions that can be used to query and modify the campaign state, known for historic reasons as the episodic scripting interface. Documentation for it can be found here:
These functions are provided through a
game_interface object. The
campaign_manager, when created, internally creates and stores a
game_interface object and provides a pass-through interface to it. This means that functions on the episodic scripting interface may be called on the
campaign manager e.g.
cm:enable_ui(false). Scripters are encouraged to call functions on the episodic scripting interface in this way, rather than trying to get an interface to the underlying
game_interface object, as in many cases the
campaign_manager overrides the underlying call and adds additional functionality.
The campaign model also provides a model hierarchy that may be navigated around and queried by script. This is of most use when a campaign event is triggered - from the context provided by event, the script may navigate amongst objects querying their state. For example, the
FactionTurnStart event provides a context object from which the faction starting its turn may be derived. This faction object may be further queried to get a list of region objects that the faction owns, military force objects that the faction controls, a character object representing the faction leader, and so on. These objects in turn may be asked for further related objects (e.g. get the settlement of the region of the faction leader character of the faction starting its turn) allowing scripts to perform tests of any feasible complexity on the current state of the game. This model hierarchy is read-only, however - all function calls that modify objects are found on the episodic scripting interface.
The campaign automatically generates documentation on this model hierarchy which can be found here: Model Hierarchy.
Read more about events in the dedicated page here:
Campaign scripts rely heavily on the script event system. While running, the game triggers script events when particular changes in the state of the model (or the UI) take place. Scripts may register functions as listeners for script events in order to be notified of these changes. Should a lua function be registered as a listener for an event then that function will be called when the event is triggered by the game. Furthermore, the game provides a
userdata context object to the function being called which can then be queried to determine more information about the change taking place. Script events are triggered in all game environments, but they are used most extensively by campaign scripts.
Examples of campaign events include when a faction starts a turn (
FactionTurnStart) or when a character is created (
CharacterCreated). In the former case the context would contain information about the faction involved, in the latter the context would contain information about the character. A list of all events triggered across the game can be seen on the autogenerated model hierarchy documentation. For more information about context interrogation see the section below about the
The events system also allows scripts to request functions to be called after an interval e.g. "call this function one second from now". The underlying functionality that supports this is repackaged by the campaign manager - see the
Timer Callbacks section for information on usage.
Example - PendingBankruptcy listener:Listen for a PendingBankruptcy event for a particular faction
"faction_turn_start_listener", -- name for listener
"PendingBankruptcy", -- event to listen for
function(context) -- test to perform prior to triggering callback
return context:faction():name() == "wh_main_emp_empire"
function() -- callback to trigger
false -- continue listening after trigger
When an event is triggered by the campaign model it provides a context object to any listener scripts that gets called. This context object provides links to one or more objects within the model hierarchy, each of which represent objects in the game such as a faction, a settlement, or a character. For example, the context of the
FactionTurnStart event provides a
faction object representing the faction that is starting its turn, whereas the
CharacterLootedSettlement object provides both a
Each object in the model hierarchy provides a range of functions that may be called by script to determine the state of the object and also to retrieve related objects. For example each
faction object provides a
faction_leader method which can be called to return a character object representing the faction leader character of that faction. This character object can then be queried like any other character object, including being asked for other related objects such as the military force commanded by the character or the region the character is stood in.
A list of events, what objects they provide, and what methods each of the objects in the model hierarchy support can be found in the model hierarchy documentation that is generated by the game when a campaign is loaded.
The following image illustrates many of the main objects provided by the model hierarchy and how they link together. It is by no means authoritative! See the model hierarchy documentation for a complete list.
See the section on
Output for more information about how to print debug output.
The campaign contains two co-ordinate systems that are overlaid on top of one another: logical and display. Logical co-ordinates define the position of a hex in the logical data, and are used to position logical game objects that can only occupy a hex, such as a military force or a settlement. Display co-ordinates define the position of objects that don't exist in the logical game data, such as visual props or the camera.
The logical and display positions of the cursor may be shown in campaign by selecting
controllers -> Campaign Debug and then
UIs -> Cursor position from the debug dropdown menus. The hexmap map may also be drawn over the campaign map by selecting
UIs -> Pathfinding Debug and also
Warscape -> Debug Line Renderer. This hexmap and the co-ordinates of each hex should conform to the source hexmap in the Twitch tool.
The game can be instructed to output the display co-ordinates of the camera by entering the command
camera_position on the console. The co-ordinates then printed to the command tab.
Camera target: 201.634811, 520.228577; distance: 18.334259, bearing: 0.0, height: 9.76396 (201.634811 520.228577 18.334259 0.0 9.76396)