Files
OpenRA/mods/cnc/scripts/campaign.lua
let5sne.win10 9cf6ebb986
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled
Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 21:46:54 +08:00

204 lines
6.3 KiB
Lua

--[[
Copyright (c) The OpenRA Developers and Contributors
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version. For more
information, see COPYING.
]]
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"))
end)
Trigger.OnObjectiveFailed(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), UserInterface.GetFluentMessage("objective-failed"))
end)
Trigger.OnPlayerLost(player, function()
Trigger.AfterDelay(DateTime.Seconds(1), function()
Media.PlaySpeechNotification(player, "Lose")
end)
end)
Trigger.OnPlayerWon(player, function()
Trigger.AfterDelay(DateTime.Seconds(1), function()
Media.PlaySpeechNotification(player, "Win")
end)
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
if #units == 1 then
subcell = 0
end
Utils.Do(units, function(a)
transport.LoadPassenger(Actor.Create(a, false, { Owner = transport.Owner, Facing = transport.Facing, Location = transportUnload, SubCell = subcell }))
subcell = subcell + 1
end)
transport.ScriptedMove(transportUnload)
transport.CallFunc(function()
Utils.Do(units, function()
local a = transport.UnloadPassenger()
a.IsInWorld = true
a.MoveIntoWorld(transport.Location - CVec.New(0, 1))
if rallypoint then
a.Move(rallypoint)
end
end)
end)
transport.Wait(5)
transport.ScriptedMove(transportStart)
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
building.StartBuildingRepairs()
end
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
RepairBuilding(owner, actor, modifier)
end
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
end
factory.Build(toBuild(), function(units)
if delay and delay() > 0 then
Trigger.AfterDelay(delay(), function() ProduceUnits(player, factory, delay, toBuild, after) end)
end
if after then
after(units)
end
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
Utils.Do(buildingTypes, function(name)
if #player.GetActorsByType(name) > 0 then
count = count + 1
end
end)
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)
RebuildUnit(actors, player, factory)
end)
end)
end
--- 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(waypoints, function(point)
actor.AttackMove(point.Location)
end)
IdleHunt(actor)
end)
end
--- 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(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()
if #list == 0 then
return
end
local target = list[DateTime.GameTime % #list + 1].CenterPosition
local sams = Map.ActorsInCircle(target, WDist.New(8 * 1024), function(actor)
return actor.Type == "sam" end)
if #sams == 0 then
Searches = 0
return target
elseif Searches < 6 then
Searches = Searches + 1
return GetAirstrikeTarget(player)
else
Searches = 0
return nil
end
end