Files
OpenRA/mods/d2k/bits/scripts/campaign-global.lua

217 lines
5.9 KiB
Lua

--[[
Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
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.LobbyOption("difficulty")
IdleHunt = function(actor)
if actor.HasProperty("Hunt") and not actor.IsDead then
Trigger.OnIdle(actor, actor.Hunt)
end
end
InitObjectives = function(player)
Trigger.OnObjectiveAdded(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
end)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "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
SendCarryallReinforcements = function(player, currentWave, totalWaves, delay, pathFunction, unitTypes, customCondition, customHuntFunction, announcementFunction)
Trigger.AfterDelay(delay, function()
if customCondition and customCondition() then
return
end
currentWave = currentWave + 1
if currentWave > totalWaves then
return
end
if announcementFunction then
announcementFunction(currentWave)
end
local path = pathFunction()
local units = Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", unitTypes[currentWave], path, { path[1] })[2]
if not customHuntFunction then
customHuntFunction = IdleHunt
end
Utils.Do(units, customHuntFunction)
SendCarryallReinforcements(player, currentWave, totalWaves, delay, pathFunction, unitTypes, customCondition, customHuntFunction)
end)
end
TriggerCarryallReinforcements = function(triggeringPlayer, reinforcingPlayer, area, unitTypes, path, customCondition)
local fired = false
Trigger.OnEnteredFootprint(area, function(a, id)
if customCondition and customCondition() then
return
end
if not fired and a.Owner == triggeringPlayer and a.Type ~= "carryall" then
fired = true
Trigger.RemoveFootprintTrigger(id)
local units = Reinforcements.ReinforceWithTransport(reinforcingPlayer, "carryall.reinforce", unitTypes, path, { path[1] })[2]
Utils.Do(units, IdleHunt)
end
end)
end
-- Used for the AI:
IdlingUnits = { }
Attacking = { }
HoldProduction = { }
LastHarvesterEaten = { }
SetupAttackGroup = function(owner, size)
local units = { }
for i = 0, size, 1 do
if #IdlingUnits[owner] == 0 then
return units
end
local number = Utils.RandomInteger(1, #IdlingUnits[owner] + 1)
if IdlingUnits[owner][number] and not IdlingUnits[owner][number].IsDead then
units[i] = IdlingUnits[owner][number]
table.remove(IdlingUnits[owner], number)
end
end
return units
end
SendAttack = function(owner, size)
if Attacking[owner] then
return
end
Attacking[owner] = true
HoldProduction[owner] = true
local units = SetupAttackGroup(owner, size)
Utils.Do(units, IdleHunt)
Trigger.OnAllRemovedFromWorld(units, function()
Attacking[owner] = false
HoldProduction[owner] = false
end)
end
DefendActor = function(unit, defendingPlayer, defenderCount)
Trigger.OnDamaged(unit, function(self, attacker)
if unit.Owner ~= defendingPlayer then
return
end
-- Don't try to attack spiceblooms
if attacker and attacker.Type == "spicebloom" then
return
end
if Attacking[defendingPlayer] then
return
end
Attacking[defendingPlayer] = true
local Guards = SetupAttackGroup(defendingPlayer, defenderCount)
if #Guards <= 0 then
Attacking[defendingPlayer] = false
return
end
Utils.Do(Guards, function(unit)
if not self.IsDead then
unit.AttackMove(self.Location)
end
IdleHunt(unit)
end)
Trigger.OnAllRemovedFromWorld(Guards, function() Attacking[defendingPlayer] = false end)
end)
end
ProtectHarvester = function(unit, owner, defenderCount)
DefendActor(unit, owner, defenderCount)
-- Worms don't kill the actor, but dispose it instead.
-- If a worm kills the last harvester (hence we check for remaining ones),
-- a new harvester is delivered by the harvester insurance.
-- Otherwise, there's no need to check for new harvesters.
local killed = false
Trigger.OnKilled(unit, function()
killed = true
end)
Trigger.OnRemovedFromWorld(unit, function()
if not killed and #unit.Owner.GetActorsByType("harvester") == 0 then
LastHarvesterEaten[owner] = true
end
end)
end
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
DefendAndRepairBase = function(owner, baseBuildings, modifier, defenderCount)
Utils.Do(baseBuildings, function(actor)
if actor.IsDead then
return
end
DefendActor(actor, owner, defenderCount)
RepairBuilding(owner, actor, modifier)
end)
end
ProduceUnits = function(player, factory, delay, toBuild, attackSize, attackThresholdSize)
if factory.IsDead or factory.Owner ~= player then
return
end
if HoldProduction[player] then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceUnits(player, factory, delay, toBuild, attackSize, attackThresholdSize) end)
return
end
player.Build(toBuild(), function(unit)
IdlingUnits[player][#IdlingUnits[player] + 1] = unit[1]
Trigger.AfterDelay(delay(), function() ProduceUnits(player, factory, delay, toBuild, attackSize, attackThresholdSize) end)
if #IdlingUnits[player] >= attackThresholdSize then
SendAttack(player, attackSize)
end
end)
end