AI triggers and team production
Draws one weighted AI trigger per house on a timer and turns the TeamTypes it names into recruitment and production demand.
TeamTypes and AI triggers in brief
Section titled “TeamTypes and AI triggers in brief”A team is a group of infantry, vehicles and aircraft that one house owns and that acts together. A computer house’s raids, attacks and base defense all arrive as teams.
A scenario does not hold teams. It holds TeamTypes, the definitions that teams are created from. A new team fills up with objects its house already owns or builds for the purpose. When the team reaches full strength it is started, or set under way. It pauses to gather, as team execution describes, and then works through its Script. What the team does after that is outside this page.
A TeamType is one INI section that points at two others. The table shows what each of the three sections contributes to the mechanics on this page.
| Where it is written | What it contributes |
|---|---|
The TaskForce section named by TaskForce= | The roster: up to six <count>,<ObjectType ID> lines. The sum of the counts is the team’s full strength, the number of members it wants. Full strength counts members, not hit points. |
The Script section named by Script= | The team missions the team carries out in order once it starts. Reaching the Success mission is the only thing the track record counts as a win. |
| The TeamType section itself | Which TaskForce and Script to use, the country House= gives the team to, the Waypoint= where the team starts and recruits, and the settings in the next table. |
A team raised by an AI trigger belongs to the house whose pass raised it, whatever country House= names. House= decides the owner only when a trigger action creates the team.
Eight more TeamType settings affect the decisions on this page. The table links each one to the section that covers it.
| Setting | Where it acts |
|---|---|
Max= | How many teams of the type one house may hold. A TeamType that never sets it is rejected before the draw, so no AI trigger can raise it. |
IsBaseDefense= | Marks the type as defensive. The team budget counts, caps and deletes defensive teams. |
Reinforce= | Keeps recruitment open after the team has started. |
Recruiter= | Lets recruitment take objects from outside the team’s group. |
Group= | The group recruitment draws from, and the group each member is given when it joins. |
Priority= | Whether recruitment may take a member from another team: only from a team of strictly lower priority. |
Autocreate= | Sets the autocreate mark from the start. |
AreTeamMembersRecruitable= | The value a joining member’s autocreate recruitable state is set to. |
Autocreated is a mark on a TeamType. It does not make the engine create teams by itself. Autocreate=yes sets the mark when the TeamType is read, and an AI trigger drawing the TeamType sets it permanently. The mark only decides which of an object’s two recruitable states a team of that type checks; recruitment covers the pair.
An AI trigger is one line in [AITriggerTypes]. It is unrelated to the tags, events and actions a map uses: nothing springs it, and it does nothing except name teams. Each line names a first TeamType and optionally a second, one condition, three weights, and a set of gate fields: difficulty flags, a side, a campaign owner and a skirmish flag. A house never picks a team directly. It draws a trigger and creates the TeamTypes that trigger names.
The example below shows one trigger and the three sections behind it.
[TaskForces]0=MyRaidForce
[MyRaidForce] ; example TaskForceName=Raid force0=3,E11=1,TTNK
[ScriptTypes]0=MyRaidScript
[MyRaidScript] ; example ScriptName=Raid0=0,1 ; attack anything1=49,0 ; Success; without it every raid team records a failure
[TeamTypes]0=MyRaidTeam
[MyRaidTeam] ; example TeamTypeName=Raid teamHouse=NodTaskForce=MyRaidForceScript=MyRaidScriptMax=4Priority=8
[AITriggerTypes]MyRaidTrigger=Raid a blacked-out base,MyRaidTeam,<all>,0,3,GAPOWR,0000000000000000,8,1,20,1,0,0,0,<none>,0,1,1The AI triggers page covers the fields of the trigger record. In this example:
Max=4is required. WithoutMax, no AI trigger can raise the TeamType.Priority=8lets a raid team take a member from a team left at the default priority of7.- Condition type
3holds while the enemy’s power output is below its drain. This condition ignores the comparison block and the condition object, soGAPOWRis never counted. - The last three fields leave the trigger off at Easy and on at Medium and Hard.
The pass in outline
Section titled “The pass in outline”Each house raises teams on its own countdown. When the countdown reaches zero, the house draws one AI trigger at random from those whose gates and condition currently hold. Each trigger’s chance depends on a weight that tracks how its past teams fared. The house then creates one team from the trigger’s first TeamType, and one from its second TeamType if it names one.
The new teams fill themselves from objects the house owns. A computer house orders the members still missing through its ordinary production. A human house orders no production for its teams.
When the pass runs
Section titled “When the pass runs”The countdown first runs for 175 * <the house's position in the house list> + TeamDelays frames, so houses do not all run their pass on the same frame. After every pass it restarts at TeamDelays alone.
Every house runs the pass, computer or human. The pass reaches the AI triggers only while both of these hold:
- a roll from
1to100comes out at or below the house’sRatioAITriggerTeam; - the house’s AI-trigger switch is on.
If either fails, the pass raises no team and the countdown restarts. A failed roll does not raise some other kind of team instead.
The switch starts off for every house. Four events change it:
| Event | Effect |
|---|---|
| AI triggers begin… | On, for the house the action names |
| AI triggers stop… | Off, for the house the action names |
| An MCV deploying into a construction yard | On, for a non-human house outside a campaign game |
| A house passing from a human player to the computer | On, if the house still holds a construction yard |
The begin action works on a human house as well. That house then raises teams from AI triggers like a computer house, but orders no production to fill them.
The team budget
Section titled “The team budget”Before examining any trigger, the house counts the teams it owns and how many of them come from IsBaseDefense=yes TeamTypes. Every team the house owns is counted, however it was created.
The two counts select one of two cases. Only the second case deletes a team.
| The house’s counts | What this pass does |
|---|---|
Fewer teams than TotalAITeamCap, or fewer defensive teams than half the team count, rounded down | Nothing is deleted. Defensive triggers are skipped in this pass if the defensive count is above MaximumAIDefensiveTeams. |
At least TotalAITeamCap teams, and at least half of them, rounded down, defensive | The house deletes its oldest defensive team, which lowers its team count by one. Defensive triggers are skipped in this pass whatever the defensive count. A house holding no defensive team deletes nothing and skips nothing. |
The house then goes on to draw a trigger only if its team count is below TotalAITeamCap.
Which triggers are eligible
Section titled “Which triggers are eligible”The house tests each trigger against these gates in order. The first gate that fails rejects the trigger.
- It names a first TeamType.
- It is defensive, or the house is not restricted to defensive triggers.
- It is not defensive, or the team budget is not skipping defensive triggers in this pass.
- It is a map-local trigger, or the scenario does not set
IgnoreGlobalAITriggers=yes. - It is enabled.
- Outside a campaign game, it is marked as available in skirmish.
- Its flag for the current difficulty is set.
- In a campaign game, its owner is not
<none>, and is either<all>or this house’s country. - Its side field is
0or less, or it gives the position in[Sides], counting from1, of the side of the country the house acts as. A value that names no side rejects the trigger. - The house’s tech level is at least the trigger’s tech level requirement.
- Its condition holds.
- The house can build every member of both TeamTypes’ TaskForces.
- Neither TeamType has reached its
Maxamong the teams this house owns.
The tech level requirement is not a field of the record. It is the highest TechLevel among the members of the trigger’s TaskForces, so a trigger requires what its teams require. A member with TechLevel=-1 raises the requirement to 11, which rejects the trigger for every house below tech level 11.
Difficulty
Section titled “Difficulty”The three difficulty flags on a trigger mean Easy, Medium and Hard as the player chose them. This holds for every house in a campaign game, and for computer houses outside one.
In a campaign game, the house tests the flag that matches the scenario’s difficulty. Outside a campaign, the house tests the flag opposite to its difficulty slot. A computer house’s slot is already the inverse of the setting the player chose, so the two inversions cancel. The table traces one computer house.
| Setting the player chose | Slot the computer house holds | Flag the trigger must set |
|---|---|---|
| Easy | 2, the [Difficult] section | Easy |
| Normal | 1, the [Normal] section | Medium |
| Hard | 0, the [Easy] section | Hard |
A human house outside a campaign always holds slot 1, so it always tests the Medium flag.
A computer seat’s [HouseHandicaps] value in a launch file sets its slot directly. It replaces both the inversion and the bonus described below. The flag the house tests then follows the slot column of the table, so a value of 0 tests the Hard flag.
The per-difficulty lists in [General] are not inverted a second time. Each list is indexed by the house’s slot, so for a computer house entry 0 applies at the hardest setting and entry 2 at the easiest. The lists are TeamDelays, TotalAITeamCap, MinimumAIDefensiveTeams, MaximumAIDefensiveTeams, FillEarliestTeamProbability and AIHateDelays.
Defensive teams and the enemy
Section titled “Defensive teams and the enemy”A trigger is defensive when its first TeamType is IsBaseDefense=yes and its second TeamType is either absent or defensive as well.
A house considers only defensive triggers while either of these holds:
- the house has no enemy;
- All of:
UseMinDefenseRule=yes, and the house has fewer defensive teams thanMinimumAIDefensiveTeams.
A house’s enemy is the house it is angriest with, and damage is what raises that anger. Outside a campaign, a computer house without an enemy also picks one on a timer. Nothing picks one on a timer in a campaign. A campaign house has no enemy until damage raises its anger or a map trigger action makes it an enemy of another house. Until then it considers only defensive triggers.
Conditions
Section titled “Conditions”The trigger record page lists the condition types. At runtime they measure the following:
- The two owning conditions count the objects of the condition object’s type that the enemy, or this house, currently owns. The count is compared against the record’s number with the record’s comparator. If the condition object ID is not recognized, the count is
0. - The yellow power condition ignores the record’s number and comparator. It holds while the enemy’s power output minus its drain is below
100. - The red power condition holds while the enemy’s power output minus its drain is below
0. - The money condition compares the enemy’s available credits against the record’s number with the record’s comparator.
Every condition except the one that counts this house’s objects reads the enemy. A house without an enemy can therefore pass only a defensive trigger that has no condition or counts the house’s objects.
The weighted draw
Section titled “The weighted draw”The house draws one trigger from those that passed every gate. Each trigger’s chance is in proportion to its current weight. Weights count only as whole numbers: the three weights in a record are truncated as it is read, and the current weight is truncated again for the draw. A trigger whose current weight is below 1 passes its gates but can never be drawn.
The track record
Section titled “The track record”Each trigger has a current weight, a minimum weight and a maximum weight, and two counters: the runs it has had and the runs that succeeded. The counters start at 0. Each weight is 1 unless the record supplies it.
When a team is removed for any reason, every trigger whose first TeamType is that team’s type records an outcome. The outcome is a success if the team reached the Success team mission at any point in its Script, and a failure otherwise.
Each outcome adds a history term and a fixed delta to the current weight. The history term is the number of successes so far minus half the number of runs so far, counted before this outcome. It is 0 at a success rate of exactly one in two, and it grows with the number of runs, so a long record moves the weight further than a short one. AITriggerTrackRecordCoefficient scales the history term for failures only.
| Outcome | History term added | Delta added | Counters afterward |
|---|---|---|---|
| Success | Successes minus half the runs, or 0 if that is negative | AITriggerSuccessWeightDelta | One more run, one more success |
| Failure | Successes minus half the runs, multiplied by AITriggerTrackRecordCoefficient, or 0 if that product is positive | AITriggerFailureWeightDelta | One more run |
After each outcome, the weight is clamped between the trigger’s minimum and maximum. A starting weight outside that range stays as written until the trigger’s first outcome.
Outcomes are keyed on the team’s TeamType alone. The engine does not check which trigger raised the team or which house owns it. As a result:
- every trigger that names the TeamType first records the same outcome;
- one house’s outcomes change the weights every other house draws with;
- a team that a map trigger action created also records outcomes;
- a team created from a trigger’s second TeamType records outcomes only for triggers that name that TeamType first.
From suggestion to team
Section titled “From suggestion to team”Before creating anything, the house checks the teams it already owns. If one of them is reforming or not under way, and its TeamType is either of the drawn trigger’s TeamTypes, the house discards the whole draw. Neither TeamType is created.
Each TeamType that survives is marked as autocreated for the rest of the scenario. Autocreate=yes sets the same mark from the start. Recruitment reads the mark. So does the campaign substitute in gate 12, because it asks whether the team could recruit the object it finds.
The house then creates one team from each surviving TeamType. Each creation checks Max again, and this check differs from the eligibility gate:
- In a campaign game, it counts the teams of that type that any house owns.
- Outside a campaign, it counts the teams of that type this house owns, the same count the eligibility gate used.
A campaign house can therefore pass the eligibility gate and still create nothing, because other houses’ teams of the same type count toward Max.
Recruitment
Section titled “Recruitment”A team fills its TaskForce by taking objects its house already owns. It looks for them on each of its logic turns while all of this holds:
- Any of:
- the team is not under way: it has not started yet, or it was sent back to regroup, which happens only to a
Reinforce=yesteam; - All of: it is short of full strength, and its TeamType is
Reinforce=yes.
- the team is not under way: it has not started yet, or it was sent back to regroup, which happens only to a
- Any of:
- the team belongs to a computer house;
- the team has never reached full strength and has never started.
The second group closes recruitment on a human house’s team for good once the team reaches full strength or starts. Losing members afterward does not reopen it, and neither does Reinforce=yes.
On each turn, the team adds at most one member for each roster line that is still short. Passengers inside a recruited transport do not join the team with it.
The team takes the nearest candidate that passes every check below. Distance is measured from the cell of the TeamType’s Waypoint, or from the team’s center when it has no waypoint. An object is considered at all only under one of these:
- the team’s group is
-2; - the object is in the team’s group;
- the TeamType is
Recruiter=yes.
A candidate from outside the team’s group counts as 50 cells farther away than it is. The team therefore takes it only if it is more than 50 cells nearer than every candidate from the group.
The team’s group is the TeamType’s Group. While the TeamType leaves Group at -1, the TaskForce’s Group is used instead. Each member’s group is set to the team’s group when it joins.
A considered candidate must pass these checks, in this order:
- It is not already on this team.
- It is alive and on the map, it is not in radio contact, and its house is the team’s house.
- It has no mission, or its current mission is one that allows recruitment.
- Its recruitable state for this kind of team is set, as described below.
- If it is on another team, that team’s
Priorityis strictly lower than this team’s. - It is not an armed aircraft that is out of ammunition.
- Its type matches one of the TaskForce’s roster lines, and that line still has room.
Every object has two recruitable states: one for ordinary teams and one for autocreated teams. A team whose TeamType is not marked autocreated checks only the ordinary state. A marked team checks only the autocreate state. Both states start set, unless a map’s placed-object record clears one.
Joining any team sets the object’s autocreate state to that TeamType’s AreTeamMembersRecruitable. A team with AreTeamMembersRecruitable=no keeps its members out of autocreated teams, even after the team itself is gone. The lock lasts until the object joins a team whose TeamType sets AreTeamMembersRecruitable=yes.
A team with no members is deleted in either of these cases:
- it has reached full strength or started at some point;
- outside a campaign, more than
DissolveUnfilledTeamDelayframes have passed since it was created.
The second case is the usual end of a team whose TaskForce the house could not fill. In a campaign, an empty team that never filled is not deleted this way. It stays and keeps recruiting. Until it fills, it counts toward Max and the team budget, and it makes the house discard every draw that names its TeamType.
Production demand
Section titled “Production demand”Only computer houses order production for their teams. The base planner chooses structures. Vehicles, infantry and aircraft each have a separate chooser, and all three work the same way.
Two cases come before the steps below. The vehicle chooser may order a harvester instead when the house is short of harvesters for its refineries. A chooser that already has a type selected and not yet built does nothing.
A computer house normally runs the base planner and all three choosers together. When its credits fall below AIAlternateProductionCreditCutoff, it alternates between structures and units instead. While structures have their turn, the three choosers run only if the base planner has chosen no structure, or one the house cannot build. In a campaign game no house alternates.
-
Demand. A team of this house adds to demand in either of these cases:
- All of: its TeamType is
Reinforce=yes, and it is short of full strength; - All of: it is not forced active, and it has never reached full strength or started. Only a reinforcement group is forced active.
Each unfilled roster place of a type the chooser builds adds one to that type’s demand. For each type, the house also notes the creation time of the oldest team that wants it.
- All of: its TeamType is
-
Supply. Each object of the house that is free to recruit takes one off its type’s demand. An object is free when it is on the map, on no team, on a mission that allows recruitment, and its ordinary recruitable state is set.
-
Candidates. A type is a candidate while its demand is above zero, the house can build it, and its cost is within the house’s available credits.
-
Choice. With a chance of
FillEarliestTeamProbabilitypercent, the house builds the candidate wanted by the oldest team. Otherwise it picks from the candidate list at random, with equal chances.
Supply does not check the autocreate recruitable state. An object that AreTeamMembersRecruitable=no locked away still takes one off demand, although no autocreated team can recruit it.
The random pick does not favor the types in greatest demand. The candidate list is emptied only when the house reaches a candidate with more demand than every candidate before it. The list therefore holds that type and every candidate registered after it, including candidates with less demand. Which types those are depends on the order the types are registered in.
Demand is counted for every registered InfantryType, UnitType and AircraftType, however many a mod defines.
Parsed settings without effect
Section titled “Parsed settings without effect”A TeamType’s Prebuild and LooseRecruit are read but have no effect, and neither does the TeamType’s TechLevel. A trigger’s tech level requirement comes from its TaskForce members instead. AutocreateTime in [AI] is read but reaches only disabled code.
Related settings
31 of 31
| Key | Description | Value | When omitted |
|---|---|---|---|
AIHateDelaysglobal rules | The frames a computer house waits before picking its first enemy, one entry per difficulty. | list of integers | (empty) |
AITriggerFailureWeightDeltaglobal rules | The amount added to an AI trigger's weight each time a team of its first TeamType fails. | floating point | -1 |
AITriggerSuccessWeightDeltaglobal rules | The amount added to an AI trigger's weight each time a team of its first TeamType succeeds. | floating point | 1 |
AITriggerTrackRecordCoefficientglobal rules | The multiplier applied to an AI trigger's history term when one of its teams fails. | floating point | 1 |
AreTeamMembersRecruitableTeamType | The autocreate-recruitable state written onto each object as it joins a team of this type. | boolean | yes |
AutocreateTeamType | Which of an object's two recruitable states a team of this type reads when it recruits. | boolean | no |
AutocreateTimeNo effectglobal rules | Parsed number that the engine never uses. | floating point | 5 |
CompEasyBonusglobal rules | Whether a computer house drops one difficulty slot when the session holds more than one human seat. | boolean | yes |
DissolveUnfilledTeamDelayglobal rules | The frames an empty team outside a campaign waits before dissolving itself. | integer | 5000 |
FillEarliestTeamProbabilityglobal rules | The percent chance that the next vehicle, infantryman or aircraft chosen goes to the oldest waiting team, one entry per difficulty. | list of integers | (empty) |
GroupTeamType, TaskForce | The recruitment group a team draws its members from, taken from the TaskForce when the TeamType leaves its own unset. | integer | -1 |
HouseTeamType | The house, named by country or start position, that owns teams a trigger action creates from this TeamType. | HouseType | none |
IgnoreGlobalAITriggersscenarios | Whether the scenario passes over every AI trigger that was not defined by the map itself. | boolean | no |
IsBaseDefenseBuildingType, TeamType | Gives a BuildingType the computed ratings the computer picks base defenses by, or counts a TeamType against its house's defensive team total. | boolean | no |
LooseRecruitNo effectTeamType | Parsed TeamType flag that the engine never uses. | boolean | no |
MaxTeamType | How many teams of this TeamType can exist before AI triggers stop raising more. | integer | 0 |
MaximumAIDefensiveTeamsglobal rules | The number of defensive teams above which a house passes over its defensive AI triggers, one entry per difficulty. | list of integers | (empty) |
MinimumAIDefensiveTeamsglobal rules | The number of defensive teams a house must hold before any non-defensive AI trigger may spring, one entry per difficulty. | list of integers | (empty) |
PrebuildNo effectTeamType | Parsed TeamType flag that the engine never uses. | boolean | no |
PriorityTeamType, Sounds | How firmly a team holds its members against other teams, or how hard a sound competes for a playback channel. | integer | Varies by type |
RatioAITriggerTeamHouse (per-scenario) | The percent chance that a house reads its AI triggers when its team countdown expires. | integer | 100 |
Recruitablemission behavior | Whether an object in this mission may be taken onto a team. | boolean | yes |
RecruiterTeamType | Whether a team of this type may recruit an object whose group does not match its own. | boolean | no |
ReinforceTeamType | Whether a team of this type keeps recruiting after it has begun to move. | boolean | no |
ScriptTeamType | The Script whose team missions a team of this type carries out. | class | none |
TaskForceTeamType | The TaskForce whose composition a team of this type recruits and builds toward. | class | none |
TeamDelaysglobal rules | The frames a house waits between team creation passes, one entry per difficulty. | list of integers | (empty) |
TechLevelNo effect in some scopes7 applicable types | The level an object type requires, the level a house holds, the starting value of the tech level setting for skirmish and network games, or a TeamType level that nothing reads. | integer | Varies by type |
TotalAITeamCapglobal rules | Team count at which a house stops starting teams from AI triggers, one entry per difficulty. | list of integers | (empty) |
UseMinDefenseRuleglobal rules | Whether a house must hold its minimum number of defensive teams before any other AI trigger may spring. | boolean | yes |
WaypointTeamType | The waypoint a team of this type starts at and recruits around. | string | none |
No keys match the current filters.