AN INTERMEDIATE GUIDE TO SCRIPTING
BACKGROUND SCRIPTS
By Epistolary Richard & Myrddraal
___________________________
In A Beginner Guide to Scripting we identified two different types of scripts: campaign scripts and show_me scripts, and went further to divide show_me scripts into event scripts and background scripts.
The Beginner Guide taught us the basics of using the event script – which is a script that runs only for a moment, making a change to the game world. These must be manually activated when their trigger event occurs.
This guide takes us a little deeper into the world of the background script – this is a script that is running constantly in the background of the game. It must be activated at the start of the game, and then manually reactivated each time the game is reloaded.
The Benefits of a Background script
There are two major limitations to the use of event scripts. The first is that it requires the player to click on the show_me button each and every time you want to make a change to the game environment.
The second, more importantly, is that the event script trigger can only ever be something that will happen in the player’s own turn. If it occurs outside of the player’s turn then the player will never get the chance to click on the show_me button as the advisor will appear and disappear during the AI turn.
This is why modders use background scripts as the main driver for their scripting features as they require the player only to make a single click each time the game is reloaded to run all their features and it gives them complete flexibility as to when and how their features are implemented.
In fact, the very first scripts that Myrddraal released – the Multiple Turns per Year script and the Hot Seat Beta script – were both background scripts.
In truth, every mod with significant scripting features will end up making use of all of the different types of script – background, event and campaign – as they all compliment each other.
What is a Background script?
As all show_me scripts, the background script is activated through the advisor. It must have all the components of a show_me script as listed in the Beginner Guide, namely trigger, advice thread and script.
The fundamental difference between an event script and a background script is that a background script is supposed to keep running and not terminate until the game is quit.
This is accomplished with the addition of a simple piece of code to the script – a While loop:
Once activated, this script will never terminate as when it reaches the end_while it will loop back to the I_CompareCounter.Code:script declare_counter loop set_counter loop 0 ; Insert your background script here while I_CompareCounter loop = 0 end_while end_script
Now we have the script working all the time, however, we have to incorporate the triggers we want to use into the script itself, instead of the export_descr_advice file. To do that, we need to use new syntax:
Monitors, If statements and While loops
The monitor event/monitor conditions/if/while commands are very much like the triggers for advice threads.
Basically they are for checking conditions.
If statements
Like for example if you have a counter called no
What this will do is at the stage at which it reaches the If line, it will check counter no, if counter no is 1 then it will run the code, if not it will skip to the end_if.Code:script declare_counter no set_counter no 1 If I_CompareCounter no 1 Insert code here end_if end_script
While loops
A while loop will repeat itself whilst its conditions are true.
When the script runs through, everytime it reaches and end_while, it will check the conditions, and if they are still true, it will jump back to the while statement. Basically looping that bit of code. In this example, the script will keep running forever, because the condition is that no is zero, and there is no code to stop this.Code:script declare_counter no set_counter no 0 While I_CompareCounter no = 0 Insert code here end_while end_script
While monitors can be extreemly usefull for pausing the script until something happens.
This will pause the script until the player ends the first turn (turn 0)Code:While I_TurnNumber = 0 end_while
It can also be very helpfull if you do not want a script to end before a monitor is triggered. (see below)
Monitors
Condition monitors
The difference between a Monitor and an If statement is that the conditions for an if statement are checked when the if statement is reached, and not again. A monitor can be declared at the beginning of the script and will then be checked continuously.Code:script declare_counter loop set_counter loop 1 declare_counter no set_counter no 0 monitor_conditions I_CompareCounter no = 1 Insert code here terminate_monitor end_monitor campaign_wait 10 set_counter no 1 while I_CompareCounter loop = 1 end_while end_script
In the example above, the monitor is declared, but the counter no is not 1. As soon as no changes to 1 (after waiting 10) the monitor is triggered and the code inside it is run.
Event monitors
An event monitor is basically a trigger using certain conditions. For example the pressing of a button. In this case, on the pressing of the end turn button, the code inside the monitor will be run.Code:script declare_counter loop set_counter loop 1 monitor_event buttonpressed buttonpressed end_turn TrueCondition Insert code here terminate_monitor end_monitor while I_CompareCounter loop = 1 end_while end_script
The difference between terminate_monitor and end_monitor
With some monitors, you will see both terminate_monitor and end_monitor at the end. This basically determines whether the monitor can be triggered more than once. If you include both, the monitor can only be triggered once, then it cannot be used again. If you only include the end_monitor, then the monitor can be enabled several times.
And statements
And statments can be used with monitors, if statements and while loops. This is for multiple conditions. For example:
A full list of events, conditions & commands can be found here:Code:script declare_counter noone declare_counter notwo declare_counter nothree set_counter noone 1 set_counter notwo 1 set_counter nothree 1 monitor_conditions I_CompareCounter noone = 1 and I_CompareCounter notwo = 1 and I_CompareCounter nothree = 1 Insert code here terminate_monitor end_monitor if I_CompareCounter noone = 1 and I_CompareCounter notwo = 1 and I_CompareCounter nothree = 1 Insert code here end_if end_script
https://forums.totalwar.org/vb/showthread.php?t=54299
Now, that’s all a lot to take in. So let’s try some examples:
More More Money
Here we give the player a little monetary boost each turn. It’ll happen automatically, no need for him to manually activate it.
For the event to trigger it, I’m going to choose FactionTurnStart and I want it only at the start of the player’s turn so I’m going to use the FactionIsLocal conditional.
Now, at the beginning of each turn, the player’s treasury will increase by 100.Code:script declare_counter loop set_counter loop 0 monitor_event FactionTurnStart FactionIsLocal console_command add_money 100 end_monitor while I_CompareCounter loop = 0 end_while end_script
Simple enough. Let’s make it more complicated.
Here is a script that will make it considerably harder for a player to amass a huge treasury:
At the beginning of each turn, the script will check the player’s treasury and then, if it above a certain amount and the player is not losing money, it will reduce it by the specified amount eg, 1,000 if it is above 10,000.Code:script declare_counter loop set_counter loop 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;; Creosote remover ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; monitor_event FactionTurnStart FactionIsLocal and not LosingMoney and Treasury > 10000 console_command add_money -1000 end_monitor monitor_event FactionTurnStart FactionIsLocal and not LosingMoney and Treasury > 20000 console_command add_money -3000 end_monitor monitor_event FactionTurnStart FactionIsLocal and not LosingMoney and Treasury > 30000 console_command add_money -6000 end_monitor while I_CompareCounter loop = 0 end_while end_script
Note that all of these monitors will be triggered at the start of the player’s turn. Therefore if his treasury has gone higher than 30,000 he will not be docked 6,000 but 10,000 (1,000 + 3,000 + 6,000).
Here’s a very different script (from the late, unlamented Client Kingdoms 2 which will never be), one designed to give a non-player controlled faction a helping hand if things start going bad for them.
Let’s take it step by step, first of all, the initial event:Code:script declare_counter loop set_counter loop 0 monitor_event FactionTurnStart FactionType britons and I_NumberOfSettlements britons < 4 and RandomPercent < 15 console_command create_unit Londinium "warband sword briton" 1 console_command create_unit Londinium "warband hurler briton" 1 console_command create_unit Eburacum "warband sword briton" 1 console_command create_unit Eburacum "warband hurler briton" 1 console_command create_unit Deva "warband sword briton" 1 console_command create_unit Deva "warband hurler briton" 1 end_monitor while I_CompareCounter loop = 0 end_while end_script
Means that it will be triggered when:Code:monitor_event FactionTurnStart FactionType Britons and not FactionIsLocal and I_NumberOfSettlements britons < 4 and RandomPercent < 26
1) At the start of the Britons turn
2) When the player is _not_ playing the Britons
3) When the number of settlements the Britons own is less than 4
4) And if the computer picks a random number between 1 and 25 – this means that even when all the other conditions are satisfied it will only happen on average 1 time in 4.
If all those conditions are satisfied, then the game will run the script within the monitor, creating the units within those settlements. The problem with it at present is that script will create the unit its told to, irrespective of whether it is the Britons or another faction who control that settlement, and assign it to that faction which controls the settlement. We therefore need to check to make sure we only create the unit in a settlement if the Britons control that settlement, for example:
So our full script would look like the following:Code:if I_SettlementOwner Londinium = britons console_command create_unit Londinium "warband sword briton" 1 console_command create_unit Londinium "warband hurler briton" 1 end_if
Code:script declare_counter loop set_counter loop 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;; britons in danger - Dads Army ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; monitor_event FactionTurnStart FactionType britons and I_NumberOfSettlements britons < 4 and RandomPercent < 15 if I_SettlementOwner Londinium = britons console_command create_unit Londinium "warband sword briton" 1 console_command create_unit Londinium "warband hurler briton" 1 end_if if I_SettlementOwner Eburacum = britons console_command create_unit Eburacum "warband sword briton" 1 console_command create_unit Eburacum "warband hurler briton" 1 end_if if I_SettlementOwner Deva = britons console_command create_unit Deva "warband sword briton" 1 console_command create_unit Deva "warband hurler briton" 1 end_if end_monitor while I_CompareCounter loop = 0 end_while end_script
Triggers
We’re now beginning to understand what a background script is, however the script is only one of the three elements listed in the Beginner Guide – we also need an advice thread and, more importantly, a trigger. These are done in the same way as in the Beginner Guide, so rather than go through them again, I’ll just show you an example.
The F1 trigger
This is the trigger used by Myrddraal in the first scripts that he released. It’s great benefit is that the trigger is not activated by normal play, it is therefore ideal for testing purposes and mods where the player can be relied upon to follow the process each time.
It is, in fact the exact same trigger that was used in the Beginner Guide. But here it is again
This is the advice thread (NB, all this already exists, only the Script line has been added)
To activate your background script (placed in the data\scripts\show_me folder, of course), you must press F1 – then click on the ? – then the advisor should pop up and you can click on the Show Me How button at the beginning of the campaign and after each reload.Code:;------------------------------------------ AdviceThread Help_Campaign_Keyboard_Shortcuts_Scroll_Thread GameArea Campaign Item Help_Campaign_Keyboard_Shortcuts_Scroll_Text_01 Uninhibitable Verbosity 0 Threshold 1 Attitude Normal Presentation Default Title Help_Campaign_Keyboard_Shortcuts_Scroll_Text_01_Title Script scripts\show_me\background_script.txt ; This is the added line Text Help_Campaign_Keyboard_Shortcuts_Scroll_Text_01_Text1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;------------------------------------------ Trigger 2137_Help_Campaign_Keyboard_Shortcuts_Scroll_Trigger WhenToTest ScrollAdviceRequested Condition ScrollAdviceRequested help_scroll AdviceThread Help_Campaign_Keyboard_Shortcuts_Scroll_Thread 0
Now more and more mods are developing background scripts, scripters have been looking into ways to make activation and reactivated more user friendly. Eventually, once a certain number of mods have been released, I imagine that a community standard will develop as mod-users become accustomed with a specific method. More sophisticated triggers (and their consequences) will be the topic of the further portion of this guide which will be a series of modules focusing on various advanced scripting techniques to which all are invited to contribute.
Scripting links
CA's list of commands, events and conditions
Scripting research thread
Hot Seat Mod - Beta Release
More than two turns a year - release
Bookmarks