#region Copyright & License Information /* * Copyright 2007-2013 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. For more information, * see COPYING. */ #endregion using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Missions { class Survival01ScriptInfo : TraitInfo, Requires { } class Survival01Script : IHasObjectives, IWorldLoaded, ITick { public event Action OnObjectivesUpdated = notify => { }; public IEnumerable Objectives { get { return new[] { maintainPresence, destroySoviets }; } } Objective maintainPresence = new Objective(ObjectiveType.Primary, MaintainPresenceText, ObjectiveStatus.InProgress); Objective destroySoviets = new Objective(ObjectiveType.Primary, DestroySovietsText, ObjectiveStatus.Inactive); const string MaintainPresenceText = "Enforce your position and hold-out the onslaught until reinforcements arrive. We must not lose the base!"; const string DestroySovietsText = "Take control of French reinforcements and dismantle the nearby Soviet base."; Player allies; Player soviets; Actor sovietEntryPoint1; Actor sovietEntryPoint2; Actor sovietEntryPoint3; Actor sovietEntryPoint4; Actor sovietEntryPoint5; CPos[] sovietEntryPoints; Actor sovietRallyPoint1; Actor sovietRallyPoint2; Actor sovietRallyPoint3; Actor sovietRallyPoint4; Actor sovietRallyPoint5; CPos[] sovietRallyPoints; Actor sovietinfantryentry1; Actor sovietinfantryrally1; Actor badgerEntryPoint1; Actor badgerEntryPoint2; Actor paraDrop1; Actor paraDrop2; Actor sovietEntryPoint7; Actor alliesbase1; Actor alliesbase2; Actor alliesbase; Actor sam1; Actor sam2; Actor barrack1; World world; CountdownTimer survivalTimer; CountdownTimerWidget survivalTimerWidget; int attackAtFrame; int attackAtFrameIncrement; int attackAtFrameInf; int attackAtFrameIncrementInf; const int paradropTicks = 750; static readonly string[] badger1Passengers = { "e1", "e1", "e1", "e2", "e2" }; const int factoryClearRange = 10; static readonly string[] squad1 = { "e1", "e1" }; static readonly string[] squad2 = { "e2", "e2" }; static readonly string[] sovietVehicles = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "v2rl", "v2rl", "ftrk", "ftrk", "ftrk", "apc", "apc" }; static readonly string[] sovietInfantry = { "e1", "e1", "e1", "e1", "e2", "e2", "e2", "e4", "e4", "e3", }; static readonly string[] reinforcements = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "1tnk", "1tnk", "1tnk", "arty", "arty", "arty", "jeep", "jeep" }; const int sovietAttackGroupSize = 5; const int sovietInfantryGroupSize = 7; const int timerTicks = 1500 * 25; bool spawningSovietUnits = true; bool spawningInfantry = true; string difficulty; void MissionAccomplished(string text) { MissionUtils.CoopMissionAccomplished(world, text, allies); } public void Tick(Actor self) { if (allies.WinState != WinState.Undefined) return; survivalTimer.Tick(); if (world.FrameNumber == attackAtFrame) { attackAtFrame += attackAtFrameIncrement; attackAtFrameIncrement = Math.Max(attackAtFrameIncrement - 5, 100); SpawnSovietUnits(); ManageSovietUnits(); MissionUtils.CapOre(soviets); } if (world.FrameNumber == attackAtFrameInf) { attackAtFrameInf += attackAtFrameIncrementInf; attackAtFrameIncrementInf = Math.Max(attackAtFrameIncrementInf - 5, 100); SpawnSovietInfantry(); } if (barrack1.Destroyed) { spawningInfantry = false; } if (world.FrameNumber == paradropTicks) { MissionUtils.Paradrop(world, soviets, badger1Passengers, badgerEntryPoint1.Location, paraDrop1.Location); MissionUtils.Paradrop(world, soviets, badger1Passengers, badgerEntryPoint2.Location, paraDrop2.Location); } if (world.FrameNumber == paradropTicks * 2) { MissionUtils.Paradrop(world, soviets, badger1Passengers, badgerEntryPoint1.Location, alliesbase2.Location); MissionUtils.Paradrop(world, soviets, badger1Passengers, badgerEntryPoint2.Location, alliesbase1.Location); } if (world.FrameNumber == 1500 * 23) { attackAtFrame = 100; attackAtFrameIncrement = 100; } if (world.FrameNumber == 1500 * 25) { spawningSovietUnits = false; spawningInfantry = false; } if (destroySoviets.Status == ObjectiveStatus.InProgress) { if (barrack1.Destroyed) { destroySoviets.Status = ObjectiveStatus.Completed; OnObjectivesUpdated(true); MissionAccomplished("The French forces have survived and dismantled the soviet presence in the area!"); } } } void SendSquad1() { for (int i = 0; i < squad1.Length; i++) { var actor = world.CreateActor(squad1[i], new TypeDictionary { new OwnerInit(soviets), new LocationInit(alliesbase1.Location + new CVec(-2 + i, -6 + i * 2)) }); actor.QueueActivity(new Move.Move(alliesbase1.Location)); } } void SendSquad2() { for (int i = 0; i < squad2.Length; i++) { var actor = world.CreateActor(squad2[i], new TypeDictionary { new OwnerInit(soviets), new LocationInit(alliesbase2.Location + new CVec(-9 + i, -2 + i * 2)) }); actor.QueueActivity(new Move.Move(alliesbase2.Location)); } } void SpawnSovietInfantry() { if (spawningInfantry) { var units = world.CreateActor((sovietInfantry).Random(world.SharedRandom), new TypeDictionary { new LocationInit(sovietinfantryentry1.Location), new OwnerInit(soviets) }); units.QueueActivity(new Move.Move(sovietinfantryrally1.Location, 3)); var unitsincircle = world.FindAliveCombatantActorsInCircle(sovietinfantryrally1.CenterPosition, WRange.FromCells(10)) .Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait()); if (unitsincircle.Count() >= sovietInfantryGroupSize) { foreach (var scatteredunits in unitsincircle) AttackNearestAlliedActor(scatteredunits); } } } void SpawnSovietUnits() { if (spawningSovietUnits) { var route = world.SharedRandom.Next(sovietEntryPoints.Length); var spawnPoint = sovietEntryPoints[route]; var rallyPoint = sovietRallyPoints[route]; var unit = world.CreateActor(sovietVehicles.Random(world.SharedRandom), new TypeDictionary { new LocationInit(spawnPoint), new OwnerInit(soviets) }); unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(rallyPoint, 3))); } } void AttackNearestAlliedActor(Actor self) { var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == allies) && ((u.HasTrait() && !u.HasTrait()) || u.HasTrait())); var targetEnemy = enemies.ClosestTo(self); if (targetEnemy != null) self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), WRange.FromCells(3)))); } void ManageSovietUnits() { foreach (var rallyPoint in sovietRallyPoints) { var units = world.FindAliveCombatantActorsInCircle(rallyPoint.CenterPosition, WRange.FromCells(4)) .Where(u => u.IsIdle && u.HasTrait() && u.Owner == soviets); if (units.Count() >= sovietAttackGroupSize) { foreach (var unit in units) { AttackNearestAlliedActor(unit); } } } var scatteredUnits = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && u.HasTrait() && u.IsIdle && u.Owner == soviets) .Except(world.WorldActor.Trait().Actors.Values) .Except(sovietRallyPoints.SelectMany(rp => world.FindAliveCombatantActorsInCircle(rp.CenterPosition, WRange.FromCells(4)))); foreach (var unit in scatteredUnits) { AttackNearestAlliedActor(unit); } } void StartCountDownTimer() { Sound.Play("timergo1.aud"); survivalTimer = new CountdownTimer(timerTicks, CountDownTimerExpired, true); survivalTimerWidget = new CountdownTimerWidget(survivalTimer, "Survive: {0}"); Ui.Root.AddChild(survivalTimerWidget); } void SendReinforcements() { foreach (var unit in reinforcements) { var u = world.CreateActor(unit, new TypeDictionary { new LocationInit(sovietEntryPoint7.Location), new FacingInit(0), new OwnerInit(allies) }); u.QueueActivity(new Move.Move(alliesbase.Location)); } } void CountDownTimerExpired(CountdownTimer countDownTimer) { survivalTimerWidget.Visible = false; SendReinforcements(); maintainPresence.Status = ObjectiveStatus.Completed; destroySoviets.Status = ObjectiveStatus.InProgress; OnObjectivesUpdated(true); } public void WorldLoaded(World w, WorldRenderer wr) { world = w; allies = w.Players.SingleOrDefault(p => p.InternalName == "Allies"); if (allies != null) { attackAtFrameInf = 300; attackAtFrameIncrementInf = 300; attackAtFrame = 450; attackAtFrameIncrement = 450; } difficulty = w.LobbyInfo.GlobalSettings.Difficulty; Game.Debug("{0} difficulty selected".F(difficulty)); switch (difficulty) { case "Hard": attackAtFrameIncrement = 350; attackAtFrameIncrementInf = 200; break; case "Normal": attackAtFrameIncrement = 450; attackAtFrameIncrementInf = 300; break; case "Easy": attackAtFrameIncrement = 550; attackAtFrameIncrementInf = 400; break; } soviets = w.Players.Single(p => p.InternalName == "Soviets"); var actors = w.WorldActor.Trait().Actors; sovietEntryPoint1 = actors["sovietEntryPoint1"]; sovietEntryPoint2 = actors["sovietEntryPoint2"]; sovietEntryPoint3 = actors["sovietEntryPoint3"]; sovietEntryPoint4 = actors["sovietEntryPoint4"]; sovietEntryPoint5 = actors["sovietEntryPoint5"]; sovietEntryPoints = new[] { sovietEntryPoint1, sovietEntryPoint2, sovietEntryPoint3, sovietEntryPoint4, sovietEntryPoint5 }.Select(p => p.Location).ToArray(); sovietRallyPoint1 = actors["sovietRallyPoint1"]; sovietRallyPoint2 = actors["sovietRallyPoint2"]; sovietRallyPoint3 = actors["sovietRallyPoint3"]; sovietRallyPoint4 = actors["sovietRallyPoint4"]; sovietRallyPoint5 = actors["sovietRallyPoint5"]; sovietRallyPoints = new[] { sovietRallyPoint1, sovietRallyPoint2, sovietRallyPoint3, sovietRallyPoint4, sovietRallyPoint5 }.Select(p => p.Location).ToArray(); alliesbase = actors["alliesbase"]; alliesbase1 = actors["alliesbase1"]; alliesbase2 = actors["alliesbase2"]; badgerEntryPoint1 = actors["BadgerEntryPoint1"]; badgerEntryPoint2 = actors["BadgerEntryPoint2"]; sovietEntryPoint7 = actors["sovietEntryPoint7"]; sovietinfantryentry1 = actors["SovietInfantryEntry1"]; sovietinfantryrally1 = actors["SovietInfantryRally1"]; paraDrop1 = actors["ParaDrop1"]; paraDrop2 = actors["ParaDrop2"]; barrack1 = actors["Barrack1"]; sam1 = actors["Sam1"]; sam2 = actors["Sam2"]; var shroud = allies.PlayerActor.Trait(); shroud.Explore(w, sam1.Location, 4); shroud.Explore(w, sam2.Location, 4); wr.Viewport.Center(alliesbase.CenterPosition); StartCountDownTimer(); SendSquad1(); SendSquad2(); MissionUtils.PlayMissionMusic(); } } }