Skip to content

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.

Features & systemsScenarios & AIAI & teams

Changed in 0.1.0

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

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

AI.INI, AIFS.INI, or map file
[TaskForces]
0=MyRaidForce
[MyRaidForce] ; example TaskForce
Name=Raid force
0=3,E1
1=1,TTNK
[ScriptTypes]
0=MyRaidScript
[MyRaidScript] ; example Script
Name=Raid
0=0,1 ; attack anything
1=49,0 ; Success; without it every raid team records a failure
[TeamTypes]
0=MyRaidTeam
[MyRaidTeam] ; example TeamType
Name=Raid team
House=Nod
TaskForce=MyRaidForce
Script=MyRaidScript
Max=4
Priority=8
[AITriggerTypes]
MyRaidTrigger=Raid a blacked-out base,MyRaidTeam,<all>,0,3,GAPOWR,0000000000000000,8,1,20,1,0,0,0,<none>,0,1,1

The AI triggers page covers the fields of the trigger record. In this example:

  • Max=4 is required. Without Max, no AI trigger can raise the TeamType.
  • Priority=8 lets a raid team take a member from a team left at the default priority of 7.
  • Condition type 3 holds while the enemy’s power output is below its drain. This condition ignores the comparison block and the condition object, so GAPOWR is never counted.
  • The last three fields leave the trigger off at Easy and on at Medium and Hard.

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.

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 1 to 100 comes out at or below the house’s RatioAITriggerTeam;
  • 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:

EventEffect
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 yardOn, for a non-human house outside a campaign game
A house passing from a human player to the computerOn, 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.

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 countsWhat this pass does
Fewer teams than TotalAITeamCap, or fewer defensive teams than half the team count, rounded downNothing 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, defensiveThe 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.

The house tests each trigger against these gates in order. The first gate that fails rejects the trigger.

  1. It names a first TeamType.
  2. It is defensive, or the house is not restricted to defensive triggers.
  3. It is not defensive, or the team budget is not skipping defensive triggers in this pass.
  4. It is a map-local trigger, or the scenario does not set IgnoreGlobalAITriggers=yes.
  5. It is enabled.
  6. Outside a campaign game, it is marked as available in skirmish.
  7. Its flag for the current difficulty is set.
  8. In a campaign game, its owner is not <none>, and is either <all> or this house’s country.
  9. Its side field is 0 or less, or it gives the position in [Sides], counting from 1, of the side of the country the house acts as. A value that names no side rejects the trigger.
  10. The house’s tech level is at least the trigger’s tech level requirement.
  11. Its condition holds.
  12. The house can build every member of both TeamTypes’ TaskForces.
  13. Neither TeamType has reached its Max among 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.

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 choseSlot the computer house holdsFlag the trigger must set
Easy2, the [Difficult] sectionEasy
Normal1, the [Normal] sectionMedium
Hard0, the [Easy] sectionHard

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.

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:

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.

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

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.

OutcomeHistory term addedDelta addedCounters afterward
SuccessSuccesses minus half the runs, or 0 if that is negativeAITriggerSuccessWeightDeltaOne more run, one more success
FailureSuccesses minus half the runs, multiplied by AITriggerTrackRecordCoefficient, or 0 if that product is positiveAITriggerFailureWeightDeltaOne 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.

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.

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=yes team;
    • All of: it is short of full strength, and its TeamType is Reinforce=yes.
  • 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:

  1. It is not already on this team.
  2. It is alive and on the map, it is not in radio contact, and its house is the team’s house.
  3. It has no mission, or its current mission is one that allows recruitment.
  4. Its recruitable state for this kind of team is set, as described below.
  5. If it is on another team, that team’s Priority is strictly lower than this team’s.
  6. It is not an armed aircraft that is out of ammunition.
  7. 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 DissolveUnfilledTeamDelay frames 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.

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.

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

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

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

  4. Choice. With a chance of FillEarliestTeamProbability percent, 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.

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.

31 of 31

KeyDescriptionValueWhen omitted
AIHateDelaysglobal rulesThe frames a computer house waits before picking its first enemy, one entry per difficulty.list of integers(empty)
AITriggerFailureWeightDeltaglobal rulesThe amount added to an AI trigger's weight each time a team of its first TeamType fails.floating point-1
AITriggerSuccessWeightDeltaglobal rulesThe amount added to an AI trigger's weight each time a team of its first TeamType succeeds.floating point1
AITriggerTrackRecordCoefficientglobal rulesThe multiplier applied to an AI trigger's history term when one of its teams fails.floating point1
AreTeamMembersRecruitableTeamTypeThe autocreate-recruitable state written onto each object as it joins a team of this type.booleanyes
AutocreateTeamTypeWhich of an object's two recruitable states a team of this type reads when it recruits.booleanno
AutocreateTimeNo effectglobal rulesParsed number that the engine never uses.floating point5
CompEasyBonusglobal rulesWhether a computer house drops one difficulty slot when the session holds more than one human seat.booleanyes
DissolveUnfilledTeamDelayglobal rulesThe frames an empty team outside a campaign waits before dissolving itself.integer5000
FillEarliestTeamProbabilityglobal rulesThe 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, TaskForceThe recruitment group a team draws its members from, taken from the TaskForce when the TeamType leaves its own unset.integer-1
HouseTeamTypeThe house, named by country or start position, that owns teams a trigger action creates from this TeamType.HouseTypenone
IgnoreGlobalAITriggersscenariosWhether the scenario passes over every AI trigger that was not defined by the map itself.booleanno
IsBaseDefenseBuildingType, TeamTypeGives a BuildingType the computed ratings the computer picks base defenses by, or counts a TeamType against its house's defensive team total.booleanno
LooseRecruitNo effectTeamTypeParsed TeamType flag that the engine never uses.booleanno
MaxTeamTypeHow many teams of this TeamType can exist before AI triggers stop raising more.integer0
MaximumAIDefensiveTeamsglobal rulesThe number of defensive teams above which a house passes over its defensive AI triggers, one entry per difficulty.list of integers(empty)
MinimumAIDefensiveTeamsglobal rulesThe 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 effectTeamTypeParsed TeamType flag that the engine never uses.booleanno
PriorityTeamType, SoundsHow firmly a team holds its members against other teams, or how hard a sound competes for a playback channel.integerVaries by type
RatioAITriggerTeamHouse (per-scenario)The percent chance that a house reads its AI triggers when its team countdown expires.integer100
Recruitablemission behaviorWhether an object in this mission may be taken onto a team.booleanyes
RecruiterTeamTypeWhether a team of this type may recruit an object whose group does not match its own.booleanno
ReinforceTeamTypeWhether a team of this type keeps recruiting after it has begun to move.booleanno
ScriptTeamTypeThe Script whose team missions a team of this type carries out.classnone
TaskForceTeamTypeThe TaskForce whose composition a team of this type recruits and builds toward.classnone
TeamDelaysglobal rulesThe frames a house waits between team creation passes, one entry per difficulty.list of integers(empty)
TechLevelNo effect in some scopes7 applicable typesThe 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.integerVaries by type
TotalAITeamCapglobal rulesTeam count at which a house stops starting teams from AI triggers, one entry per difficulty.list of integers(empty)
UseMinDefenseRuleglobal rulesWhether a house must hold its minimum number of defensive teams before any other AI trigger may spring.booleanyes
WaypointTeamTypeThe waypoint a team of this type starts at and recruits around.stringnone

History

  1. Changed0.1.0

    Size AI production demand from the type registries