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.
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.