diff --git a/mods/d2k/maps/ordos-02b/map.bin b/mods/d2k/maps/ordos-02b/map.bin new file mode 100644 index 0000000000..4bf1a21b01 Binary files /dev/null and b/mods/d2k/maps/ordos-02b/map.bin differ diff --git a/mods/d2k/maps/ordos-02b/map.png b/mods/d2k/maps/ordos-02b/map.png new file mode 100644 index 0000000000..81ebd22878 Binary files /dev/null and b/mods/d2k/maps/ordos-02b/map.png differ diff --git a/mods/d2k/maps/ordos-02b/map.yaml b/mods/d2k/maps/ordos-02b/map.yaml new file mode 100644 index 0000000000..bc78c293ce --- /dev/null +++ b/mods/d2k/maps/ordos-02b/map.yaml @@ -0,0 +1,140 @@ +MapFormat: 11 + +RequiresMod: d2k + +Title: Ordos 02b + +Author: Westwood Studios + +Tileset: ARRAKIS + +MapSize: 52,52 + +Bounds: 2,2,48,48 + +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: Ordos, Harkonnen + PlayerReference@Ordos: + Name: Ordos + Playable: True + LockFaction: True + Faction: ordos + LockColor: True + Color: B3EAA5 + Enemies: Harkonnen, Creeps + PlayerReference@Harkonnen: + Name: Harkonnen + LockFaction: True + Faction: harkonnen + LockColor: True + Color: FE0000 + Enemies: Ordos + +Actors: + Actor0: light_inf + Location: 12,3 + Owner: Ordos + OPower1: wind_trap + Location: 15,3 + Owner: Ordos + OConyard: construction_yard + Location: 20,4 + Owner: Ordos + Actor3: light_inf + Location: 9,5 + Owner: Ordos + Actor4: light_inf + Location: 13,5 + Owner: Ordos + Actor5: light_inf + Location: 18,6 + Owner: Ordos + Actor6: raider + Location: 12,7 + Owner: Ordos + Actor7: raider + Location: 19,8 + Owner: Ordos + Actor8: light_inf + Location: 36,10 + Owner: Harkonnen + Actor9: light_inf + Location: 5,19 + Owner: Harkonnen + Actor10: light_inf + Location: 45,25 + Owner: Harkonnen + Actor11: light_inf + Location: 45,32 + Owner: Harkonnen + Actor12: light_inf + Location: 42,33 + Owner: Harkonnen + Actor13: light_inf + Location: 48,33 + Owner: Harkonnen + HPower1: wind_trap + Location: 38,36 + Owner: Harkonnen + HPower2: wind_trap + Location: 40,36 + Owner: Harkonnen + HOutpost: outpost + Location: 45,37 + Owner: Harkonnen + Actor17: light_inf + Location: 38,40 + Owner: Harkonnen + Actor18: light_inf + Location: 41,40 + Owner: Harkonnen + Actor19: light_inf + Location: 10,42 + Owner: Harkonnen + Actor20: wormspawner + Location: 17,42 + Owner: Creeps + HBarracks: barracks + Location: 39,42 + Owner: Harkonnen + HConyard: construction_yard + Location: 45,43 + Owner: Harkonnen + Actor23: trike + Location: 38,46 + Owner: Harkonnen + Actor24: trike + Location: 41,47 + Owner: Harkonnen + HarkonnenRally1: waypoint + Owner: Neutral + Location: 25,15 + HarkonnenEntry1: waypoint + Owner: Neutral + Location: 49,15 + HarkonnenRally2: waypoint + Owner: Neutral + Location: 14,13 + HarkonnenEntry2: waypoint + Owner: Neutral + Location: 31,49 + HarkonnenRally3: waypoint + Owner: Neutral + Location: 9,8 + +Rules: d2k|rules/campaign-rules.yaml, rules.yaml diff --git a/mods/d2k/maps/ordos-02b/ordos02b-AI.lua b/mods/d2k/maps/ordos-02b/ordos02b-AI.lua new file mode 100644 index 0000000000..00e5e4dcc7 --- /dev/null +++ b/mods/d2k/maps/ordos-02b/ordos02b-AI.lua @@ -0,0 +1,122 @@ +IdlingUnits = { } + +AttackGroupSize = +{ + easy = 6, + normal = 8, + hard = 10 +} +AttackDelays = +{ + easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, + normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, + hard = { DateTime.Seconds(1), DateTime.Seconds(5) } +} + +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() +end diff --git a/mods/d2k/maps/ordos-02b/ordos02b.lua b/mods/d2k/maps/ordos-02b/ordos02b.lua new file mode 100644 index 0000000000..02db573544 --- /dev/null +++ b/mods/d2k/maps/ordos-02b/ordos02b.lua @@ -0,0 +1,129 @@ + +HarkonnenBase = { HConyard, HPower1, HPower2, HBarracks, HOutpost } + +HarkonnenReinforcements = { } +HarkonnenReinforcements["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" }, +} + +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" } +} + +HarkonnenAttackPaths = +{ + { HarkonnenEntry1.Location, HarkonnenRally1.Location }, + { HarkonnenEntry1.Location, HarkonnenRally2.Location }, + { HarkonnenEntry2.Location, HarkonnenRally2.Location }, + { HarkonnenEntry2.Location, HarkonnenRally3.Location } +} + +HarkonnenAttackDelay = +{ + easy = DateTime.Minutes(5), + normal = DateTime.Minutes(2) + DateTime.Seconds(40), + hard = DateTime.Minutes(1) + DateTime.Seconds(20) +} + +HarkonnenAttackWaves = +{ + easy = 3, + normal = 6, + 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) + end + + if harkonnen.HasNoRequiredUnits() and not player.IsObjectiveCompleted(KillHarkonnen) then + Media.DisplayMessage("The Harkonnen have been annihilated!", "Mentat") + player.MarkCompletedObjective(KillHarkonnen) + end +end + +WorldLoaded = function() + harkonnen = Player.GetPlayer("Harkonnen") + player = Player.GetPlayer("Ordos") + + InitObjectives() + + Camera.Position = OConyard.CenterPosition + + Trigger.OnAllKilled(HarkonnenBase, function() + Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt) + end) + + SendHarkonnen() + 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 diff --git a/mods/d2k/maps/ordos-02b/rules.yaml b/mods/d2k/maps/ordos-02b/rules.yaml new file mode 100644 index 0000000000..c5f2ec3637 --- /dev/null +++ b/mods/d2k/maps/ordos-02b/rules.yaml @@ -0,0 +1,48 @@ +Player: + PlayerResources: + DefaultCash: 5000 + +World: + LuaScript: + Scripts: 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 + MapOptions: + TechLevel: low + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: easy + +carryall.reinforce: + Cargo: + MaxWeight: 10 + +construction_yard: + Production: + Produces: Building + +concreteb: + Buildable: + Prerequisites: ~disabled + +heavy_factory: + Buildable: + Prerequisites: ~disabled + +medium_gun_turret: + Buildable: + Prerequisites: ~disabled + +wall: + Buildable: + Prerequisites: ~disabled + +outpost: + Buildable: + Prerequisites: barracks diff --git a/mods/d2k/missions.yaml b/mods/d2k/missions.yaml index 30d11841de..dd5ef68355 100644 --- a/mods/d2k/missions.yaml +++ b/mods/d2k/missions.yaml @@ -11,6 +11,7 @@ Ordos Campaign: ./mods/d2k/maps/ordos-01a ./mods/d2k/maps/ordos-01b ./mods/d2k/maps/ordos-02a + ./mods/d2k/maps/ordos-02b Harkonnen Campaign: ./mods/d2k/maps/harkonnen-01a