PDA

View Full Version : Tutorial [Beginner coding/scripting]: Triggers&Monitors



alpaca
01-09-2007, 22:06
You can link to or quote this tutorial at wish, but please don't mirror it. This is required in order to keep discussion about it in one place.

Prerequisites

In order to be able to follow this tutorial, you should be confident with the following:
- The traits tutorial (https://forums.totalwar.org/vb/showthread.php?p=1380384) and all that is required there
- The docudemon (https://forums.totalwar.org/vb/showthread.php?t=73016) files


Triggers

First of all, I want to make sure you understand the enormous spread of the concept of triggers in the MTW2 data files. They are directly used in all of the following files (among which are some of the most-edited files for every mod):
- descr_faction_standing.txt
- export_descr_advice.txt
- export_descr_ancillaries.txt
- export_descr_character_traits.txt
- export_descr_guilds.txt

On top of that, the monitor_event scripting structure works pretty much in the same way.


1. Overview

Well, since you are reading this tutorial, I guess you have already had a good look at one of the files containing triggers and formed your own opinion about what they do (if not, have a look at my traits tutorial (https://forums.totalwar.org/vb/showthread.php?p=1380384) and read the first part carefully). Now, to see if your assumptions are correct - look at this example:

;------------------------------------------
Trigger diplomatinit6
WhenToTest AgentCreated

Condition Trait Multilingual >= 1

Affects Multilingual 1 Chance 33

You can clearly see that each trigger consists of four basic parts:
- A trigger head (aka the name)
- A WhenToTest event
- Zero or more conditions
- Zero or more affects


2. The trigger head

The trigger head starts with the keyword Trigger followed by the trigger name.
The only thing you should observe here is that each trigger is assigned an individual name. I think the game will use the last version of a trigger name it can find (no idea how having the same trigger name in multiple files affects this).


3. The WhenToTest event

This part consists of the keyword WhenToTest followed by an event name. This entry determines when the trigger will actually execute. In the above example, the trigger will be run every time an agent is created, but only if the conditions are met (see below).

You can find a list of all allowed events in docudemon_events.txt which you downloaded with the docudemon package.
For more info on this file, press on "Show":
Here's an example from the file:
---------------------------------------------------
Identifier: SettlementTurnStart
Event: A Settlement is being processed for the start of its faction's turn
Exports: faction, settlement, region_id
Class: ET_SETTLEMENT_TURN_START
Author: Guy
---------------------------------------------------
Identifier: SettlementTurnEnd
Event: A Settlement is being processed for the end of its faction's turn
Exports: faction, settlement, region_id
Class: ET_SETTLEMENT_TURN_END
Author: Guy
As you can see, each entry consists of the event name (Identifier - this is what goes behind WhenToTest), a description of the event, which types of objects this event exports (see below) and two (for us) unimportant lines.
Most of these events are fairly self-explaining, but some take a lot of guessing and/or testing to figure out what they do exactly and what you can do with them.

4. Conditions

This section is quite a bit more complex than the first two. Looking at our example from the beginning, you will notice that it has only one condition:

;------------------------------------------
Trigger diplomatinit6
WhenToTest AgentCreated

Condition Trait Multilingual >= 1

Affects Multilingual 1 Chance 33
This is actually an interesting example for a trigger, because it has a certain level of the trait it is changing as a condition. This means, it will never award the trait in the first place but can amplify it.

Let's have a look at a more complex example now:

;------------------------------------------
Trigger hate_n_fear_29
WhenToTest PostBattle

Condition IsGeneral
and not WonBattle
and BattleSuccess = crushing
and I_ConflictType Normal
and BattleOdds >= 0.9
and GeneralFoughtFaction england

Affects Fearsengland 1 Chance 100
This is one of the hate&fear triggers that will give your general boni/mali in combat against certain factions or cultures. This trigger contains 6 conditions, that are linked with the and keyword (you should put each condition on a new line), and the Effects section will only be executed if all of the conditions are true.
The first condition always has to be preceded by the Condition keyword, the others by and. Both of these can in turn be followed by not to negate the condition (like it's done with "and not WonBattle" in the example).
Be careful when using not. It apparently doesn't work with some conditions that use a logic token (like I_CompareCounter counter = 1).
If you want to negate these, manually negate the token, so "not condition = 1" would become "condition != 1", "not condition >= 1" would become "condition < 1" and so on.

You can find a complete list of allowed condtions in docudemon_conditions.txt - shipped with the docudemon package.
Understanding this section is vitally important for the correct usage of conditions, but before you read this, you should be comfortable with some basic examples (you can find a few here <--ToDo: Write this)

Ok, since you know the basics about conditions, let's have a look at two examples for the basic condition types in the docudemon:

Identifier: FactionIsLocal
Trigger requirements: faction
Parameters: None
Sample use: FactionIsLocal
Description: Is the faction the local faction?
Battle or Strat: Either
Class: FACTION_IS_LOCAL
Implemented: Yes
Author: Guy
---------------------------------------------------
Identifier: I_LocalFaction
Trigger requirements:
Parameters: faction
Sample use: I_LocalFaction romans_julii
Description: Is the faction the local faction?
Battle or Strat: Either
Class: I_LOCAL_FACTION
Implemented: Yes
Author: Guy
Identifier: the name of the condition

Trigger requirements: This is one of the most important and apparently most difficult to understand aspects of conditions.
Basically, each condition has a certain scope (i.e. it only works on certain game objects). This scope is the trigger requirement, and you will notice that this exactly fits the Exports entry for the events.
If you want to use a condition with a certain trigger requirement, you can only do that in a trigger with a WhenToTest event that exports this object. For example, the FactionIsLocal condition (it is true if and only if the faction the event exports is the player's faction) will work with the SettlementTurnStart event but not with the CrusadeCalled event because the former exports a faction object, while the latter doesn't.

The second example (I_LocalFaction) is a fine specimen of an independent condition. These conditions don't have a trigger requirement, and they work in all triggers. They are usually fairly inflexible but if you know how to use them properly, they have important applications (especially in scripting).

Parameters: This is another important entry. It tells you which parameters a condition takes. A lot of conditions simply take one parameter, but a lot of them also take a logic token (<, <=, =, >, >=) or multiple parameters. Independent conditions almost always take at least one parameter, dependent conditions often take one, but as you could view the trigger requirement object as an additional parameter they don't always have to have another one.

The rest of the file should be fairly self-explanatory, or isn't important for modding purposes.


5. The affects section

First of all, don't confuse this with effects for traits. This is something quite different.
This part of a trigger definition consists of zero or more variations on the theme:

Affects <Trait> <Points> Chance <Percentage>
This means that, when the trigger is run and all conditions are true, the character in question will have a <Percentage> chance to get <Points> trait points in <Trait>. An example:

Affects GoodCommander 1 Chance 50
When this is executed, the character has a 50% chance of getting one point in the GoodCommander trait chain, thus making him a more able general.

As I said, you can use multiple Affects lines in one trigger, or even omit them altogether (although this will make the trigger completely useless), like this:
;------------------------------------------
Trigger corruption4
WhenToTest CharacterTurnEnd

Condition EndedInSettlement
and Treasury > 150000

Affects Corrupt 1 Chance 3
Affects Aesthetic 1 Chance 3
Affects ExpensiveTastes 1 Chance 3
Affects Epicurean 1 Chance 3
Affects Embezzler 1 Chance 3

5.1 Other files

To view this section, click on Show:
I told you in the introduction that triggers are actually a concept pretty wide-spread in MTW2 modding. Up until now, the triggers in descr_faction_standing.txt, export_descr_advice.txt, export_descr_ancillaries.txt, export_descr_character_traits.txt and export_descr_guilds.txt look exactly the same. They differ, however, insofar as only the edct file uses an actual Affects line. As for the other files, I will tell you the keywords but not go into too great detail about them:


export_descr_ancillaries.txt
This file uses an entry called AcquireAncillary instead of the Affects line. It looks like this:

AcquireAncillary <Ancillary> chance <Percentage>
You will notice that this is almost the same as an Affects statement, however you can't have different levels of the same ancillary so you only have one parameter, which is the chance to acquire that ancillary.
An example:

AcquireAncillary holy_lance chance 10


export_descr_advice.txt
The equivalent statement here is:

AdviceThread <thread> <points>
Where <thread> is a thread identifier and <points> is used for Threshold and, I think, MaxRepeats


descr_faction_standing.txt
The line here is:

FactionStanding <factions> [normalise/points]
A bit more explanation needed I think. However I'd rather leave this to a tutorial about this file as it is pretty complex


export_descr_guilds.txt
For this file, it looks like:
[code]Guild <guild> [s/a/o] <points>
Where <guild> is a guild name and <points> is a numeric value.
"s" will award the points to the settlement in question only, "a" will award the bonus to all the faction's settlements and "o" will give it to all except for the settlement "s" will award the points to.




Monitors

Well, monitors are the scripting equivalent of triggers. Before you read this, you should have some basic grasp about scripting, which you might be able to get from old RTW tutorials.
Anyways, the thing that is closest to triggers is the monitor_event struct.
The exact command goes like this:

monitor_event <Event> <Condition>
[and [not] <Condition>]

...code...
end_monitor
What this does is practically the same as a trigger: When <Event> fires (this is the same as a WhenToTest event in a trigger), and all <Conditions> are satisfied, the code inside the monitor will be executed. It is important to know that here, too, you can only use conditions which trigger requirements fit the exports of the event you are testing for.
The first <Condition> is compulsory, and if you don't want to use one, supply TrueCondition here (which is, as the name says, always true).

The [and [not] <Condition>] can be repeated as many times as you like.

The second monitor struct is monitor_conditions.
The definition for it is:

monitor_conditions <Condition
[and [not] <Condition>]

...code...
end_monitor
This is actually a bit similar to monitor_event - but not quite. It is important to notice that, since you don't have any event to export objects, you can only use independent conditions here, whereas in monitor_event, you can also use (fitting) dependent conditions.
It's also quite apparent that a monitor_conditions will execute multiple times (in fact as long as all its conditions are true), which often has unwanted results as opposed to a monitor_event that will only execute once every time its event fires.
To prevent this, you can switch monitor_conditions on and off like this:

declare_counter switch
set_counter switch 1
monitor_conditions I_CompareCounter switch 1

console_command add_money 10000
set_counter switch 0
end_monitor
This monitor will add 10000 florins to your treasury every time you set the counter switch to 1 somewhere in the script and then switch itself off again.

Another important concept of monitors is that you can switch them off completely, using the terminate_monitor command. If you use that somewhere inside the monitor, it will be closed to be never executed again until you start a new game.

Sinuhet
01-11-2007, 12:56
Thank you for nice summary on this hot topic, alpaca! I think that it is the area, where is the largest potential as for modding MTW2 at all .... Every modder should be able to handle with at least the basics of these tools which CA has given to us. And these basics are her in one place in this excellent tutorial. Bye and thanks for you work in this, Sinuhet

alpaca
01-11-2007, 21:55
Thank you for nice summary on this hot topic, alpaca! I think that it is the area, where is the largest potential as for modding MTW2 at all .... Every modder should be able to handle with at least the basics of these tools which CA has given to us. And these basics are her in one place in this excellent tutorial. Bye and thanks for you work in this, Sinuhet
Thanks for the kind words. I do hope though that CA will release some modelling tools.
Anyways, in my opinion the campaign AI files are the most important area for modding (because it just stumps me every time the AI launches yet another suicide attack on me without sense or reason)

ezekiel6
01-14-2007, 13:54
Hi, I have been following this tutorial to put the ancillaries armour_custom and armour_ornate into the game. At the moment they are appearing fine in the game, I even gave them their own .tga files to show, so that I would know when they appeared. However I think I have missed something as they do not appear to be adding or subtracting from my General's hitpoints, they always remain at 2. Any idea of what I have to do to get them fully operating?
Cheers

alpaca
01-14-2007, 15:41
How do you know it doesn't add any hitpoints? You should know that the effects description is set in a text file, so if that is missing, the ancillary won't display any effect (similar to traits) - but it will still be there.

ezekiel6
01-14-2007, 19:20
How do you know it doesn't add any hitpoints?
Well checking the General's BG unit when he's out of a castle/city it says he has 2 hitpoints. At least 1 of the General's I have has the Fine Armour anc' but his hitpoints still say 2 and he has no other ancs' traits that cancel out the Fine Armour. On further checking I am not sure they are all working, another General has the Healthy trait giving him +2 hp and his show only 2 as well. What is the name of the text file for checking? I'm pretty sure I have that in there somewhere.
Cheers.

alpaca
01-15-2007, 17:39
Ah, but that is the number of hitpoints for the general's bodyguard unit, not the general himself.
If I recall correctly, the general usually has 5 hp, and there's no easy way of telling how many he has. So I think the extra hitpoints work, but there's no way to be 100% sure (well you could try running some tests but it'd take a long time to figure out a significant difference between 5 and 6 hp).

ezekiel6
01-15-2007, 22:19
Right I see, cheers. I just assumed that the BG unit info updated, like it does when you get armour upgrades. That's a shame.:(, but then it makes sense, if the whole unit had 5hp or more they'd be unstoppable.

Russ Mitchell
02-13-2007, 00:03
I have a question: can the "monitor" function disable boni/mali?

Direct query: horse-archers are skirmishers, and are therefore "losing" as CA defines it is irrelevant... could a general unit of these folks have the "battle-losing" trait offset by a counter-trait? Obviously, if one gets one's unit cut to ribbons, that's different... so I don't know if this is possible.

But if so... it would make E-Euro campaigning much more accurate.

alpaca
03-28-2007, 16:49
Small update adding this (after I found it out the hard way...):

Be careful when using not. It apparently doesn't work with some conditions that use a logic token (like I_CompareCounter counter = 1).
If you want to negate these, manually negate the token, so "not condition = 1" would become "condition !=1", "not condition >= 1" would become "condition < 1" and so on.

FactionHeir
03-28-2007, 18:41
Shame there is no condition to test for whether a charaacter has a certain ancillary. Would love such a condition as it allows to make traits work with ancillaries without having to create control traits.

alpaca
03-28-2007, 19:10
You can use has_anc_type, although that'd require you to use a new type for each anc.

isellj0epnuts
03-28-2007, 22:12
Alpaca, have you used the condition 'has_anc_type' in your EDCT? I tried connecting the possession of a mistress ancillary to the BastardSon trait in BBB, but the condition was ignored and all sons were born bastards.

alpaca
03-29-2007, 00:20
I think I only tried it out with scripting. It's usually a lot easier to tell if the conditions work and they should work in other files, too.

KnightErrant
03-29-2007, 03:11
@isellj0epnuts
I've used it a lot in a mod for doing titles the old MTW-I
way, you know where if your general is the Earl of York you get special
advantages when that general is the governor of York but you lose
those advantages if you leave York. Basically, you use hasAncType
to check if the general has the EarlOfYork ancillary type (not name)
and is in the York settlement, then you give him an InResidence hidden
trait that confers those advantages. So it does work, you just have
to create new ancillary types for each and every title, for example.

Suraknar
12-02-2007, 02:36
This is great Alpaca!

I do have a small question in how to go about making the change I wish to make, this is the first time I mod Triggers and Conditions I am by no means experienced here at all.

basically I am trying to make St-john's chapter, Hospitaller Knights available to Byzantium. made the Changes in EDU and EDB and ModelDB...but they never seem to pop up, so I looked in deeper and found export_descr_guilds.txt, saw all the Trigger info and came here to search for it. :)

So I found these triggers:




;------------------------------------------
Trigger 0150_Crusading_Army_Created
WhenToTest GeneralJoinCrusade


Guild templars_chapter_house a 25
Guild st_johns_chapter_house a 25
Guild knights_of_santiago_chapter_house a 25
Guild teutonic_knights_chapter_house a 25



This basically awards points to all of a Factions settlements that accepts a Crusade.



;------------------------------------------
Trigger 0151_Crusading_Army_Abandon
WhenToTest GeneralAbandonCrusade


Guild templars_chapter_house a -25
Guild st_johns_chapter_house a -25
Guild knights_of_santiago_chapter_house a -25
Guild teutonic_knights_chapter_house a -25



This is the inverse of the above, when abandoning a Crusade. Loss of points.



;------------------------------------------
Trigger 0160_Recruit_Hospitaller_Knight
WhenToTest UnitTrained

Condition UnitType Knights Hospitaller

Guild st_johns_chapter_house s 10
Guild st_johns_chapter_house o 1



This awards points for recruiting Knights Hospitaller, some to the settlement of recruitment and some to the rest, but one has to have a St-john's Guild Chapter in the first place.



;------------------------------------------
Trigger 0170_Declare_War_Muslim_Faction
WhenToTest FactionWarDeclared

Condition TargetFactionReligion islam
and FactionReligion catholic

Guild st_johns_chapter_house a 10



This will award points to all the settlements of a Catholic Faction that Declares War on a Muslim Faction.



;------------------------------------------
Trigger 0171_Muslim_Neighbours
WhenToTest SettlementTurnStart

Condition NeighbourReligion islam > 50
and FactionReligion catholic

Guild st_johns_chapter_house s 10
Guild st_johns_chapter_house o 1



This will award points to Catholic factions neignboring Muslim Factions, more points to the settlement with the border and some points to the others.



;------------------------------------------
Trigger 0196_Governor_Chivalry
WhenToTest SettlementTurnStart

Condition GovernorAttribute Chivalry > 4

Guild woodsmens_guild s 5
Guild knights_of_santiago_chapter_house s 5
Guild st_johns_chapter_house s 5



Finally this will award points to the settlement containing a Governor with more than 4 Chivalry.

---------

From the above, Triggers 150 and 151, do not apply to Byzantium because it does not perform Crusades.

So the only Triggers that could be used are 160,170,171 and 196.

Question

My problem and question pertains more to triggers 170 and 170, due to the condition of:

and FactionReligion catholic

Above in your guide you said, all Conditions must be true, so If I were to append:

and FactionReligion orthodox

That would not work right? because a faction cant be both catholic and Orthodox at the same time.

Is the logic correct here or am I in la la land? :dizzy2:

Converselly if I were to remove that condition, then the trigger would award points to all even on Muslims vs Muslims. is that ok?

Is it possible to put an "or" in conditions? like:

and FactionReligion catholic
or FactionReligion orthodox

Finally, would it be better to just create new triggers all together specifically for Orthodox Factions (or even only Byzantium) than try to modify the existing ones?

Thanks for any clarification here, I guess, I am just trying to get some confirmation from the people with knowledge about this rather than go in trial and error mode. :sweatdrop:

Suraknar
12-02-2007, 05:44
Hrm, seems like its a Low Season for TW modding, and I haven't realized it :inquisitive:

In any case, I think I may have found a way, after looking at the Docudemon files :book: (which still does not make much sence but anyways :juggle2: ).

I am going to try modifying the Trigger conditions from:

Condition NeighbourReligion islam > 50
and FactionReligion catholic

And from including the Faction that we want to test as true to excluding the factions that we don't want as true, like so:

Condition NeighbourReligion islam > 50
and not FactionReligion islam
and not FactionReligion pagan
and not FactionReligion heretic

This way, if our faction is Catholic or Orthodox, it will be true since it is nor islam nor pagan nor heretic.

If this works...then its simpler than I thought..if it does not...I am in trouble! :sweatdrop:

More soon :)

alpaca
12-02-2007, 13:26
Yeah that should work.
In general you can also split up the trigger. Since these two conditions are mutually exclusive (a faction can't be catholic AND orthodox), a trigger which fires for catholics and one which fires for orthodox works fine.

An "or" keyword isn't implemented.

Suraknar
12-02-2007, 19:36
Thank you very much Alpaca for the confirmation!

I haven't had the offer yet for a St-John's Guild, but haven't had problems otherwise with these changes either, so I'll just keep playing now that you have confirmed the validity of this :)

Usually happy in making Graphical mods myself, and never really dabbled in to scripting more than modifying EDU EDB and Strat.

But this is somewhat fun too :)

(The only real turn down was modelDB this time around, heh, touk me sometime, but it works too, I'll post some findings in the other thread about it)

Cheers!

alpaca
12-02-2007, 20:25
Keep in mind though that I'm not 100% sure how the NeighbourReligion condition works. You should try to enable logging (search for that) and make a settlement where you should be guaranteed to get the trigger, and check if it actually fires in the log.

Suraknar
12-03-2007, 04:48
Ok, sounds great, will enable logging and see if it does.

First glance, I would assume that the "> 50" means it will award the points to the settlement bordering a region that has more than 50% of its population part of Islamic religion.

Which would mean that if a Faction has 3 regions bordering with 3 islamic regions then 10 points will be awarded for each of these settlements, then 3 points total to all the other settlements of that faction.

If the above assumption is correct.

I would also assume that calculations are performed on a settlement by settlement basis.

Yet your the expert here, you have more in depth knowledge.

alpaca
12-03-2007, 11:49
Judging from the docudemons entry I'd say the condition probably takes the average over all neighboring settlements. Which average though is the question:
Does it sum over each citizen or does it calculate percentage for each settlement and then takes the average over the settlements?

Suraknar
12-06-2007, 08:58
Ahh, averages, haven't thought of that.

The what it calculates I guess is the key component.

The condition is called "NeigborReligion" based on that, it is why I assume its about the Percentage of Population belonging to "Religion Islam".

Like in the following scenario.

lets say that the Turks are neighbors, and have 4 Regions, 2 of which have 10000 population, and 2 of which have 2500 each, for a total population of 25000.

Lets say that we send detachments of our priests over to the two regions with high population and over time our priests convert about 75% of thos population over to Christianity, it would then mean that the Turks have 15000 Christians and 10000 Muslims in their entire faction.

60% are Christians and 40% are Muslims, in that case, the Trigger would not apply because the condition is >50 must belong to islam is not true.

I am assuming the settlements with neighboring the Turks get tested one by one for this trigger.

What do you think?


EDIT: Small error on percentages was thinking 1/3rd
----

Btw the Logger gave me this:

"Trigger <0171_Muslim_Neighbours> fired"

So its working.

alpaca
12-06-2007, 15:48
Actually I was thinking that NeighbourReligion takes the average over all adjacent territories, not over adjacent factions.

Suraknar
03-03-2009, 02:06
Better late than never,

Just wanted to confirm that this is working pretty good All my provinces neighboring Islamic ones eventually got Hospitaller Knights.