--[[ Copyright 2007-2019 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. ]] DeathThreshold = { easy = 200, normal = 100, } TanyaType = "e7" if Map.LobbyOption("difficulty") ~= "easy" then TanyaType = "e7.noautotarget" end RepairTriggerThreshold = { easy = 50, normal = 75, } Sams = { Sam1, Sam2, Sam3, Sam4 } TownUnits = { Einstein, Engineer, TownUnit01, TownUnit02, TownUnit03, TownUnit04, TownUnit05, TownUnit06, TownUnit07, TownUnit08, TownUnit09, TownUnit10, TownUnit11, TownUnit12, TownUnit13, TownUnit14, } ParabombDelay = DateTime.Seconds(30) ParatroopersDelay = DateTime.Minutes(5) Paratroopers = { { proxy = "powerproxy.paras1", entry = BadgerEntryPoint1.Location, drop = BadgerDropPoint1.Location, }, { proxy = "powerproxy.paras2", entry = BadgerEntryPoint1.Location + CVec.New(3, 0), drop = BadgerDropPoint2.Location, }, { proxy = "powerproxy.paras2", entry = BadgerEntryPoint1.Location + CVec.New(6, 0), drop = BadgerDropPoint3.Location, }, } AttackGroup = { } AttackGroupSize = 5 SovietInfantry = { "e1", "e2", "e3" } SovietVehiclesUpgradeDelay = DateTime.Minutes(4) SovietVehicleType = "Normal" SovietVehicles = { Normal = { "3tnk" }, Upgraded = { "3tnk", "v2rl" }, } ProductionInterval = { easy = DateTime.Seconds(10), normal = DateTime.Seconds(2), } ReinforcementsDelay = DateTime.Minutes(16) ReinforcementsUnits = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "1tnk", "1tnk", "jeep", "e1", "e1", "e1", "e1", "e3", "e3", "mcv", "truk", "truk", "truk", "truk", "truk", "truk" } SpawnAlliedReinforcements = function() if allies2.IsLocalPlayer then UserInterface.SetMissionText("") Media.PlaySpeechNotification(allies2, "AlliedReinforcementsArrived") end Reinforcements.Reinforce(allies2, ReinforcementsUnits, { ReinforcementsEntryPoint.Location, Allies2BasePoint.Location }) end Yak = nil YakAttack = function() local targets = Map.ActorsInCircle(YakAttackPoint.CenterPosition, WDist.FromCells(10), function(a) return a.Owner == allies1 and not a.IsDead and a ~= Einstein and a ~= Tanya and a ~= Engineer and Yak.CanTarget(a) end) if (#targets > 0) then Yak.Attack(Utils.Random(targets)) end Yak.Move(Map.ClosestEdgeCell(Yak.Location)) Yak.Destroy() Trigger.OnRemovedFromWorld(Yak, function() Yak = nil end) end SovietTownAttack = function() local units = Utils.Shuffle(Utils.Where(Map.ActorsWithTag("TownAttacker"), function(a) return not a.IsDead end)) Utils.Do(Utils.Take(5, units), function(unit) unit.AttackMove(TownPoint.Location) Trigger.OnIdle(unit, unit.Hunt) end) end SendParabombs = function() local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = soviets }) proxy.SendAirstrikeFrom(BadgerEntryPoint2.Location, ParabombPoint1.Location) proxy.SendAirstrikeFrom(BadgerEntryPoint2.Location + CVec.New(0, 3), ParabombPoint2.Location) proxy.Destroy() end SendParatroopers = function() Utils.Do(Paratroopers, function(para) local proxy = Actor.Create(para.proxy, false, { Owner = soviets }) local units = proxy.SendParatroopersFrom(para.entry, para.drop) proxy.Destroy() Utils.Do(units, function(unit) Trigger.OnIdle(unit, function(a) if a.IsInWorld then a.Hunt() end end) end) end) end SendAttackGroup = function() if #AttackGroup < AttackGroupSize then return end Utils.Do(AttackGroup, function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end) AttackGroup = { } end ProduceInfantry = function() if SovietBarracks.IsDead or SovietBarracks.Owner ~= soviets then return end soviets.Build({ Utils.Random(SovietInfantry) }, function(units) table.insert(AttackGroup, units[1]) SendAttackGroup() Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceInfantry) end) end ProduceVehicles = function() if SovietWarFactory.IsDead or SovietWarFactory.Owner ~= soviets then return end soviets.Build({ Utils.Random(SovietVehicles[SovietVehicleType]) }, function(units) table.insert(AttackGroup, units[1]) SendAttackGroup() Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles) end) end NumBaseBuildings = function() local buildings = Map.ActorsInBox(AlliedBaseTopLeft.CenterPosition, AlliedBaseBottomRight.CenterPosition, function(a) return not a.IsDead and a.Owner == allies2 and a.HasProperty("StartBuildingRepairs") end) return #buildings end Tick = function() if DateTime.GameTime > 1 and DateTime.GameTime % 25 == 0 and NumBaseBuildings() == 0 then allies2.MarkFailedObjective(objHoldPosition) end if not allies2.IsObjectiveCompleted(objCutSovietPower) and soviets.PowerState ~= "Normal" then allies2.MarkCompletedObjective(objCutSovietPower) end if not allies2.IsObjectiveCompleted(objLimitLosses) and allies2.UnitsLost > DeathThreshold[Map.LobbyOption("difficulty")] then allies2.MarkFailedObjective(objLimitLosses) end if allies2.IsLocalPlayer and DateTime.GameTime <= ReinforcementsDelay then UserInterface.SetMissionText("Allied reinforcements arrive in " .. Utils.FormatTime(ReinforcementsDelay - DateTime.GameTime)) else UserInterface.SetMissionText("") end end SetupSoviets = function() soviets.Cash = 1000 if Map.LobbyOption("difficulty") == "easy" then Utils.Do(Sams, function(sam) local camera = Actor.Create("Camera.SAM", true, { Owner = allies1, Location = sam.Location }) Trigger.OnKilledOrCaptured(sam, function() camera.Destroy() end) end) end local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == soviets and self.HasProperty("StartBuildingRepairs") end) Utils.Do(buildings, function(actor) Trigger.OnDamaged(actor, function(building) if building.Owner == soviets and building.Health < (building.MaxHealth * RepairTriggerThreshold[Map.LobbyOption("difficulty")] / 100) then building.StartBuildingRepairs() end end) end) SovietBarracks.IsPrimaryBuilding = true SovietBarracks.RallyPoint = SovietRallyPoint.Location SovietWarFactory.IsPrimaryBuilding = true SovietWarFactory.RallyPoint = SovietRallyPoint.Location Trigger.AfterDelay(SovietVehiclesUpgradeDelay, function() SovietVehicleType = "Upgraded" end) Trigger.AfterDelay(0, function() ProduceInfantry() ProduceVehicles() end) end SetupTriggers = function() Trigger.OnKilled(Tanya, function() allies1.MarkFailedObjective(objTanyaMustSurvive) end) Trigger.OnAllKilledOrCaptured(Sams, function() allies1.MarkCompletedObjective(objDestroySamSites) objExtractEinstein = allies1.AddPrimaryObjective("Wait for a helicopter at the LZ and extract Einstein.") Actor.Create("flare", true, { Owner = allies1, Location = ExtractionLZ.Location + CVec.New(1, -1) }) Beacon.New(allies1, ExtractionLZ.CenterPosition) Media.PlaySpeechNotification(allies1, "SignalFlareNorth") ExtractionHeli = Reinforcements.ReinforceWithTransport(allies1, "tran", nil, { ExtractionLZEntryPoint.Location, ExtractionLZ.Location })[1] Trigger.OnKilled(ExtractionHeli, function() allies1.MarkFailedObjective(objExtractEinstein) end) Trigger.OnPassengerEntered(ExtractionHeli, function(heli, passenger) if passenger == Einstein then heli.Move(ExtractionLZEntryPoint.Location) heli.Destroy() Trigger.OnRemovedFromWorld(heli, function() allies2.MarkCompletedObjective(objLimitLosses) allies2.MarkCompletedObjective(objHoldPosition) allies1.MarkCompletedObjective(objTanyaMustSurvive) allies1.MarkCompletedObjective(objEinsteinSurvival) allies1.MarkCompletedObjective(objExtractEinstein) end) end end) end) Trigger.OnEnteredProximityTrigger(TownPoint.CenterPosition, WDist.FromCells(15), function(actor, trigger) if actor.Owner == allies1 then ReassignActors(TownUnits, neutral, allies1) Utils.Do(TownUnits, function(a) a.Stance = "Defend" end) allies1.MarkCompletedObjective(objFindEinstein) objEinsteinSurvival = allies1.AddPrimaryObjective("Keep Einstein alive at all costs.") Trigger.OnKilled(Einstein, function() allies1.MarkFailedObjective(objEinsteinSurvival) end) Trigger.RemoveProximityTrigger(trigger) SovietTownAttack() end end) Trigger.OnEnteredProximityTrigger(YakAttackPoint.CenterPosition, WDist.FromCells(5), function(actor, trigger) if not (Yak == nil or Yak.IsDead) or actor.Owner ~= allies1 then return end Yak = Actor.Create("yak", true, { Owner = soviets, Location = YakEntryPoint.Location, CenterPosition = YakEntryPoint.CenterPosition + WVec.New(0, 0, Actor.CruiseAltitude("yak")) }) Yak.Move(YakAttackPoint.Location + CVec.New(0, -10)) Yak.CallFunc(YakAttack) end) Trigger.AfterDelay(ParabombDelay, SendParabombs) Trigger.AfterDelay(ParatroopersDelay, SendParatroopers) Trigger.AfterDelay(ReinforcementsDelay, SpawnAlliedReinforcements) end SpawnTanya = function() Tanya = Actor.Create(TanyaType, true, { Owner = allies1, Location = TanyaLocation.Location }) if Map.LobbyOption("difficulty") ~= "easy" and allies1.IsLocalPlayer then Trigger.AfterDelay(DateTime.Seconds(2), function() Media.DisplayMessage("According to the rules of engagement I need your explicit orders to fire, Commander!", "Tanya") end) end end ReassignActors = function(actors, from, to) Utils.Do(actors, function(a) if a.Owner == from then a.Owner = to a.Stance = "Defend" end end) end WorldLoaded = function() neutral = Player.GetPlayer("Neutral") -- Allies is the pre-set owner of units that get assigned to either the second player, if any, or the first player otherwise. allies = Player.GetPlayer("Allies") -- Allies1 is the player starting on the right, controlling Tanya allies1 = Player.GetPlayer("Allies1") -- Allies2 is the player starting on the left, defending the base allies2 = Player.GetPlayer("Allies2") soviets = Player.GetPlayer("Soviets") Utils.Do({ allies1, allies2 }, function(player) if player and player.IsLocalPlayer then 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.OnPlayerWon(player, function() Media.PlaySpeechNotification(player, "MissionAccomplished") end) Trigger.OnPlayerLost(player, function() Media.PlaySpeechNotification(player, "MissionFailed") end) end end) if not allies2 or allies2.IsLocalPlayer then Camera.Position = Allies2BasePoint.CenterPosition else Camera.Position = ChinookHusk.CenterPosition end if not allies2 then allies2 = allies1 end ReassignActors(Map.ActorsInWorld, allies, allies2) SpawnTanya() objTanyaMustSurvive = allies1.AddPrimaryObjective("Tanya must survive.") objFindEinstein = allies1.AddPrimaryObjective("Find Einstein's crashed helicopter.") objDestroySamSites = allies1.AddPrimaryObjective("Destroy the SAM sites.") objHoldPosition = allies2.AddPrimaryObjective("Hold your position and protect the base.") objLimitLosses = allies2.AddSecondaryObjective("Do not lose more than " .. DeathThreshold[Map.LobbyOption("difficulty")] .. " units.") objCutSovietPower = allies2.AddSecondaryObjective("Take out the Soviet power grid.") SetupTriggers() SetupSoviets() end