Annotate campaign.lua

This commit is contained in:
JovialFeline
2025-02-09 03:37:05 -05:00
committed by Matthias Mailänder
parent 96de59f75a
commit 459bbf0025
3 changed files with 128 additions and 10 deletions

View File

@@ -9,6 +9,8 @@
Difficulty = Map.LobbyOptionOrDefault("difficulty", "normal")
--- Prepare basic messages for a player's win, loss, or objective updates.
---@param player player
InitObjectives = function(player)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), UserInterface.GetFluentMessage("objective-completed"))
@@ -29,6 +31,12 @@ InitObjectives = function(player)
end)
end
--- Send reinforcements carried by a naval landing craft.
---@param player player Owner of the landing craft and its passengers.
---@param units string[] Unit types to spawn and unload.
---@param transportStart cpos Cell at which the craft spawns and removes itself.
---@param transportUnload cpos Cell at which passengers unload.
---@param rallypoint? cpos Cell to which unloaded passengers will move.
ReinforceWithLandingCraft = function(player, units, transportStart, transportUnload, rallypoint)
local transport = Actor.Create("lst", true, { Owner = player, Facing = Angle.North, Location = transportStart })
local subcell = 1
@@ -61,6 +69,10 @@ ReinforceWithLandingCraft = function(player, units, transportStart, transportUnl
transport.Destroy()
end
--- Schedule repairs for this building once it takes enough damage.
---@param owner player Owner of the building.
---@param actor actor Building to be repaired.
---@param modifier number The repair threshold. Below this health percentage, repairs are started. 1 is full health, while 0.5 is half.
RepairBuilding = function(owner, actor, modifier)
Trigger.OnDamaged(actor, function(building)
if building.Owner == owner and building.Health < building.MaxHealth * modifier then
@@ -69,6 +81,9 @@ RepairBuilding = function(owner, actor, modifier)
end)
end
--- Schedule repairs for a player's starting buildings.
---@param owner player Owner of the buildings.
---@param modifier number The repair threshold. Below this health percentage, repairs are started. 1 is full health, while 0.5 is half.
RepairNamedActors = function(owner, modifier)
Utils.Do(Map.NamedActors, function(actor)
if actor.Owner == owner and actor.HasProperty("StartBuildingRepairs") then
@@ -77,6 +92,12 @@ RepairNamedActors = function(owner, modifier)
end)
end
--- Schedule production tasks for a factory or other unit producer.
---@param player player Owner of the factory.
---@param factory actor The factory itself.
---@param delay? fun():integer Function that returns a delay until production repeats. If this is absent, production will not repeat.
---@param toBuild fun():string[] Function that returns a list of unit types to be produced.
---@param after? fun(actors: actor[]) Function called by each group of built units after their production is finished. Only alive actors are included.
ProduceUnits = function(player, factory, delay, toBuild, after)
if factory.IsDead or factory.Owner ~= player then
return
@@ -93,6 +114,10 @@ ProduceUnits = function(player, factory, delay, toBuild, after)
end)
end
--- Check if a player currently owns one of each building type in a list.
---@param player player
---@param buildingTypes string[]
---@return boolean
CheckForBase = function(player, buildingTypes)
local count = 0
@@ -105,6 +130,10 @@ CheckForBase = function(player, buildingTypes)
return count == #buildingTypes
end
--- Schedule production of a unit's replacement after its death.
---@param unit { [1]: actor }
---@param player player
---@param factory actor
RebuildUnit = function(unit, player, factory)
Trigger.OnKilled(unit[1], function()
ProduceUnits(player, factory, nil, function() return { unit[1].Type } end, function(actors)
@@ -113,13 +142,16 @@ RebuildUnit = function(unit, player, factory)
end)
end
MoveAndHunt = function(actors, path)
--- Order a group to attack-move toward each waypoint in a list, then hunt.
---@param actors actor[]
---@param waypoints actor[]
MoveAndHunt = function(actors, waypoints)
Utils.Do(actors, function(actor)
if not actor or actor.IsDead then
return
end
Utils.Do(path, function(point)
Utils.Do(waypoints, function(point)
actor.AttackMove(point.Location)
end)
@@ -127,19 +159,25 @@ MoveAndHunt = function(actors, path)
end)
end
MoveAndIdle = function(actors, path)
--- Order a group to move toward each waypoint in a list.
---@param actors any
---@param waypoints actor[]
MoveAndIdle = function(actors, waypoints)
Utils.Do(actors, function(actor)
if not actor or actor.IsDead then
return
end
Utils.Do(path, function(point)
Utils.Do(waypoints, function(point)
actor.Move(point.Location, 0)
end)
end)
end
Searches = 0
--- Get the position of a hostile, mobile actor that is distant from anti-air sites.
---@param player player Player to be targeted.
---@return wpos|nil target The chosen airstrike position, if any.
GetAirstrikeTarget = function(player)
local list = player.GetGroundAttackers()

View File

@@ -9,6 +9,8 @@
Difficulty = Map.LobbyOptionOrDefault("difficulty", "normal")
--- Prepare basic messages for a player's win, loss, or objective updates.
---@param player player
InitObjectives = function(player)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), UserInterface.GetFluentMessage("objective-completed"))
@@ -29,11 +31,22 @@ InitObjectives = function(player)
end)
end
---The Dune stand-in for the usual "Battlefield Control" announcer.
Mentat = UserInterface.GetFluentMessage("mentat")
SendCarryallReinforcements = function(player, currentWave, totalWaves, delay, pathFunction, unitTypes, customCondition, customHuntFunction, announcementFunction)
--- Prepare waves of reinforcements to be deployed from Carryalls.
---@param player player Owner of the reinforcements and Carryalls.
---@param currentWave integer Current wave count. A typical starting value is 0.
---@param totalWaves integer Total number of waves to be reinforced.
---@param delay integer Ticks between each reinforcement.
---@param pathFunction fun():cpos[] Returns a path for each Carryall's entry flight.
---@param unitTypes table<integer, string[]> Collection of unit types that will be reinforced. Each group within this collection is keyed to a different wave number.
---@param haltCondition? fun():boolean Returns true if reinforcements should stop. If this function is absent, assume false.
---@param customHuntFunction? fun(actors: actor[]) Function called by each unit within a group upon creation. This defaults to IdleHunt. Note that reinforced units will not be in the world until unloaded.
---@param announcementFunction? fun(currentWave: integer) Function called when a new Carryall is created.
SendCarryallReinforcements = function(player, currentWave, totalWaves, delay, pathFunction, unitTypes, haltCondition, customHuntFunction, announcementFunction)
Trigger.AfterDelay(delay, function()
if customCondition and customCondition() then
if haltCondition and haltCondition() then
return
end
@@ -54,14 +67,21 @@ SendCarryallReinforcements = function(player, currentWave, totalWaves, delay, pa
end
Utils.Do(units, customHuntFunction)
SendCarryallReinforcements(player, currentWave, totalWaves, delay, pathFunction, unitTypes, customCondition, customHuntFunction)
SendCarryallReinforcements(player, currentWave, totalWaves, delay, pathFunction, unitTypes, haltCondition, customHuntFunction)
end)
end
TriggerCarryallReinforcements = function(triggeringPlayer, reinforcingPlayer, area, unitTypes, path, customCondition)
--- Create a one-time area trigger that reinforces attackers with a Carryall.
---@param triggeringPlayer player
---@param reinforcingPlayer player
---@param area cpos[]
---@param unitTypes string[]
---@param path cpos[] Returns a path for the Carryall's entry flight.
---@param pauseCondition? fun():boolean Returns true if this trigger's activation should be paused. If this function is absent, assume false.
TriggerCarryallReinforcements = function(triggeringPlayer, reinforcingPlayer, area, unitTypes, path, pauseCondition)
local fired = false
Trigger.OnEnteredFootprint(area, function(a, id)
if customCondition and customCondition() then
if pauseCondition and pauseCondition() then
return
end
@@ -74,17 +94,36 @@ TriggerCarryallReinforcements = function(triggeringPlayer, reinforcingPlayer, ar
end)
end
--- Destroy all non-reinforcement Carryalls owned by a player.
---@param player player
DestroyCarryalls = function(player)
Utils.Do(player.GetActorsByType("carryall"), function(actor) actor.Kill() end)
end
-- Used for the AI:
--- The following tables are used by the campaign AI,
--- with each value keyed to a different AI player.
--- Collection of a bot's spare units from production and reinforcement.
--- These units are used for periodic attacks or base/harvester defense.
---@type table<player, actor[]>
IdlingUnits = { }
--- Is a bot currently using idle units to attack or defend?
---@type table<player, boolean>
Attacking = { }
--- Is a bot's production routine on hold?
---@type table<player, boolean>
HoldProduction = { }
--- Was a bot's last harvester eaten by a sandworm?
---@type table<player, boolean>
LastHarvesterEaten = { }
--- Gather units from a bot's idle unit pool, up to a certain group size.
---@param owner player
---@param size integer
---@return actor[]
SetupAttackGroup = function(owner, size)
local units = { }
@@ -104,6 +143,9 @@ SetupAttackGroup = function(owner, size)
return units
end
--- Order an attack from this bot if one is not already started.
---@param owner player
---@param size integer
SendAttack = function(owner, size)
if Attacking[owner] then
return
@@ -120,6 +162,10 @@ SendAttack = function(owner, size)
end)
end
--- Prepare a unit to call for help if attacked.
---@param unit actor
---@param defendingPlayer player
---@param defenderCount integer
DefendActor = function(unit, defendingPlayer, defenderCount)
Trigger.OnDamaged(unit, function(self, attacker)
if unit.Owner ~= defendingPlayer then
@@ -154,7 +200,12 @@ DefendActor = function(unit, defendingPlayer, defenderCount)
end)
end
--- Prepare a harvester to call for help when attacked.
---@param unit actor
---@param owner player
---@param defenderCount integer
ProtectHarvester = function(unit, owner, defenderCount)
-- Note that worm attacks will not trigger the OnDamaged event for this.
DefendActor(unit, owner, defenderCount)
-- Worms don't kill the actor, but dispose it instead.
@@ -172,6 +223,10 @@ ProtectHarvester = function(unit, owner, defenderCount)
end)
end
--- Schedule repairs for this building once it takes enough damage.
---@param owner player Owner of the building.
---@param actor actor Building to be repaired.
---@param modifier number The repair threshold. Below this health percentage, repairs are started. 1 is full health, while 0.5 is half.
RepairBuilding = function(owner, actor, modifier)
Trigger.OnDamaged(actor, function(building)
if building.Owner == owner and building.Health < building.MaxHealth * modifier then
@@ -180,6 +235,11 @@ RepairBuilding = function(owner, actor, modifier)
end)
end
--- Prepare buildings to call for help and begin repairs if attacked.
---@param owner player Owner of the base.
---@param baseBuildings actor[] Buildings to defend and repair.
---@param modifier number The repair threshold. Below this health percentage, repairs are started. 1 is full health, while 0.5 is half.
---@param defenderCount integer Maximum number of defenders to use per counterattack.
DefendAndRepairBase = function(owner, baseBuildings, modifier, defenderCount)
Utils.Do(baseBuildings, function(actor)
if actor.IsDead then
@@ -191,6 +251,13 @@ DefendAndRepairBase = function(owner, baseBuildings, modifier, defenderCount)
end)
end
--- Schedule production and attacks for a factory or other unit producer.
---@param player player Owner of the factory.
---@param factory actor The factory itself.
---@param delay fun():integer Function that returns a delay until production repeats.
---@param toBuild fun():string[] Function that returns a list of unit types to be produced.
---@param attackSize integer Number of units that will form the next attack wave.
---@param attackThresholdSize integer Number of idle units that will trigger an attack wave.
ProduceUnits = function(player, factory, delay, toBuild, attackSize, attackThresholdSize)
if factory.IsDead or factory.Owner ~= player then
return

View File

@@ -9,6 +9,8 @@
Difficulty = Map.LobbyOptionOrDefault("difficulty", "normal")
--- Prepare basic messages for a player's win, loss, or objective updates.
---@param player player
InitObjectives = function(player)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), UserInterface.GetFluentMessage("objective-completed"))
@@ -31,6 +33,10 @@ InitObjectives = function(player)
end
AttackAircraftTargets = { }
--- Order an aircraft to seek and attack an enemy player's units whenever idle.
--- Each target is focused until it can no longer be attacked.
---@param aircraft actor
---@param enemyPlayer player
InitializeAttackAircraft = function(aircraft, enemyPlayer)
Trigger.OnIdle(aircraft, function()
local actorId = tostring(aircraft)
@@ -50,6 +56,10 @@ InitializeAttackAircraft = function(aircraft, enemyPlayer)
end)
end
--- Return a random enemy target for an actor.
---@param unit actor Actor to be given a target.
---@param enemyPlayer player Player to be targeted.
---@return actor|nil
ChooseRandomTarget = function(unit, enemyPlayer)
local target = nil
local enemies = Utils.Where(enemyPlayer.GetActors(), function(self)
@@ -61,6 +71,9 @@ ChooseRandomTarget = function(unit, enemyPlayer)
return target
end
--- Call a function when one of the actors in a group is damaged. The callback function will be called as func(self: actor, attacker: actor, damage: integer).
---@param actors actor[]
---@param func fun(self: actor, attacker: actor, damage: integer)
OnAnyDamaged = function(actors, func)
Utils.Do(actors, function(actor)
Trigger.OnDamaged(actor, func)