Add a global script for campaign missions in d2k
This commit is contained in:
@@ -100,6 +100,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Red Alert Lua scripts", "Re
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dune 2000 Lua scripts", "Dune 2000 Lua scripts", "{06B1AE07-DDB0-4287-8700-A8CD9A0E652E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
mods\d2k\bits\scripts\campaign-global.lua = mods\d2k\bits\scripts\campaign-global.lua
|
||||
mods\d2k\maps\atreides-01a\atreides01a.lua = mods\d2k\maps\atreides-01a\atreides01a.lua
|
||||
mods\d2k\maps\atreides-01b\atreides01b.lua = mods\d2k\maps\atreides-01b\atreides01b.lua
|
||||
mods\d2k\maps\atreides-02a\atreides02a-AI.lua = mods\d2k\maps\atreides-02a\atreides02a-AI.lua
|
||||
|
||||
192
mods/d2k/bits/scripts/campaign-global.lua
Normal file
192
mods/d2k/bits/scripts/campaign-global.lua
Normal file
@@ -0,0 +1,192 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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 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)
|
||||
Trigger.AfterDelay(delay, function()
|
||||
if customCondition and customCondition() then
|
||||
return
|
||||
end
|
||||
|
||||
currentWave = currentWave + 1
|
||||
if currentWave > totalWaves then
|
||||
return
|
||||
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 = { }
|
||||
HarvesterKilled = { }
|
||||
|
||||
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)
|
||||
|
||||
-- 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)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled[unit.Owner] = true 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)
|
||||
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.Minutes(1), 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
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenEntryWaypoints = { HarkonnenWaypoint1.Location, HarkonnenWaypoint2.Location, HarkonnenWaypoint3.Location, HarkonnenWaypoint4.Location }
|
||||
HarkonnenAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 1
|
||||
HarkonnenAttackWaves["normal"] = 5
|
||||
HarkonnenAttackWaves["hard"] = 12
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
AtreidesReinforcements = { "light_inf", "light_inf", "light_inf" }
|
||||
AtreidesEntryPath = { AtreidesWaypoint.Location, AtreidesRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if HarkonnenArrived and harkonnen.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Atreides")
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(AtreidesConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, AtreidesReinforcements, AtreidesEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = HarkonnenAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = HarkonnenAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = HarkonnenReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = HarkonnenReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(HarkonnenAttackDelay - DateTime.Seconds(2), HarkonnenAttackDelay)
|
||||
HarkonnenAttackDelay = HarkonnenAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if HarkonnenAttackDelay < 0 then HarkonnenAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides01a.lua
|
||||
Scripts: campaign-global.lua, atreides01a.lua
|
||||
MissionData:
|
||||
Briefing: Harvest Spice from the Imperial Basin. Construct a Spice Refinery and defend it against the Harkonnen troops scattered throughout the basin. You have been assigned only limited offensive forces - use them wisely.\n\nYou will have to learn the subtleties of mining as you go, but remember to build Silos to store the Spice. When you run out of storage space you can not gather more Spice. Also, any building without adequate concrete foundation will need immediate repair and be vulnerable to erosive damage from the harsh environment. Your greatest adversary may be the elements.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR01_E.VQA
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenEntryWaypoints = { HarkonnenWaypoint1.Location, HarkonnenWaypoint2.Location, HarkonnenWaypoint3.Location, HarkonnenWaypoint4.Location }
|
||||
HarkonnenAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 1
|
||||
HarkonnenAttackWaves["normal"] = 5
|
||||
HarkonnenAttackWaves["hard"] = 12
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
AtreidesReinforcements = { "light_inf", "light_inf", "light_inf", "light_inf" }
|
||||
AtreidesEntryPath = { AtreidesWaypoint.Location, AtreidesRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if HarkonnenArrived and harkonnen.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Atreides")
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(AtreidesConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, AtreidesReinforcements, AtreidesEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = HarkonnenAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = HarkonnenAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = HarkonnenReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = HarkonnenReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(HarkonnenAttackDelay - DateTime.Seconds(2), HarkonnenAttackDelay)
|
||||
HarkonnenAttackDelay = HarkonnenAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if HarkonnenAttackDelay < 0 then HarkonnenAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides01b.lua
|
||||
Scripts: campaign-global.lua, atreides01b.lua
|
||||
MissionData:
|
||||
Briefing: Harvest Spice from the Imperial Basin. Construct a Spice Refinery and defend it against the Harkonnen troops scattered throughout the basin. You have been assigned only limited offensive forces - use them wisely.\n\nYou will have to learn the subtleties of mining as you go, but remember to build Silos to store the Spice. When you run out of storage space you can not gather more Spice. Also, any building without adequate concrete foundation will need immediate repair and be vulnerable to erosive damage from the harsh environment. Your greatest adversary may be the elements.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR01_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -23,108 +23,12 @@ AttackDelays =
|
||||
|
||||
HarkonnenInfantryTypes = { "light_inf" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
IdlingUnits[harkonnen] = { }
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return HarkonnenInfantryTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
ProduceUnits(harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -9,35 +9,37 @@
|
||||
|
||||
HarkonnenBase = { HConyard, HPower1, HPower2, HBarracks }
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenAttackPaths =
|
||||
@@ -48,35 +50,19 @@ HarkonnenAttackPaths =
|
||||
{ HarkonnenEntry2.Location, HarkonnenRally4.Location }
|
||||
}
|
||||
|
||||
HarkonnenAttackDelay = { }
|
||||
HarkonnenAttackDelay["easy"] = DateTime.Minutes(5)
|
||||
HarkonnenAttackDelay["normal"] = DateTime.Minutes(2) + DateTime.Seconds(40)
|
||||
HarkonnenAttackDelay["hard"] = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
HarkonnenAttackDelay =
|
||||
{
|
||||
easy = DateTime.Minutes(5),
|
||||
normal = DateTime.Minutes(2) + DateTime.Seconds(40),
|
||||
hard = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
}
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 3
|
||||
HarkonnenAttackWaves["normal"] = 6
|
||||
HarkonnenAttackWaves["hard"] = 9
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 3,
|
||||
normal = 6,
|
||||
hard = 9
|
||||
}
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
@@ -93,7 +79,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
Camera.Position = AConyard.CenterPosition
|
||||
|
||||
@@ -101,33 +89,7 @@ WorldLoaded = function()
|
||||
Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenAttackPaths) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides02a.lua, atreides02a-AI.lua
|
||||
Scripts: campaign-global.lua, atreides02a.lua, atreides02a-AI.lua
|
||||
MissionData:
|
||||
Briefing: Infiltrate the Imperial Basin and build up our forces until they are strong enough to eradicate the local Harkonnen presence.\n\nThe Harkonnen are reinforcing their troops by air, so be on your guard. Use the Outpost's radar to detect attacks from unexpected quarters.\n\nBe careful when mining the Spice. Spice mounds grow out of the sand. While a vital source of Spice, Spice mounds can damage or destroy any unit that blunders into them.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR02_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -23,108 +23,12 @@ AttackDelays =
|
||||
|
||||
HarkonnenInfantryTypes = { "light_inf" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
IdlingUnits[harkonnen] = { }
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return HarkonnenInfantryTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
ProduceUnits(harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -9,35 +9,37 @@
|
||||
|
||||
HarkonnenBase = { HConyard, HOutpost, HBarracks }
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenAttackPaths =
|
||||
@@ -62,26 +64,6 @@ HarkonnenAttackWaves =
|
||||
hard = 9
|
||||
}
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
@@ -97,7 +79,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
Camera.Position = AConyard.CenterPosition
|
||||
|
||||
@@ -105,33 +89,7 @@ WorldLoaded = function()
|
||||
Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenAttackPaths) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides02b.lua, atreides02b-AI.lua
|
||||
Scripts: campaign-global.lua, atreides02b.lua, atreides02b-AI.lua
|
||||
MissionData:
|
||||
Briefing: Infiltrate the Imperial Basin and build up our forces until they are strong enough to eradicate the local Harkonnen presence.\n\nThe Harkonnen are reinforcing their troops by air, so be on your guard. Use the Outpost's radar to detect attacks from unexpected quarters.\n\nBe careful when mining the Spice. Spice mounds grow out of the sand. While a vital source of Spice, Spice mounds can damage or destroy any unit that blunders into them.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR02_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -24,148 +23,30 @@ AttackDelays =
|
||||
OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
OrdosVehicleTypes = { "raider", "raider", "quad" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(ordos, InitialOrdosReinforcements, OrdosPaths[2])
|
||||
IdlingUnits[#IdlingUnits + 1] = OTrooper1
|
||||
IdlingUnits[#IdlingUnits + 1] = OTrooper2
|
||||
IdlingUnits[#IdlingUnits + 1] = ORaider
|
||||
IdlingUnits[ordos] = Reinforcements.Reinforce(ordos, InitialOrdosReinforcements, OrdosPaths[2])
|
||||
IdlingUnits[ordos][#IdlingUnits + 1] = OTrooper1
|
||||
IdlingUnits[ordos][#IdlingUnits + 1] = OTrooper2
|
||||
IdlingUnits[ordos][#IdlingUnits + 1] = ORaider
|
||||
|
||||
Utils.Do(OrdosBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if OBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(OrdosInfantryTypes) }
|
||||
ordos.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if OLightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(OrdosVehicleTypes) }
|
||||
ordos.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(ordos, OrdosBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[ordos] = true
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
|
||||
OConyard.Produce(AtreidesUpgrades[1])
|
||||
OConyard.Produce(AtreidesUpgrades[2])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
|
||||
local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceUnits(ordos, OBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(ordos, OLightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
OrdosBase = { OBarracks, OWindTrap1, OWindTrap2, OWindTrap3, OWindTrap4, OLightFactory, OOutpost, OConyard, ORefinery, OSilo1, OSilo2, OSilo3, OSilo4 }
|
||||
|
||||
OrdosReinforcements =
|
||||
@@ -76,25 +77,6 @@ AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }
|
||||
AtreidesBaseBuildings = { "barracks", "light_factory" }
|
||||
AtreidesUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendOrdos = function()
|
||||
Trigger.AfterDelay(OrdosAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
if player.IsObjectiveCompleted(KillOrdos) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > OrdosAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local units = Reinforcements.ReinforceWithTransport(ordos, "carryall.reinforce", OrdosReinforcements[Map.LobbyOption("difficulty")][wave], OrdosPaths[1], { OrdosPaths[1][1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendOrdos()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(AtreidesBaseBuildings[index]) > 0 and not player.HasPrerequisites({ AtreidesUpgrades[index] })
|
||||
end
|
||||
@@ -109,16 +91,16 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillOrdos)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[ordos] then
|
||||
local units = ordos.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[ordos] = false
|
||||
ProtectHarvester(units[1], ordos, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -126,14 +108,19 @@ Tick = function()
|
||||
Media.DisplayMessage("Upgrade barracks and light factory to produce more advanced units.", "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
ordos = Player.GetPlayer("Ordos")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillAtreides = ordos.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillOrdos = player.AddSecondaryObjective("Eliminate all Ordos units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = AConyard.CenterPosition
|
||||
|
||||
@@ -141,38 +128,13 @@ WorldLoaded = function()
|
||||
Utils.Do(ordos.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendOrdos()
|
||||
local path = function() return OrdosPaths[1] end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillOrdos) end
|
||||
SendCarryallReinforcements(ordos, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition)
|
||||
ActivateAI()
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), function()
|
||||
Media.PlaySpeechNotification(player, "Reinforce")
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] })
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = ordos.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillOrdos = player.AddSecondaryObjective("Eliminate all Ordos units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides03a.lua, atreides03a-AI.lua
|
||||
Scripts: campaign-global.lua, atreides03a.lua, atreides03a-AI.lua
|
||||
MissionData:
|
||||
Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any agression with overwhelming force.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR03_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -24,117 +23,23 @@ AttackDelays =
|
||||
|
||||
OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Difficulty], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(ordos, InitialOrdosReinforcements, OrdosPaths[2])
|
||||
|
||||
Utils.Do(OrdosBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if OBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(OrdosInfantryTypes) }
|
||||
ordos.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
IdlingUnits[ordos] = Reinforcements.Reinforce(ordos, InitialOrdosReinforcements, OrdosPaths[2])
|
||||
DefendAndRepairBase(ordos, OrdosBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[ordos] = true
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
|
||||
OConyard.Produce(AtreidesUpgrades[1])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), ProduceInfantry)
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceUnits(ordos, OBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
OrdosBase = { OBarracks, OWindTrap1, OWindTrap2, OOutpost, OConyard, ORefinery, OSilo }
|
||||
|
||||
OrdosReinforcements =
|
||||
@@ -76,25 +77,6 @@ AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }
|
||||
AtreidesBaseBuildings = { "barracks", "light_factory" }
|
||||
AtreidesUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendOrdos = function()
|
||||
Trigger.AfterDelay(OrdosAttackDelay[Difficulty], function()
|
||||
if player.IsObjectiveCompleted(KillOrdos) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > OrdosAttackWaves[Difficulty] then
|
||||
return
|
||||
end
|
||||
|
||||
local units = Reinforcements.ReinforceWithTransport(ordos, "carryall.reinforce", OrdosReinforcements[Difficulty][wave], OrdosPaths[1], { OrdosPaths[1][1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendOrdos()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(AtreidesBaseBuildings[index]) > 0 and not player.HasPrerequisites({ AtreidesUpgrades[index] })
|
||||
end
|
||||
@@ -109,12 +91,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillOrdos)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[ordos] then
|
||||
local units = ordos.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[ordos] = false
|
||||
ProtectHarvester(units[1], ordos, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -133,10 +115,12 @@ WorldLoaded = function()
|
||||
ordos = Player.GetPlayer("Ordos")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
Difficulty = Map.LobbyOption("difficulty")
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = ordos.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillOrdos = player.AddSecondaryObjective("Eliminate all Ordos units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = AConyard.CenterPosition
|
||||
|
||||
@@ -144,38 +128,13 @@ WorldLoaded = function()
|
||||
Utils.Do(ordos.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendOrdos()
|
||||
local path = function() return OrdosPaths[1] end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillOrdos) end
|
||||
SendCarryallReinforcements(ordos, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition)
|
||||
ActivateAI()
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), function()
|
||||
Media.PlaySpeechNotification(player, "Reinforce")
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] })
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = ordos.AddPrimaryObjective("Kill all Atreides units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillOrdos = player.AddSecondaryObjective("Eliminate all Ordos units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides03b.lua, atreides03b-AI.lua
|
||||
Scripts: campaign-global.lua, atreides03b.lua, atreides03b-AI.lua
|
||||
MissionData:
|
||||
Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any agression with overwhelming force.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR03_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -25,37 +24,15 @@ AttackDelays =
|
||||
HarkonnenInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
|
||||
HarkonnenTankType = { "combat_tank_h" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Difficulty] do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
-- Overwrite the template function because of the message
|
||||
SendAttack = function(owner, size)
|
||||
if Attacking[owner] then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
Attacking[owner] = true
|
||||
HoldProduction[owner] = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
local units = SetupAttackGroup(owner, size)
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
if #units > 0 then
|
||||
@@ -63,107 +40,27 @@ SendAttack = function()
|
||||
end
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if Defending then
|
||||
return
|
||||
end
|
||||
Defending = true
|
||||
|
||||
-- Don't try to attack spiceblooms
|
||||
if attacker and attacker.Type == "spicebloom" then
|
||||
return
|
||||
end
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
Defending = 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() Defending = false end)
|
||||
Attacking[owner] = false
|
||||
HoldProduction[owner] = false
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(harkonnen, InitialHarkonnenReinforcements, HarkonnenPaths[1])
|
||||
IdlingUnits[harkonnen] = Reinforcements.Reinforce(harkonnen, InitialHarkonnenReinforcements, HarkonnenPaths[1])
|
||||
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Owner == harkonnen and building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HarkonnenBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
ProduceTanks = function()
|
||||
if HarkonnenHeavyFact.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceTanks)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
harkonnen.Build(HarkonnenTankType, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceTanks)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[harkonnen] = true
|
||||
InitAIUnits()
|
||||
FremenProduction()
|
||||
|
||||
ProduceInfantry()
|
||||
ProduceTanks()
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(HarkonnenInfantryTypes) } end
|
||||
local tanksToBuild = function() return HarkonnenTankType end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
ProduceUnits(harkonnen, HarkonnenBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(harkonnen, HarkonnenHeavyFact, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
HarkonnenBase = { HarkonnenOutpost, HarkonnenRefinery, HarkonnenHeavyFact, HarkonnenTurret1, HarkonnenTurret2, HarkonnenBarracks, HarkonnenSilo1, HarkonnenSilo2, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5 }
|
||||
|
||||
HarkonnenReinforcements =
|
||||
@@ -89,29 +90,6 @@ IntegrityLevel =
|
||||
hard = 100
|
||||
}
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty], function()
|
||||
if player.IsObjectiveCompleted(KillHarkonnen) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Difficulty] then
|
||||
return
|
||||
end
|
||||
|
||||
local entryPath = Utils.Random(HarkonnenPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Difficulty][wave], entryPath, { entryPath[1] })[2]
|
||||
Utils.Do(units, function(unit)
|
||||
unit.AttackMove(HarkonnenAttackLocation)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
FremenProduction = function()
|
||||
if Sietch.IsDead then
|
||||
return
|
||||
@@ -119,7 +97,7 @@ FremenProduction = function()
|
||||
|
||||
local delay = Utils.RandomInteger(FremenInterval[Difficulty][1], FremenInterval[Difficulty][2] + 1)
|
||||
fremen.Build({ "nsfremen" }, function()
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
Trigger.AfterDelay(delay, FremenProduction)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -136,12 +114,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KeepIntegrity)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[harkonnen] then
|
||||
local units = harkonnen.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[harkonnen] = false
|
||||
ProtectHarvester(units[1], harkonnen, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -161,9 +139,11 @@ WorldLoaded = function()
|
||||
fremen = Player.GetPlayer("Fremen")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
Difficulty = Map.LobbyOption("difficulty")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
ProtectFremen = player.AddPrimaryObjective("Protect the Fremen Sietch.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy the Harkonnen.")
|
||||
KeepIntegrity = player.AddSecondaryObjective("Keep the Sietch " .. IntegrityLevel[Difficulty] .. "% intact!")
|
||||
|
||||
Camera.Position = AConyard.CenterPosition
|
||||
HarkonnenAttackLocation = AConyard.Location
|
||||
@@ -196,7 +176,14 @@ WorldLoaded = function()
|
||||
end
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillHarkonnen) end
|
||||
local huntFunction = function(unit)
|
||||
unit.AttackMove(HarkonnenAttackLocation)
|
||||
IdleHunt(unit)
|
||||
end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty], waveCondition, huntFunction)
|
||||
|
||||
Actor.Create("upgrade.barracks", true, { Owner = harkonnen })
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
|
||||
@@ -217,32 +204,3 @@ WorldLoaded = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
ProtectFremen = player.AddPrimaryObjective("Protect the Fremen Sietch.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy the Harkonnen.")
|
||||
KeepIntegrity = player.AddSecondaryObjective("Keep the Sietch " .. IntegrityLevel[Difficulty] .. "% intact!")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides04.lua, atreides04-AI.lua
|
||||
Scripts: campaign-global.lua, atreides04.lua, atreides04-AI.lua
|
||||
MissionData:
|
||||
Briefing: Our scouts have discovered the hidden Fremen base. The Harkonnen blockade of the Fremen must be broken.\n\nPowerful Harkonnen forces to the South are massing for an assault on the Fremen. Heavy forces have been allocated to you to smash through the Harkonnen fortifications and come to the aid of the Fremen.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR04_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -18,114 +25,26 @@ HarkonnenInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "troo
|
||||
HarkonnenVehicleTypes = { "trike", "trike", "trike", "quad", "quad" }
|
||||
HarkonnenTankType = { "combat_tank_h" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Difficulty] do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
unit.AttackMove(HarkonnenAttackLocation)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if Defending then
|
||||
return
|
||||
end
|
||||
Defending = true
|
||||
|
||||
-- Don't try to attack spiceblooms
|
||||
if attacker and attacker.Type == "spicebloom" then
|
||||
return
|
||||
end
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
Defending = 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() Defending = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
RepairBuilding = function(owner, actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Owner == owner and building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", InitialHarkonnenReinforcements, HarkonnenPaths[1], { HarkonnenPaths[1][1] })[2]
|
||||
IdlingUnits[harkonnen] = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", InitialHarkonnenReinforcements, HarkonnenPaths[1], { HarkonnenPaths[1][1] })[2]
|
||||
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
RepairBuilding(harkonnen, actor)
|
||||
end)
|
||||
|
||||
DefendActor(HarkonnenBarracks)
|
||||
RepairBuilding(harkonnen, HarkonnenBarracks)
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
DefendActor(HarkonnenBarracks, harkonnen, AttackGroupSize[Difficulty])
|
||||
RepairBuilding(harkonnen, HarkonnenBarracks, 0.75)
|
||||
|
||||
Utils.Do(SmugglerBase, function(actor)
|
||||
RepairBuilding(smuggler, actor)
|
||||
RepairBuilding(smuggler, actor, 0.75)
|
||||
end)
|
||||
RepairBuilding(smuggler, Starport)
|
||||
RepairBuilding(smuggler, Starport, 0.75)
|
||||
end
|
||||
|
||||
-- Not using ProduceUnits because of the custom StopInfantryProduction condition
|
||||
ProduceInfantry = function()
|
||||
if StopInfantryProduction or HarkonnenBarracks.IsDead or HarkonnenBarracks.Owner ~= harkonnen then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
if HoldProduction[harkonnen] then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
@@ -133,63 +52,26 @@ ProduceInfantry = function()
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
IdlingUnits[harkonnen][#IdlingUnits[harkonnen] + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if HarkonnenLightFactory.IsDead or HarkonnenLightFactory.Owner ~= harkonnen then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenVehicleTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceTanks = function()
|
||||
if HarkonnenHeavyFactory.IsDead or HarkonnenHeavyFactory.Owner ~= harkonnen then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceTanks)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
harkonnen.Build(HarkonnenTankType, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceTanks)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
if #IdlingUnits[harkonnen] >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack(harkonnen, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
harkonnen.Cash = 15000
|
||||
HarvesterKilled[harkonnen] = true
|
||||
InitAIUnits()
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local vehilcesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end
|
||||
local tanksToBuild = function() return HarkonnenTankType end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceTanks()
|
||||
ProduceUnits(harkonnen, HarkonnenLightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(harkonnen, HarkonnenHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
HarkonnenBase = { HarkonnenConstructionYard, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5, HarkonnenWindTrap6, HarkonnenWindTrap7, HarkonnenWindTrap8, HarkonnenSilo1, HarkonnenSilo2, HarkonnenSilo3, HarkonnenSilo4, HarkonnenGunTurret1, HarkonnenGunTurret2, HarkonnenGunTurret3, HarkonnenGunTurret4, HarkonnenGunTurret5, HarkonnenGunTurret6, HarkonnenGunTurret7, HarkonnenHeavyFactory, HarkonnenRefinery, HarkonnenOutpost, HarkonnenLightFactory }
|
||||
SmugglerBase = { SmugglerWindTrap1, SmugglerWindTrap2 }
|
||||
|
||||
@@ -251,12 +260,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillSmuggler)
|
||||
end
|
||||
|
||||
if HarvesterKilled and DateTime.GameTime % DateTime.Seconds(30) then
|
||||
if HarvesterKilled[harkonnen] and DateTime.GameTime % DateTime.Seconds(30) then
|
||||
local units = harkonnen.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[harkonnen] = false
|
||||
ProtectHarvester(units[1], harkonnen, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -278,10 +287,13 @@ WorldLoaded = function()
|
||||
mercenary = Player.GetPlayer("Mercenaries")
|
||||
player = Player.GetPlayer("Atreides")
|
||||
|
||||
Difficulty = Map.LobbyOption("difficulty")
|
||||
InfantryReinforcements = Difficulty ~= "easy"
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
CaptureBarracks = player.AddPrimaryObjective("Capture the Barracks at Sietch Tabr.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Annihilate all other Harkonnen units\nand reinforcements.")
|
||||
CaptureStarport = player.AddSecondaryObjective("Capture the Smuggler Starport and\nconfiscate the contraband.")
|
||||
|
||||
Camera.Position = ARefinery.CenterPosition
|
||||
HarkonnenAttackLocation = AtreidesRally.Location
|
||||
@@ -412,32 +424,3 @@ WorldLoaded = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Atreides units.")
|
||||
CaptureBarracks = player.AddPrimaryObjective("Capture the Barracks at Sietch Tabr.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Annihilate all other Harkonnen units\nand reinforcements.")
|
||||
CaptureStarport = player.AddSecondaryObjective("Capture the Smuggler Starport and\nconfiscate the contraband.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: atreides05.lua, atreides05-AI.lua
|
||||
Scripts: campaign-global.lua, atreides05.lua, atreides05-AI.lua
|
||||
MissionData:
|
||||
Briefing: According to our spies, the Fremen are being held at the far Northwest corner of Sietch Tabr. Push your way through the Harkonnen ranks to rescue the hostages.\n\nScout the terrain before you launch the main assault. Our Engineers must reach the Barracks and capture it intact. The rest of the base can be razed to the ground.\n\nAdditionally, there are rumors of an illegal Smuggling operation in the area. A large shipment of contraband is expected at the Smuggler's Starport. If you can the Starport before the contraband arrives, you will be able to confiscate it for the Atreides war effort.\n\nBe warned, the Smugglers have Mercenary allies who may assist them if you interfere.\n\nGood luck.\n
|
||||
BriefingVideo: A_BR05_E.VQA
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
AtreidesReinforcements = { }
|
||||
AtreidesReinforcements["easy"] =
|
||||
AtreidesReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location }
|
||||
AtreidesAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
AtreidesAttackWaves = { }
|
||||
AtreidesAttackWaves["easy"] = 1
|
||||
AtreidesAttackWaves["normal"] = 5
|
||||
AtreidesAttackWaves["hard"] = 12
|
||||
AtreidesAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" }
|
||||
HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if AtreidesArrived and atreides.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillAtreides)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillAtreides = player.AddSecondaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(HarkonnenConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, HarkonnenReinforcements, HarkonnenEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = AtreidesAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = AtreidesAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = AtreidesReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = AtreidesReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(AtreidesAttackDelay - DateTime.Seconds(2), AtreidesAttackDelay)
|
||||
AtreidesAttackDelay = AtreidesAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if AtreidesAttackDelay < 0 then AtreidesAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillAtreides = player.AddSecondaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen01a.lua
|
||||
Scripts: campaign-global.lua, harkonnen01a.lua
|
||||
MissionData:
|
||||
Briefing: Mine the Spice from the Imperial Basin, before the Atreides try to seize the area. Execute anyone who tries to stop you.\n\nBuild Silos to store the Spice. Remember to place buildings on concrete foundations to prevent erosion and gradual decline. To build without concrete would be inefficient. Inefficiency will not be tolerated.\n
|
||||
BriefingVideo: H_BR01_E.VQA
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
AtreidesReinforcements = { }
|
||||
AtreidesReinforcements["easy"] =
|
||||
AtreidesReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location }
|
||||
AtreidesAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
AtreidesAttackWaves = { }
|
||||
AtreidesAttackWaves["easy"] = 1
|
||||
AtreidesAttackWaves["normal"] = 5
|
||||
AtreidesAttackWaves["hard"] = 12
|
||||
AtreidesAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" }
|
||||
HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if AtreidesArrived and atreides.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillAtreides)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillAtreides = player.AddSecondaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(HarkonnenConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, HarkonnenReinforcements, HarkonnenEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = AtreidesAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = AtreidesAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = AtreidesReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = AtreidesReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(AtreidesAttackDelay - DateTime.Seconds(2), AtreidesAttackDelay)
|
||||
AtreidesAttackDelay = AtreidesAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if AtreidesAttackDelay < 0 then AtreidesAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillAtreides = player.AddSecondaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen01b.lua
|
||||
Scripts: campaign-global.lua, harkonnen01b.lua
|
||||
MissionData:
|
||||
Briefing: Mine the Spice from the Imperial Basin, before the Atreides try to seize the area. Execute anyone who tries to stop you.\n\nBuild Silos to store the Spice. Remember to place buildings on concrete foundations to prevent erosion and gradual decline. To build without concrete would be inefficient. Inefficiency will not be tolerated.\n
|
||||
BriefingVideo: H_BR01_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -23,108 +23,12 @@ AttackDelays =
|
||||
|
||||
AtreidesInfantryTypes = { "light_inf" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(AtreidesBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if ABarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesInfantryTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
IdlingUnits[atreides] = { }
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return AtreidesInfantryTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
DefendAndRepairBase(atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
|
||||
ProduceUnits(atreides, ABarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -9,35 +9,37 @@
|
||||
|
||||
AtreidesBase = { AConyard, APower1, APower2, ABarracks, AOutpost }
|
||||
|
||||
AtreidesReinforcements = { }
|
||||
AtreidesReinforcements["easy"] =
|
||||
AtreidesReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
AtreidesAttackPaths =
|
||||
@@ -48,35 +50,19 @@ AtreidesAttackPaths =
|
||||
{ AtreidesEntry2.Location, AtreidesRally3.Location }
|
||||
}
|
||||
|
||||
AtreidesAttackDelay = { }
|
||||
AtreidesAttackDelay["easy"] = DateTime.Minutes(5)
|
||||
AtreidesAttackDelay["normal"] = DateTime.Minutes(2) + DateTime.Seconds(40)
|
||||
AtreidesAttackDelay["hard"] = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
AtreidesAttackDelay =
|
||||
{
|
||||
easy = DateTime.Minutes(5),
|
||||
normal = DateTime.Minutes(2) + DateTime.Seconds(40),
|
||||
hard = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
}
|
||||
|
||||
AtreidesAttackWaves = { }
|
||||
AtreidesAttackWaves["easy"] = 3
|
||||
AtreidesAttackWaves["normal"] = 6
|
||||
AtreidesAttackWaves["hard"] = 9
|
||||
|
||||
wave = 0
|
||||
SendAtreides = function()
|
||||
Trigger.AfterDelay(AtreidesAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > AtreidesAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(AtreidesAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", AtreidesReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendAtreides()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
AtreidesAttackWaves =
|
||||
{
|
||||
easy = 3,
|
||||
normal = 6,
|
||||
hard = 9
|
||||
}
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
@@ -93,7 +79,9 @@ WorldLoaded = function()
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy all Atreides forces.")
|
||||
|
||||
Camera.Position = HConyard.CenterPosition
|
||||
|
||||
@@ -101,33 +89,7 @@ WorldLoaded = function()
|
||||
Utils.Do(atreides.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendAtreides()
|
||||
local path = function() return Utils.Random(AtreidesAttackPaths) end
|
||||
SendCarryallReinforcements(atreides, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy all Atreides forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen02a.lua, harkonnen02a-AI.lua
|
||||
Scripts: campaign-global.lua, harkonnen02a.lua, harkonnen02a-AI.lua
|
||||
MissionData:
|
||||
Briefing: Strengthen your forces at our mining camp in the Imperial Basin. We must punish the Atreides for their insolence. Teach them the consequences of opposing House Harkonnen.\n\nOur radar will help you find your targets.\n
|
||||
BriefingVideo: H_BR02_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -24,131 +24,14 @@ AttackDelays =
|
||||
AtreidesInfantryTypes = { "light_inf" }
|
||||
AtreidesVehicleTypes = { "trike" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(AtreidesBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if ABarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesInfantryTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if ALightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesVehicleTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
IdlingUnits[atreides] = { }
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return AtreidesInfantryTypes end
|
||||
local vehilcesToBuild = function() return AtreidesVehicleTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
DefendAndRepairBase(atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
|
||||
ProduceUnits(atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -9,35 +9,37 @@
|
||||
|
||||
AtreidesBase = { AConyard, APower1, APower2, ABarracks, ALightFactory }
|
||||
|
||||
AtreidesReinforcements = { }
|
||||
AtreidesReinforcements["easy"] =
|
||||
AtreidesReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
AtreidesReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
AtreidesAttackPaths =
|
||||
@@ -48,35 +50,19 @@ AtreidesAttackPaths =
|
||||
{ AtreidesEntry2.Location, AtreidesRally3.Location }
|
||||
}
|
||||
|
||||
AtreidesAttackDelay = { }
|
||||
AtreidesAttackDelay["easy"] = DateTime.Minutes(5)
|
||||
AtreidesAttackDelay["normal"] = DateTime.Minutes(2) + DateTime.Seconds(40)
|
||||
AtreidesAttackDelay["hard"] = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
AtreidesAttackDelay =
|
||||
{
|
||||
easy = DateTime.Minutes(5),
|
||||
normal = DateTime.Minutes(2) + DateTime.Seconds(40),
|
||||
hard = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
}
|
||||
|
||||
AtreidesAttackWaves = { }
|
||||
AtreidesAttackWaves["easy"] = 3
|
||||
AtreidesAttackWaves["normal"] = 6
|
||||
AtreidesAttackWaves["hard"] = 9
|
||||
|
||||
wave = 0
|
||||
SendAtreides = function()
|
||||
Trigger.AfterDelay(AtreidesAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > AtreidesAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(AtreidesAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", AtreidesReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendAtreides()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
AtreidesAttackWaves =
|
||||
{
|
||||
easy = 3,
|
||||
normal = 6,
|
||||
hard = 9
|
||||
}
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
@@ -93,7 +79,9 @@ WorldLoaded = function()
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy all Atreides forces.")
|
||||
|
||||
Camera.Position = HConyard.CenterPosition
|
||||
|
||||
@@ -101,33 +89,7 @@ WorldLoaded = function()
|
||||
Utils.Do(atreides.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendAtreides()
|
||||
local path = function() return Utils.Random(AtreidesAttackPaths) end
|
||||
SendCarryallReinforcements(atreides, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy all Atreides forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen02b.lua, harkonnen02b-AI.lua
|
||||
Scripts: campaign-global.lua, harkonnen02b.lua, harkonnen02b-AI.lua
|
||||
MissionData:
|
||||
Briefing: Strengthen your forces at our mining camp in the Imperial Basin. We must punish the Atreides for their insolence. Teach them the consequences of opposing House Harkonnen.\n\nOur radar will help you find your targets.\n
|
||||
BriefingVideo: H_BR02_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -17,141 +24,22 @@ AttackDelays =
|
||||
AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
AtreidesVehicleTypes = { "trike", "trike", "quad" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if IsAttacking then
|
||||
return
|
||||
end
|
||||
IsAttacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
IsAttacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(AtreidesBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if ABarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesInfantryTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if ALightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesVehicleTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
IdlingUnits[atreides] = { }
|
||||
HarvesterKilled[atreides] = true
|
||||
DefendAndRepairBase(atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
|
||||
|
||||
AConyard.Produce(HarkonnenUpgrades[1])
|
||||
AConyard.Produce(HarkonnenUpgrades[2])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
|
||||
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceUnits(atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, ALightFactory, AOutpost, AConyard, ARefinery, ASilo }
|
||||
AtreidesBaseAreaTriggers =
|
||||
{
|
||||
@@ -84,40 +93,10 @@ HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
|
||||
HarkonnenBaseBuildings = { "barracks", "light_factory" }
|
||||
HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendAtreides = function()
|
||||
Trigger.AfterDelay(AtreidesAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
if player.IsObjectiveCompleted(KillAtreides) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > AtreidesAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(AtreidesPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", AtreidesReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendAtreides()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(HarkonnenBaseBuildings[index]) > 0 and not player.HasPrerequisites({ HarkonnenUpgrades[index] })
|
||||
end
|
||||
|
||||
SendHunters = function(areaTrigger, unit, path, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
atreides.MarkCompletedObjective(KillHarkonnen)
|
||||
@@ -128,12 +107,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillAtreides)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[atreides] then
|
||||
local units = atreides.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[atreides] = false
|
||||
ProtectHarvester(units[1], atreides, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -146,7 +125,9 @@ WorldLoaded = function()
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = HConyard.CenterPosition
|
||||
|
||||
@@ -154,43 +135,18 @@ WorldLoaded = function()
|
||||
Utils.Do(atreides.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendAtreides()
|
||||
ActivateAI()
|
||||
local path = function() return Utils.Random(AtreidesPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillAtreides) end
|
||||
SendCarryallReinforcements(atreides, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition)
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", HarkonnenReinforcements, HarkonnenPath, { HarkonnenPath[1] })
|
||||
end)
|
||||
|
||||
SendHunters(AtreidesBaseAreaTriggers[1], AtreidesHunters[1], AtreidesHunterPaths[1], HuntersSent1)
|
||||
SendHunters(AtreidesBaseAreaTriggers[1], AtreidesHunters[2], AtreidesHunterPaths[2], HuntersSent2)
|
||||
SendHunters(AtreidesBaseAreaTriggers[2], AtreidesHunters[3], AtreidesHunterPaths[3], HuntersSent3)
|
||||
SendHunters(AtreidesBaseAreaTriggers[2], AtreidesHunters[4], AtreidesHunterPaths[4], HuntersSent4)
|
||||
SendHunters(AtreidesBaseAreaTriggers[3], AtreidesHunters[5], AtreidesHunterPaths[5], HuntersSent5)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
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)
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[1], AtreidesHunters[1], AtreidesHunterPaths[1])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[1], AtreidesHunters[2], AtreidesHunterPaths[2])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[2], AtreidesHunters[3], AtreidesHunterPaths[3])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[2], AtreidesHunters[4], AtreidesHunterPaths[4])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[3], AtreidesHunters[5], AtreidesHunterPaths[5])
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen03a.lua, harkonnen03a-AI.lua
|
||||
Scripts: campaign-global.lua, harkonnen03a.lua, harkonnen03a-AI.lua
|
||||
MissionData:
|
||||
Briefing: Attack and destroy the Atreides base at Sietch Tabr. Strike hard and eliminate all resistance.\n\nHeavier Quad vehicles will be made available for your attack. Upgrade your Light Factory to gain access to these vehicles.\n
|
||||
BriefingVideo: H_BR03_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -17,143 +24,27 @@ AttackDelays =
|
||||
AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
AtreidesVehicleTypes = { "trike", "trike", "quad" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if IsAttacking then
|
||||
return
|
||||
end
|
||||
IsAttacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
IsAttacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(atreides, AtreidesInitialReinforcements, AtreidesInitialPath)
|
||||
IdlingUnits[atreides] = Reinforcements.Reinforce(atreides, AtreidesInitialReinforcements, AtreidesInitialPath)
|
||||
|
||||
Utils.Do(AtreidesBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if ABarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesInfantryTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if ALightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesVehicleTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[atreides] = true
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
|
||||
AConyard.Produce(HarkonnenUpgrades[1])
|
||||
AConyard.Produce(HarkonnenUpgrades[2])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
|
||||
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceUnits(atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, AWindTrap3, ALightFactory, AOutpost, AConyard, ARefinery, ASilo1, ASilo2, ASilo3, ASilo4 }
|
||||
AtreidesBaseAreaTriggers =
|
||||
{
|
||||
@@ -86,40 +95,10 @@ HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
|
||||
HarkonnenBaseBuildings = { "barracks", "light_factory" }
|
||||
HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendAtreides = function()
|
||||
Trigger.AfterDelay(AtreidesAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
if player.IsObjectiveCompleted(KillAtreides) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > AtreidesAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(AtreidesPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", AtreidesReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendAtreides()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(HarkonnenBaseBuildings[index]) > 0 and not player.HasPrerequisites({ HarkonnenUpgrades[index] })
|
||||
end
|
||||
|
||||
SendHunters = function(areaTrigger, unit, path, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(atreides, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
atreides.MarkCompletedObjective(KillHarkonnen)
|
||||
@@ -130,12 +109,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillAtreides)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[atreides] then
|
||||
local units = atreides.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[atreides] = false
|
||||
ProtectHarvester(units[1], atreides, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -148,7 +127,9 @@ WorldLoaded = function()
|
||||
atreides = Player.GetPlayer("Atreides")
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = HConyard.CenterPosition
|
||||
|
||||
@@ -156,42 +137,17 @@ WorldLoaded = function()
|
||||
Utils.Do(atreides.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendAtreides()
|
||||
local path = function() return Utils.Random(AtreidesPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillAtreides) end
|
||||
SendCarryallReinforcements(atreides, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition)
|
||||
ActivateAI()
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", HarkonnenReinforcements, HarkonnenPath, { HarkonnenPath[1] })
|
||||
end)
|
||||
|
||||
SendHunters(AtreidesBaseAreaTriggers[1], AtreidesHunters[1], AtreidesHunterPaths[1], HuntersSent1)
|
||||
SendHunters(AtreidesBaseAreaTriggers[2], AtreidesHunters[2], AtreidesHunterPaths[2], HuntersSent2)
|
||||
SendHunters(AtreidesBaseAreaTriggers[3], AtreidesHunters[3], AtreidesHunterPaths[3], HuntersSent3)
|
||||
SendHunters(AtreidesBaseAreaTriggers[4], AtreidesHunters[4], AtreidesHunterPaths[4], HuntersSent4)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
KillAtreides = player.AddPrimaryObjective("Eliminate all Atreides units and reinforcements\nin the area.")
|
||||
|
||||
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)
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[1], AtreidesHunters[1], AtreidesHunterPaths[1])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[2], AtreidesHunters[2], AtreidesHunterPaths[2])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[3], AtreidesHunters[3], AtreidesHunterPaths[3])
|
||||
TriggerCarryallReinforcements(player, atreides, AtreidesBaseAreaTriggers[4], AtreidesHunters[4], AtreidesHunterPaths[4])
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen03b.lua, harkonnen03b-AI.lua
|
||||
Scripts: campaign-global.lua, harkonnen03b.lua, harkonnen03b-AI.lua
|
||||
MissionData:
|
||||
Briefing: Attack and destroy the Atreides base at Sietch Tabr. Strike hard and eliminate all resistance.\n\nHeavier Quad vehicles will be made available for your attack. Upgrade your Light Factory to gain access to these vehicles.\n
|
||||
BriefingVideo: H_BR03_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -18,168 +25,21 @@ AtreidesInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "troop
|
||||
AtreidesVehicleTypes = { "trike", "trike", "quad" }
|
||||
AtreidesTankType = { "combat_tank_a" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Difficulty] do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if Defending then
|
||||
return
|
||||
end
|
||||
Defending = true
|
||||
|
||||
-- Don't try to attack spiceblooms
|
||||
if attacker and attacker.Type == "spicebloom" then
|
||||
return
|
||||
end
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
Defending = 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() Defending = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(atreides, InitialAtreidesReinforcements[1], AtreidesPaths[2]), Reinforcements.Reinforce(atreides, InitialAtreidesReinforcements[2], AtreidesPaths[3])
|
||||
end
|
||||
|
||||
RepairBase = function(house)
|
||||
Utils.Do(Base[house.Name], function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Owner == house and building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if ABarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesInfantryTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if ALightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(AtreidesVehicleTypes) }
|
||||
atreides.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceTanks = function()
|
||||
if AHeavyFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), ProduceTanks)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
atreides.Build(AtreidesTankType, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceTanks)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
IdlingUnits[fremen] = { }
|
||||
IdlingUnits[atreides] = Reinforcements.Reinforce(atreides, InitialAtreidesReinforcements[1], AtreidesPaths[2]), Reinforcements.Reinforce(atreides, InitialAtreidesReinforcements[2], AtreidesPaths[3])
|
||||
FremenProduction()
|
||||
|
||||
RepairBase(atreides)
|
||||
RepairBase(fremen)
|
||||
DefendAndRepairBase(atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
|
||||
DefendAndRepairBase(fremen, FremenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceTanks()
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
|
||||
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
|
||||
local tanksToBuild = function() return AtreidesTankType end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
ProduceUnits(atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(atreides, AHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
Base =
|
||||
{
|
||||
Atreides = { AConyard, AOutpost, ARefinery, AHeavyFactory, ALightFactory, AGunt1, AGunt2, ABarracks, ASilo, APower1, APower2, APower3, APower4, APower5, APower6 },
|
||||
Fremen = { FGunt1, FGunt2 }
|
||||
}
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AtreidesBase = { AConyard, AOutpost, ARefinery, AHeavyFactory, ALightFactory, AGunt1, AGunt2, ABarracks, ASilo, APower1, APower2, APower3, APower4, APower5, APower6 }
|
||||
FremenBase = { FGunt1, FGunt2 }
|
||||
|
||||
BaseAreaTriggers =
|
||||
{
|
||||
@@ -110,55 +116,14 @@ FremenInterval =
|
||||
hard = { DateTime.Minutes(3) + DateTime.Seconds(40), DateTime.Minutes(4) }
|
||||
}
|
||||
|
||||
wave = 0
|
||||
SendFremen = function()
|
||||
Trigger.AfterDelay(FremenAttackDelay[Difficulty], function()
|
||||
if player.IsObjectiveCompleted(KillFremen) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > FremenAttackWaves[Difficulty] then
|
||||
return
|
||||
end
|
||||
|
||||
local entryPath = Utils.Random(FremenPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(fremen, "carryall.reinforce", FremenReinforcements[Difficulty][wave], entryPath, { entryPath[1] })[2]
|
||||
Utils.Do(units, function(unit)
|
||||
unit.AttackMove(FremenAttackLocation)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
SendFremen()
|
||||
end)
|
||||
end
|
||||
|
||||
SendHunters = function(areaTrigger, unit, path, house, objective, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if player.IsObjectiveCompleted(objective) then
|
||||
return
|
||||
end
|
||||
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(house, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
FremenProduction = function()
|
||||
Trigger.OnAllKilled(Sietches, function()
|
||||
SietchesAreDestroyed = true
|
||||
end)
|
||||
|
||||
if SietchesAreDestroyed then
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(FremenInterval[Difficulty][1], FremenInterval[Difficulty][2] + 1)
|
||||
fremen.Build({ "nsfremen" }, function()
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
Trigger.AfterDelay(delay, FremenProduction)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -177,12 +142,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillFremen)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[atreides] then
|
||||
local units = atreides.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[atreides] = false
|
||||
ProtectHarvester(units[1], atreides, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -192,18 +157,30 @@ WorldLoaded = function()
|
||||
fremen = Player.GetPlayer("Fremen")
|
||||
player = Player.GetPlayer("Harkonnen")
|
||||
|
||||
Difficulty = Map.LobbyOption("difficulty")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy the Atreiedes.")
|
||||
KillFremen = player.AddPrimaryObjective("Destroy the Fremen.")
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
|
||||
Camera.Position = HConyard.CenterPosition
|
||||
FremenAttackLocation = HConyard.Location
|
||||
|
||||
Trigger.OnAllKilledOrCaptured(Base[atreides.Name], function()
|
||||
Trigger.OnAllKilledOrCaptured(AtreidesBase, function()
|
||||
Utils.Do(atreides.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendFremen()
|
||||
Trigger.OnAllKilled(Sietches, function()
|
||||
SietchesAreDestroyed = true
|
||||
end)
|
||||
|
||||
local path = function() return Utils.Random(FremenPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillFremen) end
|
||||
local huntFunction = function(unit)
|
||||
unit.AttackMove(FremenAttackLocation)
|
||||
IdleHunt(unit)
|
||||
end
|
||||
SendCarryallReinforcements(fremen, 0, FremenAttackWaves[Difficulty], FremenAttackDelay[Difficulty], path, FremenReinforcements[Difficulty], waveCondition, huntFunction)
|
||||
|
||||
Actor.Create("upgrade.barracks", true, { Owner = atreides })
|
||||
Actor.Create("upgrade.light", true, { Owner = atreides })
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
@@ -217,36 +194,11 @@ WorldLoaded = function()
|
||||
Media.DisplayMessage("Fremen concentrations spotted to the North and Southwest.", "Mentat")
|
||||
end)
|
||||
|
||||
SendHunters(BaseAreaTriggers[1], AtreidesHunters, AtreidesPaths[1], atreides, KillAtreides, HuntersSent1)
|
||||
SendHunters(BaseAreaTriggers[1], FremenHunters[1], FremenHunterPaths[3], fremen, KillFremen, HuntersSent2)
|
||||
SendHunters(BaseAreaTriggers[2], FremenHunters[2], FremenHunterPaths[2], fremen, KillFremen, HuntersSent3)
|
||||
SendHunters(BaseAreaTriggers[3], FremenHunters[3], FremenHunterPaths[1], fremen, KillFremen, HuntersSent4)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = player.AddPrimaryObjective("Destroy the Atreiedes.")
|
||||
KillFremen = player.AddPrimaryObjective("Destroy the Fremen.")
|
||||
KillHarkonnen = atreides.AddPrimaryObjective("Kill all Harkonnen units.")
|
||||
|
||||
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)
|
||||
local atreidesCondition = function() return player.IsObjectiveCompleted(KillAtreides) end
|
||||
TriggerCarryallReinforcements(player, atreides, BaseAreaTriggers[1], AtreidesHunters, AtreidesPaths[1], atreidesCondition)
|
||||
|
||||
local fremenCondition = function() return player.IsObjectiveCompleted(KillFremen) end
|
||||
TriggerCarryallReinforcements(player, fremen, BaseAreaTriggers[1], FremenHunters[1], FremenHunterPaths[3], fremenCondition)
|
||||
TriggerCarryallReinforcements(player, fremen, BaseAreaTriggers[2], FremenHunters[2], FremenHunterPaths[2], fremenCondition)
|
||||
TriggerCarryallReinforcements(player, fremen, BaseAreaTriggers[3], FremenHunters[3], FremenHunterPaths[1], fremenCondition)
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: harkonnen04.lua, harkonnen04-AI.lua
|
||||
Scripts: campaign-global.lua, harkonnen04.lua, harkonnen04-AI.lua
|
||||
MissionData:
|
||||
Briefing: The native Fremen must be dealt with. Assemble a strike force to lead a sweep through the mountains. Seek out the Fremen hold, and destroy it. If any House responds, destroy it.\n\nTanks have been deployed to grind the Fremen beneath their treads. Demonstrate the power of House Harkonnen.
|
||||
BriefingVideo: H_BR04_E.VQA
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenEntryWaypoints = { HarkonnenWaypoint1.Location, HarkonnenWaypoint2.Location, HarkonnenWaypoint3.Location }
|
||||
HarkonnenAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 1
|
||||
HarkonnenAttackWaves["normal"] = 5
|
||||
HarkonnenAttackWaves["hard"] = 12
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
OrdosReinforcements = { "light_inf", "light_inf", "light_inf", "light_inf", "raider" }
|
||||
OrdosEntryPath = { OrdosWaypoint.Location, OrdosRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if HarkonnenArrived and harkonnen.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Ordos")
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(OrdosConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, OrdosReinforcements, OrdosEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = HarkonnenAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = HarkonnenAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = HarkonnenReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = HarkonnenReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(HarkonnenAttackDelay - DateTime.Seconds(2), HarkonnenAttackDelay)
|
||||
HarkonnenAttackDelay = HarkonnenAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if HarkonnenAttackDelay < 0 then HarkonnenAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos01a.lua
|
||||
Scripts: campaign-global.lua, ordos01a.lua
|
||||
MissionData:
|
||||
Briefing: Spice is wealth. Serve the Ordos by harvesting Spice in the Imperial Basin. If Harkonnen forces attempt to interrupt the flow of the Spice - neutralize them.\n\nEfficiency dictates that Silos must be built to avoid loss of Spice. Build concrete foundations to avoid unnecessary damage from the elements. To do otherwise is wasteful.
|
||||
BriefingVideo: O_BR01_E.VQA
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "light_inf" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenEntryWaypoints = { HarkonnenWaypoint1.Location, HarkonnenWaypoint2.Location, HarkonnenWaypoint3.Location, HarkonnenWaypoint4.Location }
|
||||
HarkonnenAttackDelay = DateTime.Seconds(30)
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 1
|
||||
HarkonnenAttackWaves["normal"] = 5
|
||||
HarkonnenAttackWaves["hard"] = 12
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 1,
|
||||
normal = 5,
|
||||
hard = 12
|
||||
}
|
||||
|
||||
ToHarvest = { }
|
||||
ToHarvest["easy"] = 2500
|
||||
ToHarvest["normal"] = 3000
|
||||
ToHarvest["hard"] = 3500
|
||||
ToHarvest =
|
||||
{
|
||||
easy = 2500,
|
||||
normal = 3000,
|
||||
hard = 3500
|
||||
}
|
||||
|
||||
OrdosReinforcements = { "light_inf", "light_inf", "light_inf", "light_inf", "raider" }
|
||||
OrdosEntryPath = { OrdosWaypoint.Location, OrdosRally.Location }
|
||||
@@ -53,19 +59,12 @@ Messages =
|
||||
"Build a Silo to store additional Spice."
|
||||
}
|
||||
|
||||
|
||||
IdleHunt = function(actor)
|
||||
if not actor.IsDead then
|
||||
Trigger.OnIdle(actor, actor.Hunt)
|
||||
end
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if HarkonnenArrived and harkonnen.HasNoRequiredUnits() then
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if player.Resources > ToHarvest[Map.LobbyOption("difficulty")] - 1 then
|
||||
if player.Resources > SpiceToHarvest - 1 then
|
||||
player.MarkCompletedObjective(GatherSpice)
|
||||
end
|
||||
|
||||
@@ -86,14 +85,19 @@ Tick = function()
|
||||
Media.DisplayMessage(Messages[4], "Mentat")
|
||||
end
|
||||
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. ToHarvest[Map.LobbyOption("difficulty")], player.Color)
|
||||
UserInterface.SetMissionText("Harvested resources: " .. player.Resources .. "/" .. SpiceToHarvest, player.Color)
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
player = Player.GetPlayer("Ordos")
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
|
||||
InitObjectives()
|
||||
SpiceToHarvest = ToHarvest[Difficulty]
|
||||
|
||||
InitObjectives(player)
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(SpiceToHarvest) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Trigger.OnRemovedFromWorld(OrdosConyard, function()
|
||||
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" end)
|
||||
@@ -114,12 +118,12 @@ WorldLoaded = function()
|
||||
Reinforcements.Reinforce(player, OrdosReinforcements, OrdosEntryPath)
|
||||
end)
|
||||
|
||||
WavesLeft = HarkonnenAttackWaves[Map.LobbyOption("difficulty")]
|
||||
WavesLeft = HarkonnenAttackWaves[Difficulty]
|
||||
SendReinforcements()
|
||||
end
|
||||
|
||||
SendReinforcements = function()
|
||||
local units = HarkonnenReinforcements[Map.LobbyOption("difficulty")]
|
||||
local units = HarkonnenReinforcements[Difficulty]
|
||||
local delay = Utils.RandomInteger(HarkonnenAttackDelay - DateTime.Seconds(2), HarkonnenAttackDelay)
|
||||
HarkonnenAttackDelay = HarkonnenAttackDelay - (#units * 3 - 3 - WavesLeft) * DateTime.Seconds(1)
|
||||
if HarkonnenAttackDelay < 0 then HarkonnenAttackDelay = 0 end
|
||||
@@ -135,31 +139,3 @@ SendReinforcements = function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillAtreides = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
GatherSpice = player.AddPrimaryObjective("Harvest " .. tostring(ToHarvest[Map.LobbyOption("difficulty")]) .. " Solaris worth of Spice.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos01b.lua
|
||||
Scripts: campaign-global.lua, ordos01b.lua
|
||||
MissionData:
|
||||
Briefing: Spice is wealth. Serve the Ordos by harvesting Spice in the Imperial Basin. If Harkonnen forces attempt to interrupt the flow of the Spice - neutralize them.\n\nEfficiency dictates that Silos must be built to avoid loss of Spice. Build concrete foundations to avoid unnecessary damage from the elements. To do otherwise is wasteful.
|
||||
BriefingVideo: O_BR01_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -23,108 +23,12 @@ AttackDelays =
|
||||
|
||||
HarkonnenInfantryTypes = { "light_inf" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
IdlingUnits[harkonnen] = { }
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return HarkonnenInfantryTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
ProduceUnits(harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -10,35 +10,37 @@
|
||||
HarkonnenBase = { HConyard, HPower1, HPower2, HBarracks, HOutpost }
|
||||
HarkonnenBaseAreaTrigger = { CPos.New(31, 37), CPos.New(32, 37), CPos.New(33, 37), CPos.New(34, 37), CPos.New(35, 37), CPos.New(36, 37), CPos.New(37, 37), CPos.New(38, 37), CPos.New(39, 37), CPos.New(40, 37), CPos.New(41, 37), CPos.New(42, 37), CPos.New(42, 38), CPos.New(42, 39), CPos.New(42, 40), CPos.New(42, 41), CPos.New(42, 42), CPos.New(42, 43), CPos.New(42, 44), CPos.New(42, 45), CPos.New(42, 46), CPos.New(42, 47), CPos.New(42, 48), CPos.New(42, 49) }
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenAttackPaths =
|
||||
@@ -61,49 +63,23 @@ InitialHarkonnenReinforcements =
|
||||
{ "light_inf", "light_inf" }
|
||||
}
|
||||
|
||||
HarkonnenAttackDelay = { }
|
||||
HarkonnenAttackDelay["easy"] = DateTime.Minutes(5)
|
||||
HarkonnenAttackDelay["normal"] = DateTime.Minutes(2) + DateTime.Seconds(40)
|
||||
HarkonnenAttackDelay["hard"] = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
HarkonnenAttackDelay =
|
||||
{
|
||||
easy = DateTime.Minutes(5),
|
||||
normal = DateTime.Minutes(2) + DateTime.Seconds(40),
|
||||
hard = DateTime.Minutes(1) + DateTime.Seconds(20)
|
||||
}
|
||||
|
||||
HarkonnenAttackWaves = { }
|
||||
HarkonnenAttackWaves["easy"] = 3
|
||||
HarkonnenAttackWaves["normal"] = 6
|
||||
HarkonnenAttackWaves["hard"] = 9
|
||||
HarkonnenAttackWaves =
|
||||
{
|
||||
easy = 3,
|
||||
normal = 6,
|
||||
hard = 9
|
||||
}
|
||||
|
||||
OrdosReinforcements = { "light_inf", "light_inf", "raider" }
|
||||
OrdosEntryPath = { OrdosEntry.Location, OrdosRally.Location }
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
|
||||
SendInitialUnits = function(areaTrigger, unit, path, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
harkonnen.MarkCompletedObjective(KillOrdos)
|
||||
@@ -119,7 +95,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Ordos")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
Camera.Position = OConyard.CenterPosition
|
||||
|
||||
@@ -132,36 +110,10 @@ WorldLoaded = function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", OrdosReinforcements, OrdosEntryPath, { OrdosEntryPath[1] })
|
||||
end)
|
||||
|
||||
SendInitialUnits(HarkonnenBaseAreaTrigger, InitialHarkonnenReinforcements[1], InitialHarkonnenReinforcementsPaths[1], InitialReinforcementsSent1)
|
||||
SendInitialUnits(HarkonnenBaseAreaTrigger, InitialHarkonnenReinforcements[2], InitialHarkonnenReinforcementsPaths[2], InitialReinforcementsSent2)
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, InitialHarkonnenReinforcements[1], InitialHarkonnenReinforcementsPaths[1])
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, InitialHarkonnenReinforcements[2], InitialHarkonnenReinforcementsPaths[2])
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenAttackPaths) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos02a.lua, ordos02a-AI.lua
|
||||
Scripts: campaign-global.lua, ordos02a.lua, ordos02a-AI.lua
|
||||
MissionData:
|
||||
Briefing: Harkonnen forces are weakened in the Imperial Basin. Use the sensors in our Outpost to find them. Strike hard and destroy everything.\n
|
||||
BriefingVideo: O_BR02_E.VQA
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
IdlingUnits = { }
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -14,6 +13,7 @@ AttackGroupSize =
|
||||
normal = 8,
|
||||
hard = 10
|
||||
}
|
||||
|
||||
AttackDelays =
|
||||
{
|
||||
easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
|
||||
@@ -23,108 +23,12 @@ AttackDelays =
|
||||
|
||||
HarkonnenInfantryTypes = { "light_inf" }
|
||||
|
||||
AttackOnGoing = false
|
||||
HoldProduction = false
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if Attacking then
|
||||
return
|
||||
end
|
||||
Attacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
Attacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits()
|
||||
ProduceInfantry()
|
||||
IdlingUnits[harkonnen] = { }
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local toBuild = function() return HarkonnenInfantryTypes end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
ProduceUnits(harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end
|
||||
|
||||
@@ -9,35 +9,37 @@
|
||||
|
||||
HarkonnenBase = { HConyard, HPower1, HPower2, HBarracks, HOutpost }
|
||||
|
||||
HarkonnenReinforcements = { }
|
||||
HarkonnenReinforcements["easy"] =
|
||||
HarkonnenReinforcements =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
}
|
||||
easy =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["normal"] =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
}
|
||||
normal =
|
||||
{
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" }
|
||||
},
|
||||
|
||||
HarkonnenReinforcements["hard"] =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
hard =
|
||||
{
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf", "trike", "trike" },
|
||||
{ "light_inf", "light_inf" },
|
||||
{ "trike", "trike" },
|
||||
{ "light_inf", "light_inf", "light_inf" },
|
||||
{ "light_inf", "trike" },
|
||||
{ "trike", "trike" }
|
||||
}
|
||||
}
|
||||
|
||||
HarkonnenAttackPaths =
|
||||
@@ -62,26 +64,6 @@ HarkonnenAttackWaves =
|
||||
hard = 9
|
||||
}
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenAttackPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
IdleHunt = function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
harkonnen.MarkCompletedObjective(KillOrdos)
|
||||
@@ -97,7 +79,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Ordos")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
Camera.Position = OConyard.CenterPosition
|
||||
|
||||
@@ -105,33 +89,7 @@ WorldLoaded = function()
|
||||
Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenAttackPaths) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty])
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Destroy all Harkonnen forces.")
|
||||
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos02b.lua, ordos02b-AI.lua
|
||||
Scripts: campaign-global.lua, ordos02b.lua, ordos02b-AI.lua
|
||||
MissionData:
|
||||
Briefing: Harkonnen forces are weakened in the Imperial Basin. Use the sensors in our Outpost to find them. Strike hard and destroy everything.\n
|
||||
BriefingVideo: O_BR02_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -17,143 +24,27 @@ AttackDelays =
|
||||
HarkonnenInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
HarkonnenVehicleTypes = { "trike", "trike", "quad" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if IsAttacking then
|
||||
return
|
||||
end
|
||||
IsAttacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
IsAttacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(harkonnen, HarkonnenInitialReinforcements, HarkonnenInitialPath)
|
||||
IdlingUnits[harkonnen] = Reinforcements.Reinforce(harkonnen, HarkonnenInitialReinforcements, HarkonnenInitialPath)
|
||||
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if HLightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenVehicleTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[harkonnen] = true
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
|
||||
HConyard.Produce(OrdosUpgrades[1])
|
||||
HConyard.Produce(OrdosUpgrades[2])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(HarkonnenInfantryTypes) } end
|
||||
local vehilcesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceUnits(harkonnen, HBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(harkonnen, HLightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
HarkonnenBase = { HBarracks, HWindTrap1, HWindTrap2, HLightFactory, HOutpost, HConyard, HRefinery, HSilo1, HSilo2, HSilo3, HSilo4 }
|
||||
HarkonnenBaseAreaTrigger = { CPos.New(2, 58), CPos.New(3, 58), CPos.New(4, 58), CPos.New(5, 58), CPos.New(6, 58), CPos.New(7, 58), CPos.New(8, 58), CPos.New(9, 58), CPos.New(10, 58), CPos.New(11, 58), CPos.New(12, 58), CPos.New(13, 58), CPos.New(14, 58), CPos.New(15, 58), CPos.New(16, 58), CPos.New(16, 59), CPos.New(16, 60) }
|
||||
|
||||
@@ -67,40 +76,10 @@ OrdosPath = { OrdosEntry.Location, OrdosRally.Location }
|
||||
OrdosBaseBuildings = { "barracks", "light_factory" }
|
||||
OrdosUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
if player.IsObjectiveCompleted(KillHarkonnen) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(OrdosBaseBuildings[index]) > 0 and not player.HasPrerequisites({ OrdosUpgrades[index] })
|
||||
end
|
||||
|
||||
SendHunters = function(areaTrigger, unit, path, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if player.HasNoRequiredUnits() then
|
||||
harkonnen.MarkCompletedObjective(KillOrdos)
|
||||
@@ -111,12 +90,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[harkonnen] then
|
||||
local units = harkonnen.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[harkonnen] = false
|
||||
ProtectHarvester(units[1], harkonnen, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -129,7 +108,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Ordos")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = OConyard.CenterPosition
|
||||
|
||||
@@ -137,39 +118,14 @@ WorldLoaded = function()
|
||||
Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillHarkonnen) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty], waveCondition)
|
||||
ActivateAI()
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", OrdosReinforcements, OrdosPath, { OrdosPath[1] })
|
||||
end)
|
||||
|
||||
SendHunters(HarkonnenBaseAreaTrigger, HarkonnenHunters, HarkonnenHunterPath, HuntersSent)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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)
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, HarkonnenHunters, HarkonnenHunterPath)
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos03a.lua, ordos03a-AI.lua
|
||||
Scripts: campaign-global.lua, ordos03a.lua, ordos03a-AI.lua
|
||||
MissionData:
|
||||
Briefing: The Harkonnen hinder the production of Spice. A Harkonnen attack will disrupt efficient production. Inefficiency cannot be tolerated. The Harkonnen must be eliminated.\n\nNew weapons are available - the Quads. Newer weapons are more powerful. Powerful weapons ensure victory.
|
||||
BriefingVideo: O_BR03_E.VQA
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
IdlingUnits = { }
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -17,143 +24,27 @@ AttackDelays =
|
||||
HarkonnenInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
|
||||
HarkonnenVehicleTypes = { "trike", "trike", "quad" }
|
||||
|
||||
HarvesterKilled = true
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function()
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Map.LobbyOption("difficulty")], 1 do
|
||||
if #IdlingUnits == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits + 1)
|
||||
|
||||
if IdlingUnits[number] and not IdlingUnits[number].IsDead then
|
||||
units[i] = IdlingUnits[number]
|
||||
table.remove(IdlingUnits, number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function()
|
||||
if IsAttacking then
|
||||
return
|
||||
end
|
||||
IsAttacking = true
|
||||
HoldProduction = true
|
||||
|
||||
local units = SetupAttackGroup()
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
IsAttacking = false
|
||||
HoldProduction = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit)
|
||||
DefendActor(unit)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing then
|
||||
return
|
||||
end
|
||||
AttackOnGoing = true
|
||||
|
||||
local Guards = SetupAttackGroup()
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing = 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() AttackOnGoing = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function()
|
||||
IdlingUnits = Reinforcements.Reinforce(harkonnen, HarkonnenInitialReinforcements, HarkonnenInitialPath)
|
||||
IdlingUnits[harkonnen] = Reinforcements.Reinforce(harkonnen, HarkonnenInitialReinforcements, HarkonnenInitialPath)
|
||||
|
||||
Utils.Do(HarkonnenBase, function(actor)
|
||||
DefendActor(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceInfantry = function()
|
||||
if HBarracks.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceInfantry)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceInfantry)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ProduceVehicles = function()
|
||||
if HLightFactory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction then
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), ProduceVehicles)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Map.LobbyOption("difficulty")][1], AttackDelays[Map.LobbyOption("difficulty")][2] + 1)
|
||||
local toBuild = { Utils.Random(HarkonnenVehicleTypes) }
|
||||
harkonnen.Build(toBuild, function(unit)
|
||||
IdlingUnits[#IdlingUnits + 1] = unit[1]
|
||||
Trigger.AfterDelay(delay, ProduceVehicles)
|
||||
|
||||
if #IdlingUnits >= (AttackGroupSize[Map.LobbyOption("difficulty")] * 2.5) then
|
||||
SendAttack()
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
HarvesterKilled[harkonnen] = true
|
||||
Trigger.AfterDelay(0, InitAIUnits)
|
||||
|
||||
HConyard.Produce(OrdosUpgrades[1])
|
||||
HConyard.Produce(OrdosUpgrades[2])
|
||||
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(HarkonnenInfantryTypes) } end
|
||||
local vehilcesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end
|
||||
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
ProduceInfantry()
|
||||
ProduceVehicles()
|
||||
ProduceUnits(harkonnen, HBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
ProduceUnits(harkonnen, HLightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
HarkonnenBase = { HBarracks, HWindTrap1, HWindTrap2, HWindTrap3, HWindTrap4, HLightFactory, HOutpost, HConyard, HRefinery, HSilo1, HSilo2, HSilo3, HSilo4 }
|
||||
HarkonnenBaseAreaTrigger = { CPos.New(2, 58), CPos.New(3, 58), CPos.New(4, 58), CPos.New(5, 58), CPos.New(6, 58), CPos.New(7, 58), CPos.New(8, 58), CPos.New(9, 58), CPos.New(10, 58), CPos.New(11, 58), CPos.New(12, 58), CPos.New(13, 58), CPos.New(14, 58), CPos.New(15, 58), CPos.New(16, 58), CPos.New(16, 59), CPos.New(16, 60) }
|
||||
|
||||
@@ -96,40 +105,10 @@ OrdosReinforcementDelays =
|
||||
OrdosBaseBuildings = { "barracks", "light_factory" }
|
||||
OrdosUpgrades = { "upgrade.barracks", "upgrade.light" }
|
||||
|
||||
wave = 0
|
||||
SendHarkonnen = function()
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Map.LobbyOption("difficulty")], function()
|
||||
if player.IsObjectiveCompleted(KillHarkonnen) then
|
||||
return
|
||||
end
|
||||
|
||||
wave = wave + 1
|
||||
if wave > HarkonnenAttackWaves[Map.LobbyOption("difficulty")] then
|
||||
return
|
||||
end
|
||||
|
||||
local path = Utils.Random(HarkonnenPaths)
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", HarkonnenReinforcements[Map.LobbyOption("difficulty")][wave], path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
|
||||
SendHarkonnen()
|
||||
end)
|
||||
end
|
||||
|
||||
MessageCheck = function(index)
|
||||
return #player.GetActorsByType(OrdosBaseBuildings[index]) > 0 and not player.HasPrerequisites({ OrdosUpgrades[index] })
|
||||
end
|
||||
|
||||
SendHunters = function(areaTrigger, unit, path, check)
|
||||
Trigger.OnEnteredFootprint(areaTrigger, function(a, id)
|
||||
if not check and a.Owner == player then
|
||||
local units = Reinforcements.ReinforceWithTransport(harkonnen, "carryall.reinforce", unit, path, { path[1] })[2]
|
||||
Utils.Do(units, IdleHunt)
|
||||
check = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
SendOrdosReinforcements = function(timer, unit, path)
|
||||
Trigger.AfterDelay(timer, function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", unit, path, { path[1] })
|
||||
@@ -148,12 +127,12 @@ Tick = function()
|
||||
player.MarkCompletedObjective(KillHarkonnen)
|
||||
end
|
||||
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[harkonnen] then
|
||||
local units = harkonnen.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled = false
|
||||
ProtectHarvester(units[1])
|
||||
HarvesterKilled[harkonnen] = false
|
||||
ProtectHarvester(units[1], harkonnen, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -166,7 +145,9 @@ WorldLoaded = function()
|
||||
harkonnen = Player.GetPlayer("Harkonnen")
|
||||
player = Player.GetPlayer("Ordos")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
Camera.Position = OConyard.CenterPosition
|
||||
|
||||
@@ -174,7 +155,9 @@ WorldLoaded = function()
|
||||
Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt)
|
||||
end)
|
||||
|
||||
SendHarkonnen()
|
||||
local path = function() return Utils.Random(HarkonnenPaths) end
|
||||
local waveCondition = function() return player.IsObjectiveCompleted(KillHarkonnen) end
|
||||
SendCarryallReinforcements(harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty], waveCondition)
|
||||
ActivateAI()
|
||||
|
||||
SendOrdosReinforcements(OrdosReinforcementDelays[1], OrdosReinforcements[1], OrdosPaths[1])
|
||||
@@ -184,34 +167,7 @@ WorldLoaded = function()
|
||||
Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", OrdosReinforcements[2], OrdosPaths[2], { OrdosPaths[2][1] })
|
||||
end)
|
||||
|
||||
SendHunters(HarkonnenBaseAreaTrigger, HarkonnenHunters[1], HarkonnenHunterPaths[1], HuntersSent1)
|
||||
SendHunters(HarkonnenBaseAreaTrigger, HarkonnenHunters[2], HarkonnenHunterPaths[2], HuntersSent2)
|
||||
SendHunters(HarkonnenBaseAreaTrigger, HarkonnenHunters[3], HarkonnenHunterPaths[3], HuntersSent3)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdos = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillHarkonnen = player.AddPrimaryObjective("Eliminate all Harkonnen units and reinforcements\nin the area.")
|
||||
|
||||
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)
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, HarkonnenHunters[1], HarkonnenHunterPaths[1])
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, HarkonnenHunters[2], HarkonnenHunterPaths[2])
|
||||
TriggerCarryallReinforcements(player, harkonnen, HarkonnenBaseAreaTrigger, HarkonnenHunters[3], HarkonnenHunterPaths[3])
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos03b.lua, ordos03b-AI.lua
|
||||
Scripts: campaign-global.lua, ordos03b.lua, ordos03b-AI.lua
|
||||
MissionData:
|
||||
Briefing: The Harkonnen hinder the production of Spice. A Harkonnen attack will disrupt efficient production. Inefficiency cannot be tolerated. The Harkonnen must be eliminated.\n\nNew weapons are available - the Quads. Newer weapons are more powerful. Powerful weapons ensure victory.
|
||||
BriefingVideo: O_BR03_E.VQA
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
IdlingUnits =
|
||||
{
|
||||
Harkonnen = { },
|
||||
Smugglers = { }
|
||||
}
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
AttackGroupSize =
|
||||
{
|
||||
@@ -26,155 +29,30 @@ HarkonnenTankType = { "combat_tank_h" }
|
||||
SmugglerVehicleTypes = { "raider", "raider", "quad" }
|
||||
SmugglerTankType = { "combat_tank_o" }
|
||||
|
||||
IsAttacking =
|
||||
{
|
||||
Harkonnen = false,
|
||||
Smugglers = false
|
||||
}
|
||||
|
||||
AttackOnGoing =
|
||||
{
|
||||
Harkonnen = false,
|
||||
Smugglers = false
|
||||
}
|
||||
|
||||
HoldProduction =
|
||||
{
|
||||
Harkonnen = false,
|
||||
Smugglers = false
|
||||
}
|
||||
|
||||
HarvesterKilled =
|
||||
{
|
||||
Harkonnen = true,
|
||||
Smugglers = true
|
||||
}
|
||||
|
||||
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
|
||||
|
||||
SetupAttackGroup = function(house)
|
||||
local units = { }
|
||||
|
||||
for i = 0, AttackGroupSize[Difficulty], 1 do
|
||||
if #IdlingUnits[house.Name] == 0 then
|
||||
return units
|
||||
end
|
||||
|
||||
local number = Utils.RandomInteger(1, #IdlingUnits[house.Name])
|
||||
|
||||
if IdlingUnits[house.Name][number] and not IdlingUnits[house.Name][number].IsDead then
|
||||
units[i] = IdlingUnits[house.Name][number]
|
||||
table.remove(IdlingUnits[house.Name], number)
|
||||
end
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
|
||||
SendAttack = function(house)
|
||||
if IsAttacking[house.Name] then
|
||||
return
|
||||
end
|
||||
IsAttacking[house.Name] = true
|
||||
HoldProduction[house.Name] = true
|
||||
|
||||
local units = SetupAttackGroup(house)
|
||||
Utils.Do(units, function(unit)
|
||||
IdleHunt(unit)
|
||||
end)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(units, function()
|
||||
IsAttacking[house.Name] = false
|
||||
HoldProduction[house.Name] = false
|
||||
end)
|
||||
end
|
||||
|
||||
ProtectHarvester = function(unit, house)
|
||||
DefendActor(unit, house)
|
||||
Trigger.OnKilled(unit, function() HarvesterKilled[house.Name] = true end)
|
||||
end
|
||||
|
||||
DefendActor = function(unit, house)
|
||||
Trigger.OnDamaged(unit, function(self, attacker)
|
||||
if AttackOnGoing[house.Name] then
|
||||
return
|
||||
end
|
||||
AttackOnGoing[house.Name] = true
|
||||
|
||||
-- Don't try to attack spiceblooms
|
||||
if attacker and attacker.Type == "spicebloom" then
|
||||
return
|
||||
end
|
||||
|
||||
local Guards = SetupAttackGroup(house)
|
||||
|
||||
if #Guards <= 0 then
|
||||
AttackOnGoing[house.Name] = 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() AttackOnGoing[house.Name] = false end)
|
||||
end)
|
||||
end
|
||||
|
||||
InitAIUnits = function(house)
|
||||
IdlingUnits[house.Name] = Reinforcements.Reinforce(house, InitialReinforcements[house.Name], InitialReinforcementsPaths[house.Name])
|
||||
HarvesterKilled[house] = true
|
||||
IdlingUnits[house] = Reinforcements.Reinforce(house, InitialReinforcements[house.Name], InitialReinforcementsPaths[house.Name])
|
||||
|
||||
Utils.Do(Base[house.Name], function(actor)
|
||||
DefendActor(actor, house)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Health < building.MaxHealth * 3/4 and building.Owner.Name == house.Name then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
Produce = function(house, units, factory)
|
||||
if factory.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if HoldProduction[house.Name] then
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), function() Produce(house, units, factory) end)
|
||||
return
|
||||
end
|
||||
|
||||
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1)
|
||||
local toBuild = { Utils.Random(units) }
|
||||
house.Build(toBuild, function(unit)
|
||||
local unitCount = 1
|
||||
if IdlingUnits[house.Name] then
|
||||
unitCount = 1 + #IdlingUnits[house.Name]
|
||||
end
|
||||
IdlingUnits[house.Name][unitCount] = unit[1]
|
||||
Trigger.AfterDelay(delay, function() Produce(house, units, factory) end)
|
||||
|
||||
if unitCount >= (AttackGroupSize[Difficulty] * 2.5) then
|
||||
SendAttack(house)
|
||||
end
|
||||
end)
|
||||
DefendAndRepairBase(house, Base[house.Name], 0.75, AttackGroupSize[Difficulty])
|
||||
end
|
||||
|
||||
ActivateAI = function()
|
||||
InitAIUnits(harkonnen)
|
||||
InitAIUnits(smuggler)
|
||||
|
||||
-- Finish the upgrades first before trying to build something
|
||||
Trigger.AfterDelay(DateTime.Seconds(14), function()
|
||||
Produce(harkonnen, EnemyInfantryTypes, HBarracks)
|
||||
Produce(harkonnen, HarkonnenVehicleTypes, HLightFactory)
|
||||
Produce(harkonnen, HarkonnenTankType, HHeavyFactory)
|
||||
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
|
||||
local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end
|
||||
local hVehiclesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end
|
||||
local hTanksToBuild = function() return HarkonnenTankType end
|
||||
local sVehiclesToBuild = function() return { Utils.Random(SmugglerVehicleTypes) } end
|
||||
local sTanksToBuild = function() return SmugglerTankType end
|
||||
local attackTresholdSize = AttackGroupSize[Difficulty] * 2.5
|
||||
|
||||
Produce(smuggler, EnemyInfantryTypes, SBarracks)
|
||||
Produce(smuggler, SmugglerVehicleTypes, SLightFactory)
|
||||
Produce(smuggler, SmugglerTankType, SHeavyFactory)
|
||||
end)
|
||||
ProduceUnits(harkonnen, HBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
ProduceUnits(harkonnen, HLightFactory, delay, hVehiclesToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
ProduceUnits(harkonnen, HHeavyFactory, delay, hTanksToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
|
||||
ProduceUnits(smuggler, SBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
ProduceUnits(smuggler, SLightFactory, delay, sVehiclesToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
ProduceUnits(smuggler, SHeavyFactory, delay, sTanksToBuild, AttackGroupSize[Difficulty], attackTresholdSize)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
--[[
|
||||
Copyright 2007-2017 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.
|
||||
]]
|
||||
|
||||
Base =
|
||||
{
|
||||
Harkonnen = { HRefinery, SHeavyFactory, SLightFactory, HGunTurret1, HGunTurret2, HGunTurret3, HGunTurret4, HGunTurret5, SBarracks, HPower1, HPower2, HPower3, HPower4 },
|
||||
@@ -62,12 +71,12 @@ Hunt = function(house)
|
||||
end
|
||||
|
||||
CheckHarvester = function(house)
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[house.Name] then
|
||||
if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled[house] then
|
||||
local units = house.GetActorsByType("harvester")
|
||||
|
||||
if #units > 0 then
|
||||
HarvesterKilled[house.Name] = false
|
||||
ProtectHarvester(units[1], house)
|
||||
HarvesterKilled[house] = false
|
||||
ProtectHarvester(units[1], house, AttackGroupSize[Difficulty])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -86,15 +95,6 @@ Tick = function()
|
||||
|
||||
CheckHarvester(harkonnen)
|
||||
CheckHarvester(smuggler)
|
||||
|
||||
if SOutpost.IsDead then
|
||||
player.MarkFailedObjective(CaptureOutpost)
|
||||
end
|
||||
|
||||
if SOutpost.Owner == player then
|
||||
player.MarkCompletedObjective(CaptureOutpost)
|
||||
smuggler.MarkFailedObjective(DefendOutpost)
|
||||
end
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
@@ -102,9 +102,12 @@ WorldLoaded = function()
|
||||
smuggler = Player.GetPlayer("Smugglers")
|
||||
player = Player.GetPlayer("Ordos")
|
||||
|
||||
Difficulty = Map.LobbyOption("difficulty")
|
||||
|
||||
InitObjectives()
|
||||
InitObjectives(player)
|
||||
KillOrdosH = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillOrdosS = smuggler.AddSecondaryObjective("Kill all Ordos units.")
|
||||
DefendOutpost = smuggler.AddPrimaryObjective("Don't let the outpost to be captured or destroyed.")
|
||||
CaptureOutpost = player.AddPrimaryObjective("Capture the Smuggler Outpost.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Destroy the Harkonnen.")
|
||||
|
||||
Camera.Position = OConyard.CenterPosition
|
||||
HarkonnenAttackLocation = OConyard.Location
|
||||
@@ -115,12 +118,22 @@ WorldLoaded = function()
|
||||
SendHarkonnen(LightInfantryRushersPaths[1])
|
||||
SendHarkonnen(LightInfantryRushersPaths[2])
|
||||
SendHarkonnen(LightInfantryRushersPaths[3])
|
||||
ActivateAI()
|
||||
|
||||
Actor.Create("upgrade.barracks", true, { Owner = harkonnen })
|
||||
Actor.Create("upgrade.light", true, { Owner = harkonnen })
|
||||
Actor.Create("upgrade.barracks", true, { Owner = smuggler })
|
||||
Actor.Create("upgrade.light", true, { Owner = smuggler })
|
||||
Trigger.AfterDelay(0, ActivateAI)
|
||||
|
||||
Trigger.OnKilled(SOutpost, function()
|
||||
player.MarkFailedObjective(CaptureOutpost)
|
||||
end)
|
||||
Trigger.OnCapture(SOutpost, function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(2), function()
|
||||
player.MarkCompletedObjective(CaptureOutpost)
|
||||
smuggler.MarkFailedObjective(DefendOutpost)
|
||||
end)
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty] - DateTime.Seconds(5), function()
|
||||
Media.PlaySpeechNotification(player, "Reinforce")
|
||||
@@ -128,36 +141,6 @@ WorldLoaded = function()
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty], function()
|
||||
Media.DisplayMessage("WARNING: Large force approaching!", "Mentat")
|
||||
end)
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(player, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
KillOrdosH = harkonnen.AddPrimaryObjective("Kill all Ordos units.")
|
||||
KillOrdosS = smuggler.AddSecondaryObjective("Kill all Ordos units.")
|
||||
DefendOutpost = smuggler.AddPrimaryObjective("Don't let the outpost to be captured or destroyed.")
|
||||
CaptureOutpost = player.AddPrimaryObjective("Capture the Smuggler Outpost.")
|
||||
KillHarkonnen = player.AddSecondaryObjective("Destroy the Harkonnen.")
|
||||
|
||||
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)
|
||||
Media.DisplayMessage("WARNING: Large force approaching!", "Mentat")
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Player:
|
||||
|
||||
World:
|
||||
LuaScript:
|
||||
Scripts: ordos04.lua, ordos04-AI.lua
|
||||
Scripts: campaign-global.lua, ordos04.lua, ordos04-AI.lua
|
||||
MissionData:
|
||||
Briefing: The Smugglers at Sietch Tabr must be neutralized. Capture the Outpost where their families have taken shelter as insurance. The children's lives will assure the loyalties of their fathers. Use an Engineer to enter and capture the building.\n\nThe Smugglers' new partners, the Harkonnen, may attempt to protect them. Harkonnen firepower is great, but we have recently acquired tanks that may counter this.\n\nEnsure our investment is used wisely.\n
|
||||
BriefingVideo: O_BR04_E.VQA
|
||||
|
||||
@@ -15,6 +15,7 @@ Packages:
|
||||
|
||||
~SOUND.RS
|
||||
d2k|bits
|
||||
d2k|bits/scripts
|
||||
d2k|bits/tex
|
||||
d2k|uibits
|
||||
|
||||
|
||||
Reference in New Issue
Block a user