diff --git a/OpenRA.sln b/OpenRA.sln index 449ca07899..8561232bb2 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -112,6 +112,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dune 2000 Lua scripts", "Du mods\d2k\maps\atreides-03b\atreides03b.lua = mods\d2k\maps\atreides-03b\atreides03b.lua mods\d2k\maps\atreides-04\atreides04-AI.lua = mods\d2k\maps\atreides-04\atreides04-AI.lua mods\d2k\maps\atreides-04\atreides04.lua = mods\d2k\maps\atreides-04\atreides04.lua + mods\d2k\maps\atreides-05\atreides05-AI.lua = mods\d2k\maps\atreides-05\atreides05-AI.lua + mods\d2k\maps\atreides-05\atreides05.lua = mods\d2k\maps\atreides-05\atreides05.lua mods\d2k\maps\harkonnen-01a\harkonnen01a.lua = mods\d2k\maps\harkonnen-01a\harkonnen01a.lua mods\d2k\maps\harkonnen-01b\harkonnen01b.lua = mods\d2k\maps\harkonnen-01b\harkonnen01b.lua mods\d2k\maps\harkonnen-02a\harkonnen02a-AI.lua = mods\d2k\maps\harkonnen-02a\harkonnen02a-AI.lua diff --git a/mods/d2k/maps/atreides-05/atreides05-AI.lua b/mods/d2k/maps/atreides-05/atreides05-AI.lua new file mode 100644 index 0000000000..637a1080c5 --- /dev/null +++ b/mods/d2k/maps/atreides-05/atreides05-AI.lua @@ -0,0 +1,195 @@ +IdlingUnits = { } + +AttackGroupSize = +{ + easy = 6, + normal = 8, + hard = 10 +} + +AttackDelays = +{ + easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, + normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, + hard = { DateTime.Seconds(1), DateTime.Seconds(3) } +} + +HarkonnenInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } +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] + + Utils.Do(HarkonnenBase, function(actor) + DefendActor(actor) + RepairBuilding(harkonnen, actor) + end) + + DefendActor(HarkonnenBarracks) + RepairBuilding(harkonnen, HarkonnenBarracks) + + Utils.Do(SmugglerBase, function(actor) + RepairBuilding(smuggler, actor) + end) + RepairBuilding(smuggler, Starport) +end + +ProduceInfantry = function() + if StopInfantryProduction or HarkonnenBarracks.IsDead or HarkonnenBarracks.Owner ~= harkonnen 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 + +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() + end + end) +end + +ActivateAI = function() + harkonnen.Cash = 15000 + InitAIUnits() + + ProduceInfantry() + ProduceVehicles() + ProduceTanks() +end diff --git a/mods/d2k/maps/atreides-05/atreides05.lua b/mods/d2k/maps/atreides-05/atreides05.lua new file mode 100644 index 0000000000..1f0532dbb4 --- /dev/null +++ b/mods/d2k/maps/atreides-05/atreides05.lua @@ -0,0 +1,443 @@ +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 } + +HarkonnenReinforcements = +{ + easy = + { + { "combat_tank_h", "trooper", "trooper", "trooper", "trooper" }, + { "trooper", "trooper", "trooper", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" } + }, + + normal = + { + { "combat_tank_h", "trooper", "trooper", "trooper", "trooper" }, + { "trooper", "trooper", "trooper", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" }, + { "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" } + }, + + hard = + { + { "combat_tank_h", "trooper", "trooper", "trooper", "trooper" }, + { "trooper", "trooper", "trooper", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" }, + { "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" }, + { "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" }, + { "combat_tank_h", "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" }, + { "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h" } + } +} + +HarkonnenInfantryReinforcements = +{ + normal = + { + { "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" } + }, + + hard = + { + { "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" }, + { "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" } + } +} +InfantryPath = { HarkonnenEntry3.Location } + +HarkonnenAttackDelay = +{ + easy = DateTime.Minutes(3), + normal = DateTime.Minutes(2) + DateTime.Seconds(20), + hard = DateTime.Minutes(1) +} + +HarkonnenAttackWaves = +{ + easy = 5, + normal = 7, + hard = 9 +} + +MercenaryReinforcements = +{ + easy = + { + { "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" }, + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" } + }, + + normal = + { + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" }, + { "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }, + { "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" }, + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" } + }, + + hard = + { + { "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" }, + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }, + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" }, + { "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }, + { "combat_tank_o", "combat_tank_o", "quad", "quad", "trike", "trike", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" }, + { "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike", "quad", "quad" }, + { "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "trike", "trike", "quad", "quad", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" } + } +} + +MercenaryAttackDelay = +{ + easy = DateTime.Minutes(2) + DateTime.Seconds(40), + normal = DateTime.Minutes(1) + DateTime.Seconds(50), + hard = DateTime.Minutes(1) + DateTime.Seconds(10) +} + +MercenaryAttackWaves = +{ + easy = 3, + normal = 6, + hard = 9 +} + +MercenarySpawn = { HarkonnenRally4.Location + CVec.New(2, -2) } + +-- Ordos tanks because those were intended for the Smugglers not the Atreides +ContrabandReinforcements = { "mcv", "quad", "quad", "combat_tank_o", "combat_tank_o", "combat_tank_o" } +SmugglerReinforcements = { "quad", "quad", "trike", "trike" } +InitialHarkonnenReinforcements = { "trooper", "trooper", "quad", "quad", "trike", "trike", "trike", "light_inf" } + +HarkonnenPaths = +{ + { HarkonnenEntry1.Location, HarkonnenRally1.Location }, + { HarkonnenEntry1.Location, HarkonnenRally3.Location }, + { HarkonnenEntry1.Location, HarkonnenRally2.Location }, + { HarkonnenEntry1.Location, HarkonnenRally4.Location }, + { HarkonnenEntry2.Location } +} + +AtreidesReinforcements = { "trike", "combat_tank_a" } +AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location } + +ContrabandTimes = +{ + easy = DateTime.Minutes(10), + normal = DateTime.Minutes(5), + hard = DateTime.Minutes(2) + DateTime.Seconds(30) +} + +wave = 0 +SendHarkonnen = function() + Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty], function() + if player.IsObjectiveCompleted(KillHarkonnen) then + return + end + + wave = wave + 1 + + if InfantryReinforcements and wave % 4 == 0 then + local inf = Reinforcements.Reinforce(harkonnen, HarkonnenInfantryReinforcements[Difficulty][wave/4], InfantryPath) + Utils.Do(inf, function(unit) + unit.AttackMove(HarkonnenAttackLocation) + IdleHunt(unit) + end) + 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) + + if wave < HarkonnenAttackWaves[Difficulty] then + SendHarkonnen() + return + end + + Trigger.AfterDelay(DateTime.Seconds(3), function() LastHarkonnenArrived = true end) + end) +end + +mercWave = 0 +SendMercenaries = function() + Trigger.AfterDelay(MercenaryAttackDelay[Difficulty], function() + mercWave = mercWave + 1 + + Media.DisplayMessage("Incoming hostile Mercenary force detected.", "Mentat") + + local units = Reinforcements.Reinforce(mercenary, MercenaryReinforcements[Difficulty][mercWave], MercenarySpawn) + Utils.Do(units, function(unit) + unit.AttackMove(MercenaryAttackLocation1) + unit.AttackMove(MercenaryAttackLocation2) + IdleHunt(unit) + end) + + if mercWave < MercenaryAttackWaves[Difficulty] then + SendMercenaries() + return + end + + Trigger.AfterDelay(DateTime.Seconds(3), function() LastMercenariesArrived = true end) + end) +end + +SendContraband = function(owner) + ContrabandArrived = true + UserInterface.SetMissionText("The Contraband has arrived!", player.Color) + + local units = SmugglerReinforcements + if owner == player then + units = ContrabandReinforcements + end + + Reinforcements.ReinforceWithTransport(owner, "frigate", units, { ContrabandEntry.Location, Starport.Location + CVec.New(1, 1) }, { ContrabandExit.Location }) + + Trigger.AfterDelay(DateTime.Seconds(3), function() + if owner == player then + player.MarkCompletedObjective(CaptureStarport) + Media.DisplayMessage("Contraband has arrived and been confiscated.", "Mentat") + else + player.MarkFailedObjective(CaptureStarport) + Media.DisplayMessage("Smuggler contraband has arrived. It is too late to confiscate.", "Mentat") + end + end) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + UserInterface.SetMissionText("") + end) +end + +SmugglersAttack = function() + Utils.Do(SmugglerBase, function(building) + if not building.IsDead and building.Owner == smuggler then + building.Sell() + end + end) + + Trigger.AfterDelay(DateTime.Seconds(1), function() + Utils.Do(smuggler.GetGroundAttackers(), function(unit) + IdleHunt(unit) + end) + end) +end + +AttackNotifier = 0 +Tick = function() + if player.HasNoRequiredUnits() then + harkonnen.MarkCompletedObjective(KillAtreides) + end + + if LastHarkonnenArrived and not player.IsObjectiveCompleted(KillHarkonnen) and harkonnen.HasNoRequiredUnits() then + Media.DisplayMessage("The Harkonnen have been annihilated!", "Mentat") + player.MarkCompletedObjective(KillHarkonnen) + end + + if LastMercenariesArrived and not player.IsObjectiveCompleted(KillSmuggler) and smuggler.HasNoRequiredUnits() and mercenary.HasNoRequiredUnits() then + Media.DisplayMessage("The Smugglers have been annihilated!", "Mentat") + player.MarkCompletedObjective(KillSmuggler) + end + + if HarvesterKilled and DateTime.GameTime % DateTime.Seconds(30) then + local units = harkonnen.GetActorsByType("harvester") + + if #units > 0 then + HarvesterKilled = false + ProtectHarvester(units[1]) + end + end + + AttackNotifier = AttackNotifier - 1 + + if TimerTicks and not ContrabandArrived then + TimerTicks = TimerTicks - 1 + UserInterface.SetMissionText("The contraband will arrive in " .. Utils.FormatTime(TimerTicks), player.Color) + + if TimerTicks <= 0 then + SendContraband(smuggler) + end + end +end + +WorldLoaded = function() + harkonnen = Player.GetPlayer("Harkonnen") + smuggler = Player.GetPlayer("Smugglers") + mercenary = Player.GetPlayer("Mercenaries") + player = Player.GetPlayer("Atreides") + + Difficulty = Map.LobbyOption("difficulty") + InfantryReinforcements = Difficulty ~= "easy" + + InitObjectives() + + Camera.Position = ARefinery.CenterPosition + HarkonnenAttackLocation = AtreidesRally.Location + MercenaryAttackLocation1 = Starport.Location + CVec.New(-16, 0) + MercenaryAttackLocation2 = Starport.Location + + Trigger.AfterDelay(DateTime.Seconds(2), function() + TimerTicks = ContrabandTimes[Difficulty] + Media.DisplayMessage("The contraband is approaching the Starport to the north in " .. Utils.FormatTime(TimerTicks) .. ".", "Mentat") + end) + + Trigger.OnAllKilledOrCaptured(HarkonnenBase, function() + Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt) + end) + + Trigger.OnKilled(Starport, function() + if not player.IsObjectiveCompleted(CaptureStarport) then + ContrabandArrived = true + UserInterface.SetMissionText("Starport destroyed! Contraband can't land.", player.Color) + player.MarkFailedObjective(CaptureStarport) + SmugglersAttack() + + Trigger.AfterDelay(DateTime.Seconds(15), function() + UserInterface.SetMissionText("") + end) + end + + if DefendStarport then + player.MarkFailedObjective(DefendStarport) + end + end) + Trigger.OnDamaged(Starport, function() + if Starport.Owner ~= smuggler then + return + end + + if AttackNotifier <= 0 then + AttackNotifier = DateTime.Seconds(10) + Media.DisplayMessage("Don't destroy the Starport!", "Mentat") + + local defenders = smuggler.GetGroundAttackers() + if #defenders > 0 then + Utils.Do(defenders, function(unit) + unit.Guard(Starport) + end) + end + end + end) + Trigger.OnCapture(Starport, function() + DefendStarport = player.AddSecondaryObjective("Defend the captured Starport.") + + Starport.GrantCondition("captured") + Trigger.ClearAll(Starport) + Trigger.AfterDelay(0, function() + Trigger.OnRemovedFromWorld(Starport, function() + player.MarkFailedObjective(DefendStarport) + end) + end) + + if not ContrabandArrived then + SendContraband(player) + end + SmugglersAttack() + end) + + Trigger.OnKilled(HarkonnenBarracks, function() + player.MarkFailedObjective(CaptureBarracks) + end) + Trigger.OnDamaged(HarkonnenBarracks, function() + if AttackNotifier <= 0 and HarkonnenBarracks.Health < HarkonnenBarracks.MaxHealth * 3/4 then + AttackNotifier = DateTime.Seconds(10) + Media.DisplayMessage("Don't destroy the Barracks!", "Mentat") + end + end) + Trigger.OnCapture(HarkonnenBarracks, function() + Media.DisplayMessage("Hostages Released!", "Mentat") + + if DefendStarport then + player.MarkCompletedObjective(DefendStarport) + end + + Trigger.AfterDelay(DateTime.Seconds(3), function() + player.MarkCompletedObjective(CaptureBarracks) + end) + end) + + SendHarkonnen() + Actor.Create("upgrade.barracks", true, { Owner = harkonnen }) + Actor.Create("upgrade.light", true, { Owner = harkonnen }) + Actor.Create("upgrade.heavy", true, { Owner = harkonnen }) + Trigger.AfterDelay(0, ActivateAI) + + Trigger.AfterDelay(DateTime.Minutes(1), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] }) + end) + + local smugglerWaypoint = SmugglerWaypoint1.Location + Trigger.OnEnteredFootprint({ smugglerWaypoint + CVec.New(-2, 0), smugglerWaypoint + CVec.New(-1, 0), smugglerWaypoint, smugglerWaypoint + CVec.New(1, -1), smugglerWaypoint + CVec.New(2, -1), SmugglerWaypoint3.Location }, function(a, id) + if not warned and a.Owner == player and a.Type ~= "carryall" then + warned = true + Trigger.RemoveFootprintTrigger(id) + Media.DisplayMessage("Stay away from our Starport.", "Smuggler Leader") + end + end) + + Trigger.OnEnteredFootprint({ SmugglerWaypoint2.Location }, function(a, id) + if not paid and a.Owner == player and a.Type ~= "carryall" then + paid = true + Trigger.RemoveFootprintTrigger(id) + Media.DisplayMessage("You were warned. Now you will pay.", "Smuggler Leader") + Utils.Do(smuggler.GetGroundAttackers(), function(unit) + unit.AttackMove(SmugglerWaypoint2.Location) + end) + + Trigger.AfterDelay(DateTime.Seconds(3), function() + KillSmuggler = player.AddSecondaryObjective("Destroy the Smugglers and their Mercenaries.") + SendMercenaries() + end) + end + end) + + Trigger.OnEnteredProximityTrigger(HarkonnenBarracks.CenterPosition, WDist.New(5 * 1024), function(a, id) + if a.Owner == player and a.Type ~= "carryall" then + Trigger.RemoveProximityTrigger(id) + Media.DisplayMessage("Capture the Harkonnen barracks to release the hostages.", "Mentat") + StopInfantryProduction = true + 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 diff --git a/mods/d2k/maps/atreides-05/map.bin b/mods/d2k/maps/atreides-05/map.bin new file mode 100644 index 0000000000..dd1f33d4a4 Binary files /dev/null and b/mods/d2k/maps/atreides-05/map.bin differ diff --git a/mods/d2k/maps/atreides-05/map.png b/mods/d2k/maps/atreides-05/map.png new file mode 100644 index 0000000000..1457d60952 Binary files /dev/null and b/mods/d2k/maps/atreides-05/map.png differ diff --git a/mods/d2k/maps/atreides-05/map.yaml b/mods/d2k/maps/atreides-05/map.yaml new file mode 100644 index 0000000000..22461cfc35 --- /dev/null +++ b/mods/d2k/maps/atreides-05/map.yaml @@ -0,0 +1,366 @@ +MapFormat: 11 + +RequiresMod: d2k + +Title: Atreides 05 + +Author: Westwood Studios + +Tileset: ARRAKIS + +MapSize: 68,68 + +Bounds: 2,2,64,64 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: Random + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: Random + Enemies: Harkonnen, Atreides, Mercenaries, Smugglers + PlayerReference@Atreides: + Name: Atreides + Playable: True + LockFaction: True + Faction: atreides + LockColor: True + Color: 9191FF + Enemies: Harkonnen, Smugglers, Mercenaries, Creeps + PlayerReference@Harkonnen: + Name: Harkonnen + LockFaction: True + Faction: harkonnen + LockColor: True + Color: FE0000 + Enemies: Atreides + PlayerReference@Smugglers: + Name: Smugglers + LockFaction: True + Faction: smuggler + LockColor: True + Color: 542209 + Allies: Mercenaries + Enemies: Atreides + PlayerReference@Mercenaries: + Name: Mercenaries + LockFaction: True + Faction: mercenary + LockColor: True + Color: DDDD00 + Allies: Smugglers + Enemies: Atreides + +Actors: + Actor4: trike + Location: 44,3 + Owner: Harkonnen + Actor5: wormspawner + Location: 58,5 + Owner: Creeps + Actor6: wall + Location: 4,7 + Owner: Harkonnen + Actor7: wall + Location: 2,8 + Owner: Harkonnen + Actor8: wall + Location: 3,8 + Owner: Harkonnen + Actor10: spicebloom + Location: 15,8 + Owner: Neutral + Actor12: wall + Location: 26,11 + Owner: Harkonnen + Actor15: wall + Location: 27,12 + Owner: Harkonnen + Actor16: spicebloom + Location: 38,12 + Owner: Neutral + Actor20: spicebloom + Location: 4,15 + Owner: Neutral + Actor28: carryall + Location: 26,18 + Owner: Harkonnen + Actor29: spicebloom + Location: 49,18 + Owner: Neutral + Actor33: wall + Location: 31,19 + Owner: Harkonnen + Actor34: wall + Location: 32,19 + Owner: Harkonnen + Actor35: wall + Location: 33,19 + Owner: Harkonnen + Actor38: wall + Location: 34,20 + Owner: Harkonnen + Actor41: wall + Location: 8,23 + Owner: Harkonnen + Actor43: wall + Location: 10,23 + Owner: Harkonnen + Actor45: wall + Location: 24,23 + Owner: Harkonnen + Actor46: wall + Location: 22,24 + Owner: Harkonnen + Actor47: wall + Location: 23,24 + Owner: Harkonnen + Actor49: light_inf + Location: 59,24 + Owner: Smugglers + Actor50: wall + Location: 20,25 + Owner: Harkonnen + Actor51: wall + Location: 21,25 + Owner: Harkonnen + Actor52: wall + Location: 22,25 + Owner: Harkonnen + Actor53: light_inf + Location: 60,25 + Owner: Smugglers + Actor54: trooper + Location: 62,25 + Owner: Smugglers + Actor56: wall + Location: 16,26 + Owner: Harkonnen + Actor57: wall + Location: 17,26 + Owner: Harkonnen + Actor58: wall + Location: 18,26 + Owner: Harkonnen + Actor59: wall + Location: 19,26 + Owner: Harkonnen + Actor60: wall + Location: 20,26 + Owner: Harkonnen + Actor61: light_inf + Location: 58,26 + Owner: Smugglers + Actor62: light_inf + Location: 60,27 + Owner: Smugglers + Actor63: trooper + Location: 47,30 + Owner: Harkonnen + Actor64: trooper + Location: 42,31 + Owner: Harkonnen + Actor65: trooper + Location: 37,32 + Owner: Harkonnen + Actor66: trooper + Location: 27,38 + Owner: Harkonnen + Actor67: spicebloom + Location: 21,41 + Owner: Neutral + Actor68: trooper + Location: 26,41 + Owner: Harkonnen + Actor69: spicebloom + Location: 46,42 + Owner: Neutral + Actor70: quad + Location: 58,43 + Owner: Harkonnen + Actor71: spicebloom + Location: 23,46 + Owner: Neutral + Actor72: light_factory + Location: 48,50 + Owner: Atreides + Actor73: spicebloom + Location: 39,51 + Owner: Neutral + Actor74: barracks + Location: 52,52 + Owner: Atreides + Actor75: trike + Location: 54,52 + Owner: Atreides + Actor76: quad + Location: 51,53 + Owner: Atreides + Actor77: light_inf + Location: 57,53 + Owner: Atreides + Actor79: wind_trap + Location: 59,54 + Owner: Atreides + Actor80: wind_trap + Location: 62,54 + Owner: Atreides + Actor81: trooper + Location: 51,55 + Owner: Atreides + Actor84: light_inf + Location: 57,57 + Owner: Atreides + Actor85: light_inf + Location: 52,58 + Owner: Atreides + Actor86: spicebloom + Location: 17,62 + Owner: Neutral + HarkonnenConstructionYard: construction_yard + Location: 9,11 + Owner: Harkonnen + HarkonnenBarracks: barracks.harkonnen + Location: 3,3 + Owner: Harkonnen + HarkonnenWindTrap1: wind_trap + Location: 5,3 + Owner: Harkonnen + HarkonnenWindTrap2: wind_trap + Location: 7,3 + Owner: Harkonnen + HarkonnenWindTrap3: wind_trap + Location: 23,12 + Owner: Harkonnen + HarkonnenWindTrap4: wind_trap + Location: 26,14 + Owner: Harkonnen + HarkonnenWindTrap5: wind_trap + Location: 13,17 + Owner: Harkonnen + HarkonnenWindTrap6: wind_trap + Location: 10,19 + Owner: Harkonnen + HarkonnenWindTrap7: wind_trap + Location: 20,19 + Owner: Harkonnen + HarkonnenWindTrap8: wind_trap + Location: 18,23 + Owner: Harkonnen + HarkonnenSilo1: silo + Location: 9,3 + Owner: Harkonnen + HarkonnenSilo2: silo + Location: 18,15 + Owner: Harkonnen + HarkonnenSilo3: silo + Location: 21,18 + Owner: Harkonnen + HarkonnenSilo4: silo + Location: 26,13 + Owner: Harkonnen + HarkonnenGunTurret1: medium_gun_turret + Location: 4,8 + Owner: Harkonnen + HarkonnenGunTurret2: medium_gun_turret + Location: 27,11 + Owner: Harkonnen + HarkonnenGunTurret3: medium_gun_turret + Location: 33,20 + Owner: Harkonnen + HarkonnenGunTurret4: medium_gun_turret + Location: 35,20 + Owner: Harkonnen + HarkonnenGunTurret5: medium_gun_turret + Location: 9,23 + Owner: Harkonnen + HarkonnenGunTurret6: medium_gun_turret + Location: 24,24 + Owner: Harkonnen + HarkonnenGunTurret7: medium_gun_turret + Location: 15,26 + Owner: Harkonnen + HarkonnenHeavyFactory: heavy_factory + Location: 19,14 + Owner: Harkonnen + HarkonnenRefinery: refinery + Location: 23,15 + Owner: Harkonnen + HarkonnenOutpost: outpost + Location: 16,17 + Owner: Harkonnen + HarkonnenLightFactory: light_factory + Location: 17,20 + Owner: Harkonnen + Starport: starport + Location: 61,21 + Owner: Smugglers + SmugglerWindTrap1: wind_trap + Location: 61,17 + Owner: Smugglers + SmugglerWindTrap2: wind_trap + Location: 63,17 + Owner: Smugglers + ARefinery: refinery + Location: 54,57 + Owner: Atreides + Engineer1: engineer + Location: 56,54 + Owner: Atreides + Engineer2: engineer + Location: 52,56 + Owner: Atreides + ContrabandEntry: waypoint + Owner: Neutral + Location: 65,22 + ContrabandExit: waypoint + Owner: Neutral + Location: 2,22 + SmugglerWaypoint1: waypoint + Owner: Neutral + Location: 51,28 + SmugglerWaypoint2: waypoint + Owner: Neutral + Location: 57,29 + SmugglerWaypoint3: waypoint + Owner: Neutral + Location: 64,36 + AtreidesEntry: waypoint + Owner: Neutral + Location: 65,58 + AtreidesRally: waypoint + Owner: Neutral + Location: 54,56 + HarkonnenEntry1: waypoint + Owner: Neutral + Location: 25,2 + HarkonnenEntry2: waypoint + Owner: Neutral + Location: 38,65 + HarkonnenEntry3: waypoint + Owner: Neutral + Location: 65,32 + HarkonnenRally1: waypoint + Owner: Neutral + Location: 12,9 + HarkonnenRally2: waypoint + Owner: Neutral + Location: 39,41 + HarkonnenRally3: waypoint + Owner: Neutral + Location: 36,46 + HarkonnenRally4: waypoint + Owner: Neutral + Location: 49,4 + +Rules: d2k|rules/campaign-rules.yaml, rules.yaml diff --git a/mods/d2k/maps/atreides-05/rules.yaml b/mods/d2k/maps/atreides-05/rules.yaml new file mode 100644 index 0000000000..b7524a1976 --- /dev/null +++ b/mods/d2k/maps/atreides-05/rules.yaml @@ -0,0 +1,78 @@ +Player: + PlayerResources: + DefaultCash: 7000 + +World: + LuaScript: + Scripts: 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 + MapOptions: + TechLevel: medium + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: easy + +carryall.reinforce: + Cargo: + MaxWeight: 10 + +frigate: + Aircraft: + LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune, Concrete + CanHover: true # The frigate would teleport to land otherwise + +barracks.harkonnen: + Inherits: barracks + Buildable: + Prerequisites: ~disabled + -MustBeDestroyed: + AutoTargetIgnore: + +starport: + ExternalCondition@lua: + Condition: captured + AutoTargetIgnore: + RequiresCondition: !captured + +concreteb: + Buildable: + Prerequisites: ~disabled + +upgrade.conyard: + Buildable: + Prerequisites: ~disabled + +grenadier: + Buildable: + Prerequisites: ~disabled + +sardaukar: + Buildable: + Prerequisites: ~disabled + +large_gun_turret: + Buildable: + Prerequisites: ~disabled + +research_centre: + Buildable: + Prerequisites: outpost, heavy_factory, upgrade.heavy + +siege_tank: + Buildable: + Prerequisites: ~disabled + +missile_tank: + Buildable: + Prerequisites: upgrade.heavy, research_centre + +combat_tank_o.starport: + Buildable: + Prerequisites: starport diff --git a/mods/d2k/missions.yaml b/mods/d2k/missions.yaml index dd5ef68355..6fa9589aae 100644 --- a/mods/d2k/missions.yaml +++ b/mods/d2k/missions.yaml @@ -6,6 +6,7 @@ Atreides Campaign: ./mods/d2k/maps/atreides-03a ./mods/d2k/maps/atreides-03b ./mods/d2k/maps/atreides-04 + ./mods/d2k/maps/atreides-05 Ordos Campaign: ./mods/d2k/maps/ordos-01a