diff --git a/mods/d2k/maps/atreides-04/atreides04-AI.lua b/mods/d2k/maps/atreides-04/atreides04-AI.lua new file mode 100644 index 0000000000..7864f08181 --- /dev/null +++ b/mods/d2k/maps/atreides-04/atreides04-AI.lua @@ -0,0 +1,161 @@ +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" } +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, IdleHunt) + + if #units > 0 then + Media.DisplayMessage("Harkonnen units approaching!", "Fremen Leader") + 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 + +InitAIUnits = function() + IdlingUnits = 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) +end + +ActivateAI = function() + InitAIUnits() + FremenProduction() + + ProduceInfantry() + ProduceTanks() +end diff --git a/mods/d2k/maps/atreides-04/atreides04.lua b/mods/d2k/maps/atreides-04/atreides04.lua new file mode 100644 index 0000000000..591039e61d --- /dev/null +++ b/mods/d2k/maps/atreides-04/atreides04.lua @@ -0,0 +1,240 @@ +HarkonnenBase = { HarkonnenOutpost, HarkonnenRefinery, HarkonnenHeavyFact, HarkonnenTurret1, HarkonnenTurret2, HarkonnenBarracks, HarkonnenSilo1, HarkonnenSilo2, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5 } + +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" } + } +} + +HarkonnenAttackDelay = +{ + easy = DateTime.Minutes(3), + normal = DateTime.Minutes(2) + DateTime.Seconds(20), + hard = DateTime.Minutes(1) +} + +HarkonnenAttackWaves = +{ + easy = 5, + normal = 7, + hard = 9 +} + +InitialHarkonnenReinforcements = { "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" } + +HarkonnenPaths = +{ + { HarkonnenEntry1.Location, HarkonnenRally3.Location }, + { HarkonnenEntry2.Location, HarkonnenRally2.Location }, + { HarkonnenEntry3.Location, HarkonnenRally4.Location }, + { HarkonnenEntry4.Location, HarkonnenRally4.Location } +} + +AtreidesReinforcements = +{ + { "trike", "combat_tank_a", "combat_tank_a" }, + { "quad", "combat_tank_a", "combat_tank_a" } +} +AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location } + +FremenInterval = +{ + easy = { DateTime.Minutes(1) + DateTime.Seconds(30), DateTime.Minutes(2) }, + normal = { DateTime.Minutes(2) + DateTime.Seconds(20), DateTime.Minutes(2) + DateTime.Seconds(40) }, + hard = { DateTime.Minutes(3) + DateTime.Seconds(40), DateTime.Minutes(4) } +} + +IntegrityLevel = +{ + easy = 50, + normal = 75, + 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 + end + + local delay = Utils.RandomInteger(FremenInterval[Difficulty][1], FremenInterval[Difficulty][2] + 1) + fremen.Build({ "nsfremen" }, function() + Trigger.AfterDelay(delay, ProduceInfantry) + end) +end + +AttackNotifier = 0 +Tick = function() + if player.HasNoRequiredUnits() then + harkonnen.MarkCompletedObjective(KillAtreides) + end + + if harkonnen.HasNoRequiredUnits() and not player.IsObjectiveCompleted(KillHarkonnen) then + Media.DisplayMessage("The Harkonnen have been annihilated!", "Mentat") + player.MarkCompletedObjective(KillHarkonnen) + player.MarkCompletedObjective(ProtectFremen) + player.MarkCompletedObjective(KeepIntegrity) + end + + if DateTime.GameTime % DateTime.Seconds(30) and HarvesterKilled then + local units = harkonnen.GetActorsByType("harvester") + + if #units > 0 then + HarvesterKilled = false + ProtectHarvester(units[1]) + end + end + + if not Sietch.IsDead then + AttackNotifier = AttackNotifier - 1 + local integrity = math.floor((Sietch.Health * 100) / Sietch.MaxHealth) + UserInterface.SetMissionText("Sietch structural integrity: " .. integrity .. "%", player.Color) + + if integrity < IntegrityLevel[Difficulty] then + player.MarkFailedObjective(KeepIntegrity) + end + end +end + +WorldLoaded = function() + harkonnen = Player.GetPlayer("Harkonnen") + fremen = Player.GetPlayer("Fremen") + player = Player.GetPlayer("Atreides") + + Difficulty = Map.LobbyOption("difficulty") + + InitObjectives() + + Camera.Position = AConyard.CenterPosition + HarkonnenAttackLocation = AConyard.Location + + Trigger.AfterDelay(DateTime.Seconds(2), function() + Beacon.New(player, Sietch.CenterPosition + WVec.New(0, 1024, 0)) + Media.DisplayMessage("Fremen Sietch detected to the southeast.", "Mentat") + end) + + Trigger.OnAllKilledOrCaptured(HarkonnenBase, function() + Utils.Do(harkonnen.GetGroundAttackers(), IdleHunt) + end) + + Trigger.OnKilled(Sietch, function() + UserInterface.SetMissionText("Sietch destroyed!", player.Color) + player.MarkFailedObjective(ProtectFremen) + end) + Trigger.OnDamaged(Sietch, function() + if AttackNotifier <= 0 then + AttackNotifier = DateTime.Seconds(10) + Beacon.New(player, Sietch.CenterPosition + WVec.New(0, 1024, 0), DateTime.Seconds(7)) + Media.DisplayMessage("The Fremen Sietch is under attack!", "Mentat") + + local defenders = fremen.GetGroundAttackers() + if #defenders > 0 then + Utils.Do(defenders, function(unit) + unit.Guard(Sietch) + end) + end + end + end) + + SendHarkonnen() + Actor.Create("upgrade.barracks", true, { Owner = harkonnen }) + Trigger.AfterDelay(0, ActivateAI) + + Trigger.AfterDelay(DateTime.Seconds(50), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.Reinforce(player, AtreidesReinforcements[1], AtreidesPath) + end) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(40), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", AtreidesReinforcements[2], AtreidesPath, { AtreidesPath[1] }) + end) + + Trigger.OnEnteredProximityTrigger(HarkonnenRally1.CenterPosition, WDist.New(6 * 1024), function(a, id) + if a.Owner == player then + Trigger.RemoveProximityTrigger(id) + local units = Reinforcements.Reinforce(harkonnen, { "light_inf", "combat_tank_h", "trike" }, HarkonnenPaths[1]) + Utils.Do(units, IdleHunt) + 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 diff --git a/mods/d2k/maps/atreides-04/map.bin b/mods/d2k/maps/atreides-04/map.bin new file mode 100644 index 0000000000..c2d08db18a Binary files /dev/null and b/mods/d2k/maps/atreides-04/map.bin differ diff --git a/mods/d2k/maps/atreides-04/map.png b/mods/d2k/maps/atreides-04/map.png new file mode 100644 index 0000000000..f25f5957a1 Binary files /dev/null and b/mods/d2k/maps/atreides-04/map.png differ diff --git a/mods/d2k/maps/atreides-04/map.yaml b/mods/d2k/maps/atreides-04/map.yaml new file mode 100644 index 0000000000..c565a710a8 --- /dev/null +++ b/mods/d2k/maps/atreides-04/map.yaml @@ -0,0 +1,415 @@ +MapFormat: 11 + +RequiresMod: d2k + +Title: Atreides 04 + +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: Atreides, Harkonnen, Fremen + PlayerReference@Atreides: + Name: Atreides + Playable: True + LockFaction: True + Faction: atreides + LockColor: True + Color: 9191FF + Allies: Fremen + Enemies: Harkonnen, Creeps + PlayerReference@Harkonnen: + Name: Harkonnen + LockFaction: True + Faction: harkonnen + LockColor: True + Color: FE0000 + Enemies: Atreides, Creeps, Fremen + PlayerReference@Fremen: + Name: Fremen + LockFaction: True + Faction: fremen + LockColor: True + Color: DDDDDD + Allies: Atreides + Enemies: Harkonnen, Creeps + +Actors: + Actor0: wormspawner + Location: 63,7 + Owner: Creeps + Actor1: trike + Location: 17,11 + Owner: Harkonnen + Actor2: spicebloom + Location: 20,12 + Owner: Neutral + Actor3: spicebloom + Location: 24,14 + Owner: Neutral + Actor4: spicebloom + Location: 40,22 + Owner: Neutral + Actor5: spicebloom + Location: 57,24 + Owner: Neutral + Actor6: trike + Location: 6,25 + Owner: Atreides + Actor7: trike + Location: 10,26 + Owner: Atreides + Actor9: combat_tank_a + Location: 10,29 + Owner: Atreides + Actor10: combat_tank_a + Location: 12,29 + Owner: Atreides + Actor11: spicebloom + Location: 46,29 + Owner: Neutral + Actor12: light_inf + Location: 6,30 + Owner: Atreides + Actor13: quad + Location: 8,30 + Owner: Atreides + Actor14: light_inf + Location: 10,30 + Owner: Atreides + Actor15: light_inf + Location: 4,31 + Owner: Atreides + Actor16: combat_tank_a + Location: 11,31 + Owner: Atreides + Actor17: combat_tank_a + Location: 9,32 + Owner: Atreides + Actor18: combat_tank_a + Location: 10,32 + Owner: Atreides + Actor19: combat_tank_a + Location: 8,33 + Owner: Atreides + Actor20: light_inf + Location: 35,33 + Owner: Harkonnen + Actor21: light_inf + Location: 33,34 + Owner: Harkonnen + Actor22: spicebloom + Location: 59,34 + Owner: Neutral + Actor23: wall + Location: 42,35 + Owner: Harkonnen + Actor24: wall + Location: 43,35 + Owner: Harkonnen + Actor25: wall + Location: 44,35 + Owner: Harkonnen + Actor26: wall + Location: 45,35 + Owner: Harkonnen + Actor28: wall + Location: 46,36 + Owner: Harkonnen + Actor29: wall + Location: 46,37 + Owner: Harkonnen + Actor30: trooper + Location: 63,39 + Owner: Harkonnen + Actor31: trooper + Location: 51,40 + Owner: Harkonnen + Actor32: trooper + Location: 60,41 + Owner: Harkonnen + Actor35: light_inf + Location: 56,42 + Owner: Harkonnen + Actor37: light_inf + Location: 54,43 + Owner: Harkonnen + Actor38: wall + Location: 57,44 + Owner: Harkonnen + Actor39: wall + Location: 58,44 + Owner: Harkonnen + Actor40: wall + Location: 59,44 + Owner: Harkonnen + Actor41: wall + Location: 60,44 + Owner: Harkonnen + Actor42: wall + Location: 61,44 + Owner: Harkonnen + Actor43: wall + Location: 62,44 + Owner: Harkonnen + Actor44: wall + Location: 63,44 + Owner: Harkonnen + Actor45: wall + Location: 64,44 + Owner: Harkonnen + Actor46: wall + Location: 65,44 + Owner: Harkonnen + Actor47: wall + Location: 52,45 + Owner: Harkonnen + Actor48: wall + Location: 53,45 + Owner: Harkonnen + Actor49: wall + Location: 54,45 + Owner: Harkonnen + Actor50: wall + Location: 55,45 + Owner: Harkonnen + Actor51: wall + Location: 56,45 + Owner: Harkonnen + Actor52: wall + Location: 57,45 + Owner: Harkonnen + Actor55: wall + Location: 35,48 + Owner: Harkonnen + Actor56: wall + Location: 35,49 + Owner: Harkonnen + Actor58: wall + Location: 35,50 + Owner: Harkonnen + Actor61: wall + Location: 46,50 + Owner: Harkonnen + Actor64: wall + Location: 46,51 + Owner: Harkonnen + Actor65: nsfremen + Location: 59,51 + Owner: Fremen + Actor66: nsfremen + Location: 64,51 + Owner: Fremen + Actor67: trike + Location: 23,52 + Owner: Harkonnen + Actor68: wall + Location: 46,52 + Owner: Harkonnen + Actor69: nsfremen + Location: 60,52 + Owner: Fremen + Actor70: nsfremen + Location: 62,52 + Owner: Fremen + Actor71: wall + Location: 46,53 + Owner: Harkonnen + Actor72: nsfremen + Location: 63,53 + Owner: Fremen + Actor73: wall + Location: 46,54 + Owner: Harkonnen + Actor74: nsfremen + Location: 56,54 + Owner: Fremen + Actor75: nsfremen + Location: 57,54 + Owner: Fremen + Actor76: nsfremen + Location: 64,54 + Owner: Fremen + Actor77: wind_trap + Location: 40,55 + Owner: Harkonnen + Actor80: wall + Location: 46,55 + Owner: Harkonnen + Actor81: nsfremen + Location: 55,55 + Owner: Fremen + Actor82: wall + Location: 36,56 + Owner: Harkonnen + Actor83: wall + Location: 46,56 + Owner: Harkonnen + Actor84: nsfremen + Location: 55,56 + Owner: Fremen + Actor85: wall + Location: 36,57 + Owner: Harkonnen + Actor86: wall + Location: 46,57 + Owner: Harkonnen + Actor87: nsfremen + Location: 57,57 + Owner: Fremen + Actor88: nsfremen + Location: 60,57 + Owner: Fremen + Actor89: nsfremen + Location: 64,57 + Owner: Fremen + Actor90: wall + Location: 36,58 + Owner: Harkonnen + Actor91: wall + Location: 37,58 + Owner: Harkonnen + Actor92: wall + Location: 38,58 + Owner: Harkonnen + Actor93: wall + Location: 39,58 + Owner: Harkonnen + Actor94: wall + Location: 40,58 + Owner: Harkonnen + Actor95: wall + Location: 41,58 + Owner: Harkonnen + Actor96: wall + Location: 42,58 + Owner: Harkonnen + Actor97: wall + Location: 43,58 + Owner: Harkonnen + Actor98: wall + Location: 44,58 + Owner: Harkonnen + Actor99: wall + Location: 45,58 + Owner: Harkonnen + Actor100: wall + Location: 46,58 + Owner: Harkonnen + Actor101: nsfremen + Location: 55,59 + Owner: Fremen + Actor103: spicebloom + Location: 9,60 + Owner: Neutral + Actor104: nsfremen + Location: 55,61 + Owner: Fremen + Actor105: nsfremen + Location: 58,62 + Owner: Fremen + Actor106: nsfremen + Location: 65,63 + Owner: Fremen + HarkonnenOutpost: outpost + Location: 62,41 + Owner: Harkonnen + HarkonnenRefinery: refinery + Location: 43,43 + Owner: Harkonnen + HarkonnenHeavyFact: heavy_factory + Location: 43,46 + Owner: Harkonnen + HarkonnenTurret1: medium_gun_turret + Location: 46,35 + Owner: Harkonnen + HarkonnenTurret2: medium_gun_turret + Location: 35,47 + Owner: Harkonnen + HarkonnenBarracks: barracks + Location: 42,50 + Owner: Harkonnen + HarkonnenSilo1: silo + Location: 39,50 + Owner: Harkonnen + HarkonnenSilo2: silo + Location: 44,51 + Owner: Harkonnen + HarkonnenWindTrap1: wind_trap + Location: 37,49 + Owner: Harkonnen + HarkonnenWindTrap2: wind_trap + Location: 39,51 + Owner: Harkonnen + HarkonnenWindTrap3: wind_trap + Location: 42,55 + Owner: Harkonnen + HarkonnenWindTrap4: wind_trap + Location: 44,55 + Owner: Harkonnen + HarkonnenWindTrap5: wind_trap + Location: 52,42 + Owner: Harkonnen + AConyard: construction_yard + Location: 5,27 + Owner: Atreides + Sietch: sietch + Location: 62,59 + Owner: Fremen + HackyTile: tile475 + Location: 62,59 + Owner: Neutral + HarkonnenEntry1: waypoint + Owner: Neutral + Location: 65,35 + HarkonnenEntry2: waypoint + Owner: Neutral + Location: 14,65 + HarkonnenEntry3: waypoint + Owner: Neutral + Location: 31,2 + HarkonnenEntry4: waypoint + Owner: Neutral + Location: 10,2 + HarkonnenRally1: waypoint + Owner: Neutral + Location: 48,46 + HarkonnenRally2: waypoint + Owner: Neutral + Location: 16,39 + HarkonnenRally3: waypoint + Owner: Neutral + Location: 52,40 + HarkonnenRally4: waypoint + Owner: Neutral + Location: 8,6 + AtreidesEntry: waypoint + Owner: Neutral + Location: 2,18 + AtreidesRally: waypoint + Owner: Neutral + Location: 5,23 + +Rules: d2k|rules/campaign-rules.yaml, rules.yaml + +Sequences: sequences.yaml diff --git a/mods/d2k/maps/atreides-04/rules.yaml b/mods/d2k/maps/atreides-04/rules.yaml new file mode 100644 index 0000000000..2671ac81e8 --- /dev/null +++ b/mods/d2k/maps/atreides-04/rules.yaml @@ -0,0 +1,90 @@ +Player: + PlayerResources: + DefaultCash: 6000 + +World: + LuaScript: + Scripts: 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 + MapOptions: + TechLevel: low + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: easy + +carryall.reinforce: + Cargo: + MaxWeight: 10 + +sietch: + Exit: + ExitCell: 0,2 + Production: + Produces: Infantry + +nsfremen: + Buildable: + Prerequisites: ~sietch + AutoTarget: + InitialStanceAI: AttackAnything + +concreteb: + Buildable: + Prerequisites: ~disabled + +medium_gun_turret: + Buildable: + Prerequisites: ~disabled + +outpost: + Buildable: + Prerequisites: barracks + +quad: + Buildable: + Prerequisites: upgrade.light + +trooper: + Buildable: + Prerequisites: upgrade.barracks + +engineer: + Buildable: + Prerequisites: upgrade.barracks + +repair_pad: + Buildable: + Prerequisites: heavy_factory, upgrade.heavy + +mcv: + Buildable: + Prerequisites: repair_pad, upgrade.heavy + +upgrade.conyard: + Buildable: + Prerequisites: ~disabled + +# HACK: AI units can't attack the sietch if it was on a real rock +tile475: + AlwaysVisible: + Immobile: + OccupiesSpace: false + RenderSprites: + Palette: d2k + WithIdleOverlay@2: + Sequence: idle2 + WithIdleOverlay@3: + Sequence: idle3 + WithIdleOverlay@4: + Sequence: idle4 + WithSpriteBody: + BodyOrientation: + QuantizedFacings: 1 + AutoSelectionSize: diff --git a/mods/d2k/maps/atreides-04/sequences.yaml b/mods/d2k/maps/atreides-04/sequences.yaml new file mode 100644 index 0000000000..c375c335a5 --- /dev/null +++ b/mods/d2k/maps/atreides-04/sequences.yaml @@ -0,0 +1,14 @@ +tile475: + Defaults: BLOXWAST.R8 + idle: + Start: 706 + Offset: -16,-16 + idle2: + Start: 707 + Offset: 16,-16 + idle3: + Start: 726 + Offset: -16,16 + idle4: + Start: 727 + Offset: 16,16 diff --git a/mods/d2k/missions.yaml b/mods/d2k/missions.yaml index 97df7fccb7..415c9dcf80 100644 --- a/mods/d2k/missions.yaml +++ b/mods/d2k/missions.yaml @@ -5,6 +5,7 @@ Atreides Campaign: ./mods/d2k/maps/atreides-02b ./mods/d2k/maps/atreides-03a ./mods/d2k/maps/atreides-03b + ./mods/d2k/maps/atreides-04 Ordos Campaign: ./mods/d2k/maps/ordos-01a diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index 756159d03b..48cd52cfca 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -43,6 +43,10 @@ Name: Smugglers InternalName: smuggler Selectable: false + Faction@Fremen: + Name: Fremen + InternalName: fremen + Selectable: false ResourceType@Spice: Type: Spice Name: Spice