Total War: WARHAMMER II

Total War: WARHAMMER II

Not enough ratings
TW:WH Script Guide: Anatomy of a Listener
By IfThenOrElse
This guide will break down & explain one of the fundamental aspects of scripting for Total War: Warhammer.
   
Award
Favorite
Favorited
Unfavorite
Preface:
This is not an in-depth guide on scripting, but focuses in on a specific aspect of scripting. This guide assumes you understand the basics of Total War modding and are looking to delve further into scripting.

As such, you should understand how to create and edit pack files and be willing to do your own research into scripting fundamentals.
Introduction:
In TW:Warhammer 2 if you want to do something at specific events, such as sacking a town, ending a turn or completing a structure - you can do so by making use of the listener command.

Listeners, once activated will wait for specific events to occur and then execute your commands.
Looking at the command:
So let's take a look at this humble command.

core:add_listener("name","EVENT",boolean1, function to execute, boolean2);

  • "name": is a string and can be whatever you want.
  • "EVENT": is a string that uses pre-defined event names e.g. GarrisonOccupiedEvent. You can see a list of these events in the data.pack file under scripts > events.
  • Function to execute: This is where you define what it is you want to do!
  • Boolean1: Is the condition. If this is true the listener will execute it's function.
  • Boolean2: Determines repetition. If this is false, once the listener has fired, it will shut itself down.

Looks simple, right? But might oaks from little acorns grow. These listeners can quickly get complicated, so lets re-arrange the above into something that will be easier to read when your script gets complicated - do NOT ignore the comma's - they are important.

core:add_listener( "name", "EVENT", true, function() -- code to execute. end, true, );

It's all about context.
The events that trigger a listener will pass out a context that can be helpful for your script.

For example, the GarrisonOccupiedEvent will pass out the character who did the occupation.

This guide will not reference what is passed out by each event - however if this resource does become avaialble, it will link to it here.
Let's get clever with those booleans:
Let's refresh ourself with a a super basic listener that will fire every time a town is occupied.

core:add_listener( "MyListener", "GarrisonOccupiedEvent", true, function() -- code to execute. end, true, );

It's not great to have such a broad listener though - it's likely to slow down the game and also cause scripts to fire off when you don't intend them to. So let's look at that first 'condition' boolean and replace it with a function.

function(context) return true end,

This is functionaly the same as just writing "true" - however we can start to do some interesting things with our conditions. For example:

function(context) return context:character():region():name() == "wh_main_reikland_altdorf" end,

This function will return true if the character occupying in the original event is in Altdorf. So let's see what our listener looks like with this new function (which I edited to include every town in Reikland).

core:add_listener( "MyListener", "GarrisonOccupiedEvent", function(context) return (context:character():region():name() == wh_main_reikland_altdorf" or context:character():region():name() == "wh_main_reikland_eilhart" or context:character():region():name() == "wh_main_reikland_grunburg" or context:character():region():name() == "wh_main_reikland_helmgart") end, function() -- code to execute. end, true, );

This listener will now only fire when any character occupies a settlment in Reikland.
In Sumamry:
Listeners are great tools to help you make things happen when you need them to happen.

I hope that this guide helps deconstruct them for you so that you can start to use them in your own mods :)
1 Comments
vladuvix 2 Aug, 2018 @ 9:21am 
i have one question. Iwant to add a few low tier units to the DE ror roaster with 9999 cap and 3x price and small increase of upkeep so that they can function as a Global recruitment in case of emergency. the problem is that in order to get them on campign screen I need to add them to the Mercenarry pool from "Campaign Startpos
Compressed Data
Campaign_Env
Campaign_Model
World
Faction Array"
and the only way i know how to do that is by compiling the start_pos.esf as well as the rest of the tables, oh and also i want to change the starting hero for Malekith to a hag (that is not so important but is also somethingh from the esf)
ps. I`m a junuior programmer in c# for 2 yesrs now, im not afraid of cripts but i have no clue as how this could be done, can you point me to some example?
THANK YOU VERY MUCH!