From 130300074e90144686f2b05a3fc1e3873e8bae22 Mon Sep 17 00:00:00 2001 From: "Grant H." Date: Sat, 1 Jun 2013 19:09:27 -0500 Subject: [PATCH] Added New Missions Added New Single-player Survival Map - Survival02 Added New 4 Player Co-op Survival Minigame - Fort LoneStar --- OpenRA.Mods.RA/Missions/FortScript.cs | 409 +++++++ OpenRA.Mods.RA/Missions/Survival02Script.cs | 417 +++++++ mods/ra/maps/Fort-Lonestar/map.bin | Bin 0 -> 46085 bytes mods/ra/maps/Fort-Lonestar/map.yaml | 1110 ++++++++++++++++++ mods/ra/maps/Survival02/map.bin | Bin 0 -> 32005 bytes mods/ra/maps/Survival02/map.yaml | 1134 +++++++++++++++++++ 6 files changed, 3070 insertions(+) create mode 100644 OpenRA.Mods.RA/Missions/FortScript.cs create mode 100644 OpenRA.Mods.RA/Missions/Survival02Script.cs create mode 100644 mods/ra/maps/Fort-Lonestar/map.bin create mode 100644 mods/ra/maps/Fort-Lonestar/map.yaml create mode 100644 mods/ra/maps/Survival02/map.bin create mode 100644 mods/ra/maps/Survival02/map.yaml diff --git a/OpenRA.Mods.RA/Missions/FortScript.cs b/OpenRA.Mods.RA/Missions/FortScript.cs new file mode 100644 index 0000000000..9ed070dff6 --- /dev/null +++ b/OpenRA.Mods.RA/Missions/FortScript.cs @@ -0,0 +1,409 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Air; +using OpenRA.Mods.RA.Move; +using OpenRA.Network; +using OpenRA.Scripting; +using OpenRA.Traits; +using OpenRA.Widgets; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Effects; + +namespace OpenRA.Mods.RA.Missions +{ + class FortScriptInfo : TraitInfo, Requires { } + + class FortScript : IWorldLoaded, ITick + { + Player multi0; + Player soviets; + + Actor entry1; + Actor entry2; + Actor entry3; + Actor entry4; + Actor entry5; + Actor entry6; + Actor entry7; + Actor entry8; + CPos[] sovietEntryPoints; + Actor paradrop1; + Actor paradrop2; + Actor paradrop3; + Actor paradrop4; + + Actor baseA; + Actor baseB; + + World world; + + int WaveNumber = 0; + InfoWidget evacuateWidget; + const string ShortEvacuateTemplate = "Wave {0}"; + static readonly string[] PatrolA = { "e1", "e2", "e1" }; + static readonly string[] Infantry = { "e4", "e1", "e1", "e2", "e1", "e2" }; + static readonly string[] InfantryAdvanced = { "e4", "e1", "e1", "shok", "e1", "e2", "e4" }; + static readonly string[] Vehicles = { "arty", "ftrk", "ftrk", "jeep", "jeep", "jeep", "apc", "apc", }; + static readonly string[] Volkov = { "e8" }; + const string boss = "4tnk"; + const int TimerTicks = 1; + const int PatrolTicks = 1500; + + int AttackSquad = 6; + int AttackSquadCount = 1; + int VehicleSquad = 2; + int VehicleSquadCount = 1; + + int patrolAttackFrame; + int patrolattackAtFrameIncrement; + int WaveAttackFrame; + int WaveAttackAtFrameIncrement; + int VehicleAttackFrame; + int VehicleAttackAtFrameIncrement; + + void MissionAccomplished(string text) + { + MissionUtils.CoopMissionAccomplished(world, text, multi0); + } + + void AttackNearestAlliedActor(Actor self) + { + var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == multi0) + && ((u.HasTrait() && !u.HasTrait()))); + var targetEnemy = enemies.OrderBy(u => (self.CenterLocation - u.CenterLocation).LengthSquared).FirstOrDefault(); + if (targetEnemy != null) + { + self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), 6))); + } + } + + void SendVehicles() + { + if (SpawnVehicles == true) + { + for (int i = 1; i <= VehicleSquadCount; i++) + { + var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == soviets) + && !u.HasTrait()); + var route = world.SharedRandom.Next(sovietEntryPoints.Length); + var spawnPoint = sovietEntryPoints[route]; + for (int r = 1; r <= VehicleSquad; r++) + { + var squad = world.CreateActor(Vehicles.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(spawnPoint), new OwnerInit(soviets) }); + squad.QueueActivity(new AttackMove.AttackMoveActivity(squad, new Move.Move(paradrop1.Location, 3))); + } + } + } + } + + void SendWave() + { + if (SpawnWave == true) + { + for (int i = 1; i <= AttackSquadCount; i++) + { + var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == soviets) + && !u.HasTrait()); + var route = world.SharedRandom.Next(sovietEntryPoints.Length); + var spawnPoint = sovietEntryPoints[route]; + IEnumerable units; + if (world.FrameNumber >= 1500 * 10) + { + units = InfantryAdvanced; + } + else + { + units = Infantry; + } + for (int r = 1; r < AttackSquad; r++) + { + var squad = world.CreateActor(Infantry.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(spawnPoint), new OwnerInit(soviets) }); + squad.QueueActivity(new AttackMove.AttackMoveActivity(squad, new Move.Move(paradrop1.Location, 3))); + var scatteredUnits = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location), 15) + .Where(unit => unit.IsIdle && unit.HasTrait() && unit.Owner == soviets); + foreach (var unit in scatteredUnits) + { + AttackNearestAlliedActor(unit); + } + } + } + } + } + + void SendPatrol() + { + if (SpawnPatrol == true) + { + for (int i = 0; i < PatrolA.Length; i++) + { + var inf = world.CreateActor(PatrolA.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(paradrop1.Location + new CVec(0, -10)), new OwnerInit(soviets) }); + inf.QueueActivity(new AttackMove.AttackMoveActivity(inf, new Move.Move(paradrop1.Location + new CVec(0, 0)))); + var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location), 20) + .Where(u => u.Owner == soviets); + foreach (var unit in units) + { + AttackNearestAlliedActor(unit); + } + } + for (int i = 0; i < PatrolA.Length; i++) + { + var inf = world.CreateActor(PatrolA.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(paradrop4.Location + new CVec(10, 0)), new OwnerInit(soviets) }); + inf.QueueActivity(new AttackMove.AttackMoveActivity(inf, new Move.Move(paradrop4.Location + new CVec(0, 0)))); + var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location), 20) + .Where(u => u.Owner == soviets); + foreach (var unit in units) + { + AttackNearestAlliedActor(unit); + } + } + for (int i = 0; i < PatrolA.Length; i++) + { + var inf = world.CreateActor(PatrolA.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(paradrop3.Location + new CVec(0, 10)), new OwnerInit(soviets) }); + inf.QueueActivity(new AttackMove.AttackMoveActivity(inf, new Move.Move(paradrop3.Location + new CVec(0, 0)))); + var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location), 20) + .Where(u => u.Owner == soviets); + foreach (var unit in units) + { + AttackNearestAlliedActor(unit); + } + } + for (int i = 0; i < PatrolA.Length; i++) + { + var inf = world.CreateActor(PatrolA.Random(world.SharedRandom), + new TypeDictionary { new LocationInit(paradrop2.Location + new CVec(-10, 0)), new OwnerInit(soviets) }); + inf.QueueActivity(new AttackMove.AttackMoveActivity(inf, new Move.Move(paradrop2.Location + new CVec(0, 0)))); + var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location), 20) + .Where(u => u.Owner == soviets); + foreach (var unit in units) + { + AttackNearestAlliedActor(unit); + } + } + } + } + + void SendVolkov() + { + for (int i = 0; i < Volkov.Length; i++) + { + var route = world.SharedRandom.Next(sovietEntryPoints.Length); + var spawnPoint = sovietEntryPoints[route]; + var actor = world.CreateActor(Volkov[i], new TypeDictionary { new OwnerInit(soviets), new LocationInit(spawnPoint) }); + actor.QueueActivity(new Move.Move(paradrop1.Location + new CVec(4, -11))); + var scatteredUnits = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(paradrop1.Location + new CVec(4, -11)), 4) + .Where(unit => unit.IsIdle && unit.HasTrait() && unit.Owner == soviets); + foreach (var unit in scatteredUnits) + { + AttackNearestAlliedActor(unit); + } + } + } + + void Wave(string text) + { + Game.AddChatLine(Color.Cyan, "Wave Sequence", text); + } + + void FinalWave(string text) + { + Game.AddChatLine(Color.DarkRed, "Boss Wave Sequence Initializing", text); + } + + public void Tick(Actor self) + { + var unitsAndBuildings = world.Actors.Where(a => !a.IsDead() && a.IsInWorld && (a.HasTrait() && a.HasTrait())); + if (!unitsAndBuildings.Any(a => a.Owner == soviets)) + { + MissionAccomplished("You and your mates have survived the onslaught!"); + } + if (world.FrameNumber == patrolAttackFrame) + { + patrolAttackFrame += patrolattackAtFrameIncrement; + patrolattackAtFrameIncrement = Math.Max(patrolattackAtFrameIncrement - 5, 100); + SendPatrol(); + } + if (world.FrameNumber == WaveAttackFrame) + { + WaveAttackFrame += WaveAttackAtFrameIncrement; + WaveAttackAtFrameIncrement = Math.Max(WaveAttackAtFrameIncrement - 5, 100); + SendWave(); + } + if (world.FrameNumber == VehicleAttackFrame) + { + VehicleAttackFrame += VehicleAttackAtFrameIncrement; + VehicleAttackAtFrameIncrement = Math.Max(VehicleAttackAtFrameIncrement - 5, 100); + SendVehicles(); + } + if (world.FrameNumber == TimerTicks) + { + evacuateWidget = new InfoWidget(""); + Ui.Root.AddChild(evacuateWidget); + WaveNumber++; + Wave("One Initializing"); + UpdateWaveSequence(); + } + if (world.FrameNumber == 1500 * 2) + { + WaveNumber++; + Wave("Two Initializing"); + SpawnPatrol = false; + AttackSquad = 7; + AttackSquadCount = 2; + UpdateWaveSequence(); + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location + new CVec(0, -2)); + } + if (world.FrameNumber == 1500 * 4) + { + WaveNumber++; + Wave("Three Initializing"); + UpdateWaveSequence(); + AttackSquad = 8; + } + if (world.FrameNumber == 1500 * 6) + { + WaveNumber++; + Wave("Four Initializing"); + UpdateWaveSequence(); + AttackSquad = 9; + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry2.Location, paradrop3.Location); + AttackSquadCount = 3; + VehicleSquad = 3; + } + if (world.FrameNumber == 1500 * 8) + { + WaveNumber++; + Wave("Five Initializing"); + UpdateWaveSequence(); + AttackSquad = 10; + SendVolkov(); + VehicleSquad = 4; + VehicleSquadCount = 2; + } + if (world.FrameNumber == 1500 * 10) + { + WaveNumber++; + Wave("Six Initializing"); + UpdateWaveSequence(); + AttackSquad = 11; + AttackSquadCount = 4; + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry4.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry6.Location, paradrop3.Location); + MissionUtils.Parabomb(world, soviets, entry5.Location, paradrop3.Location); + } + if (world.FrameNumber == 1500 * 12) + { + WaveNumber++; + Wave("Seven Initializing"); + UpdateWaveSequence(); + AttackSquad = 12; + VehicleSquad = 5; + VehicleSquadCount = 3; + SendVolkov(); + } + if (world.FrameNumber == 1500 * 14) + { + SpawnVehicles = true; + WaveNumber++; + Wave("Eight Initializing"); + UpdateWaveSequence(); + AttackSquad = 13; + AttackSquadCount = 5; + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry4.Location, paradrop1.Location); + MissionUtils.Parabomb(world, soviets, entry6.Location, paradrop3.Location); + MissionUtils.Parabomb(world, soviets, entry5.Location, paradrop3.Location); + MissionUtils.Parabomb(world, soviets, entry2.Location, paradrop2.Location); + MissionUtils.Parabomb(world, soviets, entry3.Location, paradrop2.Location); + } + if (world.FrameNumber == 1500 * 16) + { + WaveNumber++; + Wave("Nine Initializing"); + UpdateWaveSequence(); + AttackSquad = 14; + VehicleSquad = 6; + VehicleSquadCount = 4; + SendVolkov(); + } + if (world.FrameNumber == 1500 * 18) + { + WaveNumber++; + Wave("Ten Initializing"); + UpdateWaveSequence(); + AttackSquad = 15; + AttackSquadCount = 6; + MissionUtils.Parabomb(world, soviets, entry1.Location, paradrop1.Location + new CVec(0, -2)); + MissionUtils.Parabomb(world, soviets, entry2.Location, paradrop3.Location + new CVec(0, -2)); + MissionUtils.Parabomb(world, soviets, entry4.Location, paradrop2.Location + new CVec(0, -2)); + MissionUtils.Parabomb(world, soviets, entry5.Location, paradrop4.Location + new CVec(0, -2)); + MissionUtils.Parabomb(world, soviets, entry2.Location, paradrop1.Location + new CVec(0, 2)); + MissionUtils.Parabomb(world, soviets, entry4.Location, paradrop3.Location + new CVec(0, 2)); + MissionUtils.Parabomb(world, soviets, entry3.Location, paradrop2.Location + new CVec(0, 2)); + MissionUtils.Parabomb(world, soviets, entry5.Location, paradrop4.Location + new CVec(0, 2)); + } + if (world.FrameNumber == 1500 * 19) + { + SpawnWave = false; + SpawnVehicles = false; + } + if (world.FrameNumber == 1500 * 20) + { + MissionAccomplished("You and your mates have Survived the Onslaught!"); + } + } + + void UpdateWaveSequence() + { + evacuateWidget.Text = ShortEvacuateTemplate.F(WaveNumber); + } + + bool SpawnPatrol = true; + + bool SpawnWave = true; + + bool SpawnVehicles = true; + + public void WorldLoaded(World w) + { + world = w; + soviets = w.Players.Single(p => p.InternalName == "Soviets"); + multi0 = w.Players.Single(p => p.InternalName == "Multi0"); + patrolAttackFrame = 750; + patrolattackAtFrameIncrement = 750; + WaveAttackFrame = 500; + WaveAttackAtFrameIncrement = 500; + VehicleAttackFrame = 2000; + VehicleAttackAtFrameIncrement = 2000; + var actors = w.WorldActor.Trait().Actors; + entry1 = actors["Entry1"]; + entry2 = actors["Entry2"]; + entry3 = actors["Entry3"]; + entry4 = actors["Entry4"]; + entry5 = actors["Entry5"]; + entry6 = actors["Entry6"]; + entry7 = actors["Entry7"]; + entry8 = actors["Entry8"]; + sovietEntryPoints = new[] { entry1, entry2, entry3, entry4, entry5, entry6, entry7, entry8 }.Select(p => p.Location).ToArray(); + paradrop1 = actors["Paradrop1"]; + paradrop2 = actors["Paradrop2"]; + paradrop3 = actors["Paradrop3"]; + paradrop4 = actors["Paradrop4"]; + baseA = actors["BaseA"]; + baseB = actors["BaseB"]; + MissionUtils.PlayMissionMusic(); + Game.AddChatLine(Color.Cyan, "Mission", "Defend Fort LoneStar At All costs!"); + } + } +} diff --git a/OpenRA.Mods.RA/Missions/Survival02Script.cs b/OpenRA.Mods.RA/Missions/Survival02Script.cs new file mode 100644 index 0000000000..d24c476353 --- /dev/null +++ b/OpenRA.Mods.RA/Missions/Survival02Script.cs @@ -0,0 +1,417 @@ +#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.Collections.Generic; +using System.Linq; +using System; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Widgets; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Air; +using OpenRA.Scripting; + +namespace OpenRA.Mods.RA.Missions +{ + class Survival02ScriptInfo : TraitInfo, Requires { } + + class Survival02Script : IHasObjectives, IWorldLoaded, ITick + { + public event Action OnObjectivesUpdated = notify => { }; + + public IEnumerable Objectives { get { return objectives.Values; } } + + Dictionary objectives = new Dictionary + { + { maintainPresenceID, new Objective(ObjectiveType.Primary, maintainPresence, ObjectiveStatus.InProgress) }, + { destroySovietsID, new Objective(ObjectiveType.Primary, destroySoviets, ObjectiveStatus.Inactive) }, + }; + const int destroySovietsID = 0; + const string destroySoviets = "Excellent work Commander! We have reinforced our position enough to initiate a counter-attack. Destroy the remaining Soviet forces in the area!"; + const int maintainPresenceID = 1; + const string maintainPresence = "Commander! The Soviets have rendered us useless... Reports indicate Soviet reinforcements are coming to finish us off... the situation looks bleak..."; + + Player allies; + Player soviets; + + Actor sovietEntry1; + Actor sovietEntry2; + Actor sovietEntry3; + CPos[] sovietentrypoints; + CPos[] newsovietentrypoints; + + Actor sovietrally; + Actor sovietrally1; + Actor sovietrally2; + Actor sovietrally3; + Actor sovietrally4; + Actor sovietrally5; + Actor sovietrally6; + Actor sovietrally7; + Actor sovietrally8; + CPos[] sovietrallypoints; + CPos[] newsovietrallypoints; + + Actor sovietparadrop1; + Actor sovietparadrop2; + Actor sovietparadrop3; + Actor sovietparadropEntry; + + Actor alliesbase; + Actor factory; + Actor barrack1; + + Actor boom1; + Actor boom2; + Actor boom3; + Actor drum1; + Actor drum2; + Actor drum3; + Actor FranceEntry; + Actor FranceRally; + Actor FranceparaEntry1; + Actor FranceparaEntry2; + Actor FranceparaEntry3; + + + World world; + + CountdownTimer survivalTimer; + CountdownTimerWidget survivalTimerWidget; + + const int timerTicks = 1500 * 10; + const int attackTicks = 1500 * 1; + const int sovietAttackGroupSize = 7; + const int SovietGroupSize = 4; + + const string Camera = "Camera"; + const string InfantryQueueName = "Infantry"; + const string Flare = "flare"; + + static readonly string[] FrenchSquad = { "2tnk", "2tnk", "mcv" }; + static readonly string[] SovietInfantry = { "e1", "e4", "e2" }; + static readonly string[] SovietVehicles = { "3tnk", "3tnk", "v2rl" }; + static readonly string[] SovietTanks = { "3tnk", "3tnk", "3tnk" }; + static readonly string[] squad = { "e1", "e1", "e2", "e4", "e4" }; + static readonly string[] platoon = { "e1", "e1", "e2", "e4", "e4", "e1", "e1", "e2", "e4", "e4" }; + + int ProduceAtFrame; + int ProduceAtFrameIncrement; + int attackAtFrame; + int attackAtFrameIncrement; + + void MissionAccomplished(string text) + { + MissionUtils.CoopMissionAccomplished(world, text, allies); + } + + void MissionFailed(string text) + { + MissionUtils.CoopMissionFailed(world, text, allies); + } + + void Message(string text) + { + Game.AddChatLine(Color.Aqua, "Incoming Report", text); + } + + void SetSovietUnitsToDefensiveStance() + { + foreach (var actor in world.Actors.Where(a => a.IsInWorld && a.Owner == soviets && !a.IsDead() && a.HasTrait())) + actor.Trait().stance = UnitStance.Defend; + } + + Actor FirstUnshroudedOrDefault(IEnumerable actors, World world, int shroudRange) + { + return actors.FirstOrDefault(u => world.FindAliveCombatantActorsInCircle(u.CenterLocation, shroudRange).All(a => !a.HasTrait())); + } + + void AttackNearestAlliedActor(Actor self) + { + var enemies = world.Actors.Where(u => u.AppearsHostileTo(self) && (u.Owner == allies) + && ((u.HasTrait() && !u.HasTrait()) || u.HasTrait()) && u.IsInWorld && !u.IsDead()); + + var enemy = FirstUnshroudedOrDefault(enemies.OrderBy(u => (self.CenterLocation - u.CenterLocation).LengthSquared), world, 20); + if (enemy != null) + self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(enemy), 3))); + } + + void SpawnAndAttack(string[] squad, Player owner, CPos location) + { + for (int i = 0; i < squad.Length; i++) + { + var actor = world.CreateActor(squad[i], new TypeDictionary { new OwnerInit(owner), new LocationInit(location) }); + AttackNearestAlliedActor(actor); + } + } + + void SpawnFlare(Player owner, Actor location) + { + world.CreateActor(Flare, new TypeDictionary { new OwnerInit(owner), new LocationInit(location.Location) }); + } + + void FinalAttack() + { + SpawnAndAttack(SovietTanks, soviets, sovietEntry1.Location); + SpawnAndAttack(SovietTanks, soviets, sovietEntry1.Location); + SpawnAndAttack(SovietTanks, soviets, sovietEntry2.Location); + SpawnAndAttack(platoon, soviets, sovietEntry1.Location); + SpawnAndAttack(platoon, soviets, sovietEntry2.Location); + } + + void FrenchReinforcements() + { + Game.MoveViewport(sovietrally1.Location.ToFloat2()); + MissionUtils.Parabomb(world, allies, FranceparaEntry1.Location, drum3.Location); + MissionUtils.Parabomb(world, allies, FranceparaEntry3.Location, drum2.Location); + MissionUtils.Parabomb(world, allies, FranceparaEntry2.Location, drum1.Location); + for (int i = 0; i < FrenchSquad.Length; i++) + { + var actor = world.CreateActor(FrenchSquad[i], new TypeDictionary { new OwnerInit(allies), new LocationInit(FranceEntry.Location) }); + actor.QueueActivity(new Move.Move(FranceRally.Location)); + } + } + + public void Tick(Actor self) + { + if (allies.WinState != WinState.Undefined) + return; + + survivalTimer.Tick(); + if (allies != null) + { + ManageSovietUnits(); + } + + var unitsAndBuildings = world.Actors.Where(a => !a.IsDead() && a.IsInWorld && (a.HasTrait() || (a.HasTrait() && !a.HasTrait()))); + if (!unitsAndBuildings.Any(a => a.Owner == soviets)) + { + objectives[destroySovietsID].Status = ObjectiveStatus.Completed; + MissionAccomplished("We have destroyed the remaining Soviet presence!"); + } + + if (world.FrameNumber == ProduceAtFrame) + { + ProduceAtFrame += ProduceAtFrameIncrement; + ProduceAtFrameIncrement = Math.Max(ProduceAtFrameIncrement - 5, 100); + InitializeSovietFactories(barrack1, sovietrally.Location); + BuildSovietUnits(factory, barrack1); + } + if (world.FrameNumber == attackAtFrame) + { + attackAtFrame += attackAtFrameIncrement; + attackAtFrameIncrement = Math.Max(attackAtFrameIncrement - 5, 100); + ManageSovietVehicles(); + if (producing) + { + BuildSovietVehicles(sovietentrypoints, sovietrallypoints); + } + else + BuildSovietVehicles(newsovietentrypoints, newsovietrallypoints); + } + if (world.FrameNumber == attackTicks) + { + SpawnAndAttack(squad, soviets, sovietrally5.Location); + SpawnAndAttack(squad, soviets, sovietrally6.Location); + } + if (world.FrameNumber == attackTicks * 3) + { + SpawnFlare(soviets, sovietparadrop3); + MissionUtils.Paradrop(world, soviets, squad, sovietparadropEntry.Location, sovietparadrop3.Location); + SpawnAndAttack(squad, soviets, sovietrally2.Location); + SpawnAndAttack(platoon, soviets, sovietrally5.Location); + SpawnAndAttack(platoon, soviets, sovietrally6.Location); + } + if (world.FrameNumber == attackTicks * 5) + { + SpawnFlare(soviets, sovietparadrop2); + MissionUtils.Paradrop(world, soviets, squad, sovietparadropEntry.Location, sovietparadrop2.Location); + } + if (world.FrameNumber == attackTicks * 7) + { + SpawnFlare(soviets, sovietparadrop1); + MissionUtils.Paradrop(world, soviets, squad, sovietparadropEntry.Location, sovietparadrop1.Location); + } + if (world.FrameNumber == attackTicks * 10) + { + SpawnFlare(soviets, sovietparadrop1); + MissionUtils.Paradrop(world, soviets, squad, sovietparadropEntry.Location, sovietparadrop1.Location); + ManageSovietUnits(); + } + if (world.FrameNumber == attackTicks * 12) + { + Sound.Play("reinfor1.aud"); + FrenchReinforcements(); + } + } + + void StartCountDownTimer() + { + Sound.Play("timergo1.aud"); + survivalTimer = new CountdownTimer(timerTicks, CountDownTimerExpired, true); + survivalTimerWidget = new CountdownTimerWidget(survivalTimer, "Time Until Soviet Reinforcements Arrive: {0}"); + Ui.Root.AddChild(survivalTimerWidget); + } + + void CountDownTimerExpired(CountdownTimer countDownTimer) + { + survivalTimerWidget.Visible = false; + Message("The Soviet reinforcements are approuching!"); + BuildSovietVehicles(newsovietentrypoints, newsovietrallypoints); + FinalAttack(); + producing = false; + objectives[maintainPresenceID].Status = ObjectiveStatus.Completed; + objectives[destroySovietsID].Status = ObjectiveStatus.InProgress; + OnObjectivesUpdated(true); + } + + void InitializeSovietFactories(Actor tent, CPos rally) + { + if (tent.IsInWorld && !tent.IsDead()) + { + var sbrp = tent.Trait(); + sbrp.rallyPoint = rally; + sbrp.nearEnough = 6; + } + } + + void BuildSovietUnit(string category, string unit) + { + var queueTent = MissionUtils.FindQueues(world, soviets, category).FirstOrDefault(q => q.CurrentItem() == null); + if (queueTent == null) return; + queueTent.ResolveOrder(queueTent.self, Order.StartProduction(queueTent.self, unit, 1)); + } + + void BuildSovietUnits(Actor factory, Actor tent) + { + if (barrack1.IsInWorld && !barrack1.IsDead()) + { + BuildSovietUnit(InfantryQueueName, SovietInfantry.Random(world.SharedRandom)); + } + } + + void ManageSovietUnits() + { + var units = world.FindAliveCombatantActorsInCircle(sovietrally.CenterLocation, 3) + .Where(u => u.IsIdle && u.HasTrait() && u.HasTrait() && u.Owner == soviets); + if (units.Count() >= sovietAttackGroupSize) + { + foreach (var unit in units) + { + var route = world.SharedRandom.Next(sovietrallypoints.Length); + unit.QueueActivity(new Move.Move(sovietrally3.Location)); + unit.QueueActivity(new Wait(300)); + unit.QueueActivity(new Move.Move(sovietrallypoints[route])); + AttackNearestAlliedActor(unit); + } + } + } + + void BuildSovietVehicles(CPos[] spawnpoints, CPos[] rallypoints) + { + var route = world.SharedRandom.Next(spawnpoints.Length); + var spawnPoint = spawnpoints[route]; + var rally = world.SharedRandom.Next(rallypoints.Length); + var rallyPoint = rallypoints[rally]; + 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 ManageSovietVehicles() + { + foreach (var rallyPoint in sovietrallypoints) + { + var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(rallyPoint), 10) + .Where(u => u.IsIdle && u.HasTrait() && u.HasTrait() && u.Owner == soviets); + if (units.Count() >= SovietGroupSize) + { + 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(Util.CenterOfCell(rp), 10))); + + foreach (var unit in scatteredUnits) + AttackNearestAlliedActor(unit); + } + + bool producing = true; + + public void WorldLoaded(World w) + { + world = w; + allies = w.Players.SingleOrDefault(p => p.InternalName == "Allies"); + if (allies != null) + { + ProduceAtFrame = 300; + ProduceAtFrameIncrement = 300; + attackAtFrame = 450; + attackAtFrameIncrement = 450; + } + soviets = w.Players.Single(p => p.InternalName == "Soviets"); + var actors = w.WorldActor.Trait().Actors; + sovietEntry1 = actors["SovietEntry1"]; + sovietEntry2 = actors["SovietEntry2"]; + sovietEntry3 = actors["SovietEntry3"]; + sovietentrypoints = new[] { sovietEntry1, sovietEntry2, sovietEntry3 }.Select(p => p.Location).ToArray(); + sovietrally = actors["SovietRally"]; + sovietrally1 = actors["SovietRally1"]; + sovietrally2 = actors["SovietRally2"]; + sovietrally3 = actors["SovietRally3"]; + sovietrally4 = actors["SovietRally4"]; + sovietrally5 = actors["SovietRally5"]; + sovietrally6 = actors["SovietRally6"]; + sovietrally7 = actors["SovietRally7"]; + sovietrally8 = actors["SovietRally8"]; + sovietrallypoints = new[] { sovietrally2, sovietrally4, sovietrally5, sovietrally6 }.Select(p => p.Location).ToArray(); + alliesbase = actors["AlliesBase"]; + sovietparadropEntry = actors["SovietParaDropEntry"]; + sovietparadrop1 = actors["SovietParaDrop1"]; + sovietparadrop2 = actors["SovietParaDrop2"]; + sovietparadrop3 = actors["SovietParaDrop3"]; + barrack1 = actors["barrack1"]; + factory = actors["Factory"]; + boom1 = actors["boom1"]; + boom2 = actors["boom2"]; + boom3 = actors["boom3"]; + drum1 = actors["drum1"]; + drum2 = actors["drum2"]; + drum3 = actors["drum3"]; + FranceEntry = actors["FranceEntry"]; + FranceRally = actors["FranceRally"]; + FranceparaEntry1 = actors["FranceparaEntry1"]; + FranceparaEntry2 = actors["FranceparaEntry2"]; + FranceparaEntry3 = actors["FranceparaEntry3"]; + newsovietentrypoints = new[] { sovietparadropEntry, sovietEntry3 }.Select(p => p.Location).ToArray(); + newsovietrallypoints = new[] { sovietrally3, sovietrally4, sovietrally8 }.Select(p => p.Location).ToArray(); + Game.MoveViewport(alliesbase.Location.ToFloat2()); + StartCountDownTimer(); + SetSovietUnitsToDefensiveStance(); + var Camera1 = world.CreateActor(Camera, new TypeDictionary + { + new OwnerInit(allies), + new LocationInit(sovietrally1.Location), + }); + //MissionUtils.PlayMissionMusic(); + } + } + +} diff --git a/mods/ra/maps/Fort-Lonestar/map.bin b/mods/ra/maps/Fort-Lonestar/map.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3a2b6011f71315df4b64140ca5c7835ef5e3ac8 GIT binary patch literal 46085 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 Zfh3Rwl0Xtj0!bhVB!MK51pe;?{tI~FfLH(k literal 0 HcmV?d00001 diff --git a/mods/ra/maps/Fort-Lonestar/map.yaml b/mods/ra/maps/Fort-Lonestar/map.yaml new file mode 100644 index 0000000000..75e8ede1ef --- /dev/null +++ b/mods/ra/maps/Fort-Lonestar/map.yaml @@ -0,0 +1,1110 @@ +Selectable: True + +MapFormat: 5 + +Title: Fort Lonestar + +Description: Survive 11 Waves with 4 mates. + +Author: Nuke'm Bro. + +Tileset: TEMPERAT + +MapSize: 96,96 + +Bounds: 8,8,48,48 + +UseAsShellmap: False + +Type: Minigame + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Race: allies + PlayerReference@Multi0: + Name: Multi0 + Playable: True + AllowBots: False + LockTeam: True + Allies: Multi1,Multi2,Multi3 + Enemies: Soviets + PlayerReference@Multi1: + Name: Multi1 + Playable: True + AllowBots: False + LockTeam: True + Allies: Multi0,Multi2,Multi3 + Enemies: Soviets + PlayerReference@Multi2: + Name: Multi2 + Playable: True + AllowBots: False + LockTeam: True + Allies: Multi0,Multi1,Multi3 + Enemies: Soviets + PlayerReference@Multi3: + Name: Multi3 + Playable: True + AllowBots: False + LockTeam: True + Allies: Multi0,Multi1,Multi2 + Enemies: Soviets + PlayerReference@Soviets: + Name: Soviets + Race: soviet + ColorRamp: 0,255,128,10 + Enemies: Multi0,Multi1,Multi2,Multi3 + +Actors: + Actor76: t11 + Location: 47,27 + Owner: Neutral + Actor47: t12 + Location: 55,24 + Owner: Neutral + Actor25: tc03 + Location: 54,49 + Owner: Neutral + Actor14: tc04 + Location: 24,7 + Owner: Neutral + Actor10: tc04 + Location: 38,53 + Owner: Neutral + Actor0: t14 + Location: 32,16 + Owner: Neutral + Actor75: tc04 + Location: 45,25 + Owner: Neutral + Actor72: tc01 + Location: 49,16 + Owner: Neutral + Actor58: t10 + Location: 22,54 + Owner: Neutral + Actor26: tc01 + Location: 54,41 + Owner: Neutral + Actor37: tc01 + Location: 54,21 + Owner: Neutral + Actor60: tc05 + Location: 7,16 + Owner: Neutral + Actor69: t17 + Location: 23,8 + Owner: Neutral + Actor4: tc04 + Location: 29,45 + Owner: Neutral + Actor6: t17 + Location: 33,43 + Owner: Neutral + Actor16: tc04 + Location: 53,16 + Owner: Neutral + Actor21: tc03 + Location: 8,14 + Owner: Neutral + Actor8: t14 + Location: 49,37 + Owner: Neutral + Actor29: tc01 + Location: 8,42 + Owner: Neutral + Actor49: t15 + Location: 54,47 + Owner: Neutral + Actor62: tc05 + Location: 6,43 + Owner: Neutral + Actor73: tc05 + Location: 16,34 + Owner: Neutral + Actor30: barr + Location: 36,26 + Owner: Multi0 + Actor84: brik + Location: 35,25 + Owner: Neutral + Actor32: tc01 + Location: 8,24 + Owner: Neutral + Actor59: tc05 + Location: 7,39 + Owner: Neutral + Actor5: tc01 + Location: 44,44 + Owner: Neutral + Actor67: brik + Location: 29,25 + Owner: Neutral + Actor41: brik + Location: 25,25 + Owner: Neutral + Actor56: brik + Location: 26,25 + Owner: Neutral + Actor85: brik + Location: 39,26 + Owner: Neutral + Actor81: brik + Location: 38,25 + Owner: Neutral + Actor65: brik + Location: 27,25 + Owner: Neutral + Actor66: brik + Location: 28,25 + Owner: Neutral + Actor51: t08 + Location: 55,46 + Owner: Neutral + Actor57: t12 + Location: 19,54 + Owner: Neutral + Actor54: t11 + Location: 26,54 + Owner: Neutral + Actor33: tc01 + Location: 21,7 + Owner: Neutral + Actor27: tc01 + Location: 42,54 + Owner: Neutral + Actor23: tc03 + Location: 16,54 + Owner: Neutral + Actor15: tc04 + Location: 38,8 + Owner: Neutral + Actor19: tc03 + Location: 18,7 + Owner: Neutral + Actor17: tc03 + Location: 54,26 + Owner: Neutral + Actor83: brik + Location: 36,25 + Owner: Neutral + Actor197: brik + Location: 39,37 + Owner: Neutral + Actor11: tc04 + Location: 20,53 + Owner: Neutral + Actor9: tc04 + Location: 53,37 + Owner: Neutral + Actor7: tc02 + Location: 44,36 + Owner: Neutral + Actor3: t15 + Location: 19,25 + Owner: Neutral + Actor1: t05 + Location: 29,16 + Owner: Neutral + Actor82: brik + Location: 37,25 + Owner: Neutral + Actor86: brik + Location: 39,27 + Owner: Neutral + Actor80: brik + Location: 39,25 + Owner: Neutral + Actor71: tc02 + Location: 15,40 + Owner: Neutral + Actor64: t06 + Location: 18,16 + Owner: Neutral + Actor63: t14 + Location: 8,22 + Owner: Neutral + Actor53: t08 + Location: 41,55 + Owner: Neutral + Actor61: tc05 + Location: 54,39 + Owner: Neutral + Actor48: t01 + Location: 54,23 + Owner: Neutral + Actor50: t17 + Location: 54,44 + Owner: Neutral + Actor36: tc01 + Location: 42,8 + Owner: Neutral + Actor52: t12 + Location: 44,53 + Owner: Neutral + Actor87: brik + Location: 39,28 + Owner: Neutral + Actor91: brik + Location: 37,39 + Owner: Neutral + Actor196: brik + Location: 39,38 + Owner: Neutral + Actor195: brik + Location: 39,39 + Owner: Neutral + Actor45: brik + Location: 25,28 + Owner: Neutral + Actor92: brik + Location: 39,29 + Owner: Neutral + Actor194: brik + Location: 38,39 + Owner: Neutral + Actor55: brik + Location: 25,39 + Owner: Neutral + Actor200: brik + Location: 28,39 + Owner: Neutral + Actor233: brik + Location: 29,39 + Owner: Neutral + Actor240: brik + Location: 39,35 + Owner: Neutral + Actor199: brik + Location: 27,39 + Owner: Neutral + Actor78: mpspawn + Location: 36,28 + Owner: Neutral + Actor28: tc01 + Location: 24,54 + Owner: Neutral + Actor22: tc03 + Location: 7,46 + Owner: Neutral + Actor24: tc03 + Location: 45,54 + Owner: Neutral + Actor18: tc03 + Location: 45,8 + Owner: Neutral + Actor12: tc04 + Location: 7,37 + Owner: Neutral + Actor13: tc04 + Location: 8,19 + Owner: Neutral + Actor2: tc04 + Location: 14,23 + Owner: Neutral + Actor74: t06 + Location: 19,36 + Owner: Neutral + Actor46: t11 + Location: 54,19 + Owner: Neutral + Actor42: t16 + Location: 53,19 + Owner: Neutral + Actor70: t16 + Location: 20,45 + Owner: Neutral + Actor68: tc05 + Location: 35,7 + Owner: Neutral + Actor239: brik + Location: 39,36 + Owner: Neutral + Actor89: brik + Location: 35,39 + Owner: Neutral + Actor90: brik + Location: 36,39 + Owner: Neutral + Actor40: oilb + Location: 32,30 + Owner: Multi0 + Actor237: brik + Location: 25,35 + Owner: Neutral + Actor236: brik + Location: 25,36 + Owner: Neutral + Actor235: brik + Location: 25,37 + Owner: Neutral + Actor234: brik + Location: 25,38 + Owner: Neutral + Actor44: brik + Location: 25,27 + Owner: Neutral + Actor43: brik + Location: 25,26 + Owner: Neutral + Actor198: brik + Location: 26,39 + Owner: Neutral + Actor88: brik + Location: 25,29 + Owner: Neutral + Entry1: waypoint + Location: 8,8 + Owner: Neutral + Entry2: waypoint + Location: 31,8 + Owner: Neutral + Entry3: waypoint + Location: 55,8 + Owner: Neutral + Entry4: waypoint + Location: 55,32 + Owner: Neutral + Entry5: waypoint + Location: 55,55 + Owner: Neutral + Entry6: waypoint + Location: 32,55 + Owner: Neutral + Entry7: waypoint + Location: 8,55 + Owner: Neutral + Entry8: waypoint + Location: 8,32 + Owner: Neutral + Paradrop1: waypoint + Location: 32,28 + Owner: Neutral + Paradrop2: waypoint + Location: 27,32 + Owner: Neutral + Paradrop3: waypoint + Location: 32,36 + Owner: Neutral + Paradrop4: waypoint + Location: 36,32 + Owner: Neutral + Rally1: waypoint + Location: 25,17 + Owner: Neutral + Rally2: waypoint + Location: 38,17 + Owner: Neutral + Rally3: waypoint + Location: 16,31 + Owner: Neutral + Rally4: waypoint + Location: 24,47 + Owner: Neutral + Rally5: waypoint + Location: 37,47 + Owner: Neutral + Rally6: waypoint + Location: 47,32 + Owner: Neutral + Actor20: apwr + Location: 37,4 + Owner: Soviets + BaseA: waypoint + Location: 24,24 + Owner: Neutral + BaseB: waypoint + Location: 40,40 + Owner: Neutral + Actor34: sniper + Location: 9,26 + Owner: Soviets + Actor35: sniper + Location: 10,21 + Owner: Soviets + Actor38: sniper + Location: 26,9 + Owner: Soviets + Actor39: sniper + Location: 40,10 + Owner: Soviets + Actor77: sniper + Location: 53,21 + Owner: Soviets + Actor79: sniper + Location: 54,25 + Owner: Soviets + Actor93: sniper + Location: 53,40 + Owner: Soviets + Actor94: sniper + Location: 54,43 + Owner: Soviets + Actor95: sniper + Location: 54,46 + Owner: Soviets + Actor96: sniper + Location: 43,53 + Owner: Soviets + Actor97: sniper + Location: 8,36 + Owner: Soviets + Actor98: sniper + Location: 28,55 + Owner: Soviets + Actor100: barr + Location: 27,26 + Owner: Multi3 + Actor99: barr + Location: 27,36 + Owner: Multi2 + Actor31: barr + Location: 36,36 + Owner: Multi1 + Actor101: oilb + Location: 32,32 + Owner: Multi1 + Actor102: oilb + Location: 30,32 + Owner: Multi2 + Actor103: oilb + Location: 30,30 + Owner: Multi3 + Actor104: mpspawn + Location: 27,28 + Owner: Neutral + Actor105: mpspawn + Location: 27,38 + Owner: Neutral + Actor106: mpspawn + Location: 36,38 + Owner: Neutral + +Smudges: + +Rules: + World: + CrateDrop: + Maximum: 1 + SpawnInterval: 100 + -SpawnMPUnits: + -MPStartLocations: + FortScript: + CRATE: + -LevelUpCrateAction: + -GiveMcvCrateAction: + -RevealMapCrateAction: + -HideMapCrateAction: + -ExplodeCrateAction@nuke: + -ExplodeCrateAction@boom: + -ExplodeCrateAction@fire: + -GiveUnitCrateAction@jeep: + -GiveUnitCrateAction@arty: + -GiveUnitCrateAction@v2rl: + -GiveUnitCrateAction@1tnk: + -GiveUnitCrateAction@2tnk: + -GiveUnitCrateAction@3tnk: + -GiveUnitCrateAction@4tnk: + SupportPowerCrateAction@parabombs: + SelectionShares: 30 + HealUnitsCrateAction: + SelectionShares: 30 + GiveCashCrateAction: + Amount: 400 + UseCashTick: yes + SelectionShares: 30 + GiveUnitCrateAction@e7: + Unit: e7 + SelectionShares: 10 + Player: + PlayerResources: + InitialCash: 50 + ClassicProductionQueue@Infantry: + Type: Infantry + BuildSpeed: 1 + LowPowerSlowdown: 3 + ClassicProductionQueue@Defense: + Type: Defense + BuildSpeed: .4 + LowPowerSlowdown: 3 + OILB: + Health: + HP: 3000 + BARR: + Buildable: + Owner: allies,soviet + Building: + Power: 0 + Health: + HP: 1000 + Production: + Produces: Defense,Infantry + FTUR: + Building: + Power: 0 + Owner: soviet + Valued: + Cost: 400 + PBOX: + Building: + Power: 0 + Owner: allies + Prerequisites: barr,oilb + Valued: + Cost: 400 + Health: + HP: 200 + Armor: + Type: Heavy + TransformOnPassenger@MEDI: + PassengerTypes: MEDI + OnEnter: pbox.MEDI + OnExit: pbox + SkipMakeAnims: true + PBOX.E1: + Buildable: + Queue: Defense + Prerequisites: barr + Owner: allies + PBOX.MEDI: + Inherits: PBOX + Tooltip: + Name: Pillbox (Medic) + RenderBuilding: + Image: PBOX + RenderRangeCircle: + AutoTarget: + AttackTurreted: + PrimaryWeapon: Heal + PrimaryLocalOffset: 0,-11,0,0,0 + HBOX.E1: + Inherits: HBOX + Buildable: + Queue: Defense + BuildPaletteOrder: 20 + Prerequisites: barr + Owner: None + HBOX: + Building: + Owner: None + GUN: + Buildable: + Queue: Defense + Prerequisites: barr + Owner: None + SAM: + Buildable: + Owner: None + SBAG: + Buildable: + Owner: None + MSLO: + Buildable: + Owner: None + GAP: + Buildable: + Owner: None + IRON: + Buildable: + Owner: None + PDOX: + Buildable: + Owner: None + SPEN: + Buildable: + Owner: allies + DOME: + Buildable: + Owner: allies + PROC: + Buildable: + Owner: allies + SILO: + Buildable: + Owner: allies + AGUN: + Buildable: + Owner: None + TSLA: + Buildable: + Owner: None + APWR: + Buildable: + Owner: allies + STEK: + Buildable: + Owner: allies + FIX: + Buildable: + Owner: allies + POWR: + Buildable: + Owner: allies + MIG: + Buildable: + Owner: allies + Prerequisites: barr,afld + Valued: + Cost: 2000 + YAK: + Buildable: + Owner: allies + Prerequisites: barr,afld + Valued: + Cost: 150 + TRAN: + Buildable: + Owner: allies + Prerequisites: barr,hpad + Valued: + Cost: 150 + HIND: + Buildable: + Owner: allies + Prerequisites: barr,hpad + Valued: + Cost: 200 + HELI: + Buildable: + Owner: allies + Prerequisites: barr,hpad + Valued: + Cost: 200 + HPAD: + Building: + Power: 0 + Buildable: + Owner: allies + Prerequisites: barr + Valued: + Cost: 200 + FENC: + Buildable: + Queue: Building + Owner: None + Prerequisites: barr + Valued: + Cost: 10 + AFLD: + Building: + Power: 0 + Buildable: + Owner: allies + Prerequisites: barr + Valued: + Cost: 200 + DOG: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 20 + E1: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 20 + E2: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 40 + Explodes: + Weapon: UnitExplodeSmall + Chance: 20 + E3: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 60 + E4: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 100 + E6: + Buildable: + Owner: soviet,allies + Prerequisites: barr + Valued: + Cost: 100 + E7: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 750 + E8: + Inherits: ^Infantry + Buildable: + Queue: Infantry + BuildPaletteOrder: 110 + Prerequisites: stek + Owner: None + Valued: + Cost: 1800 + Tooltip: + Name: Volkov + Description: Elite commando infantry, armed with \nmodular cannons and grenade launcher.\n Strong vs Vehicles, Infantry\n Weak vs Aircraft + Selectable: + Voice: VolkovVoice + Bounds: 12,17,0,-9 + Health: + HP: 200 + Armor: + Type: Heavy + Mobile: + Speed: 5 + RevealsShroud: + Range: 7 + Passenger: + PipType: Red + AttackFrontal: + PrimaryWeapon: VolkNapalm + Explodes: + Weapon: UnitExplodeSmall + Chance: 100 + TakeCover: + -RenderInfantry: + RenderInfantryProne: + IdleAnimations: idle1 + -CrushableInfantry: + MECH: + Buildable: + Owner: None + MEDI: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 100 + SHOK: + Buildable: + Owner: soviet,allies + Prerequisites: barr,oilb + Valued: + Cost: 120 + SNIPER: + Buildable: + Owner: allies,soviet + Prerequisites: barr,oilb + Valued: + Cost: 150 + SPY: + Inherits: ^Infantry + Buildable: + Queue: Infantry + BuildPaletteOrder: 60 + Prerequisites: barr,oilb + Owner: allies, soviets + Valued: + Cost: 300 + SpyToolTip: + Name: Spy + Description: Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised + Selectable: + Voice: SpyVoice + Bounds: 12,17,0,-9 + Health: + HP: 25 + Mobile: + Speed: 4 + RevealsShroud: + Range: 5 + Passenger: + PipType: Yellow + TakeCover: + Spy: + -AutoTarget: + AttackMove: + JustMove: true + -RenderInfantry: + RenderSpy: + IdleAnimations: idle1,idle2 + AttackFrontal: + PrimaryWeapon: SilencedPPK + ARTY: + Inherits: ^Tank + Buildable: + Queue: Vehicle + BuildPaletteOrder: 80 + Prerequisites: dome + Owner: allies + Valued: + Cost: 600 + Tooltip: + Name: Artillery + Description: Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft + Health: + HP: 75 + Armor: + Type: Light + Mobile: + ROT: 2 + Speed: 6 + RevealsShroud: + Range: 7 + AttackFrontal: + PrimaryWeapon: 155mm + SecondaryWeapon: 155mm + RenderUnit: + Explodes: + Weapon: UnitExplode + Chance: 50 + AutoTarget: + 4TNK: + Inherits: ^Tank + Buildable: + Queue: Vehicle + BuildPaletteOrder: 100 + Prerequisites: fix,stek + Owner: soviet + Valued: + Cost: 1800 + Tooltip: + Name: Mammoth Tank + Description: Big and slow tank, with anti-air capability.\n Strong vs Tanks, Aircraft\n Weak vs Infantry + Health: + HP: 5000 + Armor: + Type: Heavy + Mobile: + Speed: 4 + Crushes: wall, atmine, crate, infantry + RevealsShroud: + Range: 14 + Turreted: + ROT: 1 + AttackTurreted: + PrimaryWeapon: 120mm + SecondaryWeapon: MammothTusk + PrimaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 + SecondaryLocalOffset: -7,2,0,0,25, 7,2,0,0,-25 + PrimaryRecoil: 8 + PrimaryRecoilRecovery: 0.7 + SecondaryRecoil: 2 + RenderUnitTurreted: + AutoTarget: + Explodes: + Weapon: napalm + EmptyWeapon: napalm + LeavesHusk: + HuskActor: 4TNK.Husk + SelfHealing: + Step: 2 + Ticks: 1 + HealIfBelow: 80% + DamageCooldown: 150 + Selectable: + Bounds: 44,38,0,-4 + BRIK: + Inherits: ^Wall + Buildable: + Queue: Defense + BuildPaletteOrder: 1000 + Prerequisites: fact + Owner: None + Hotkey: w + Valued: + Cost: 100 + Health: + HP: 250 + Armor: + Type: Concrete + BADR.bomber: + CarpetBomb: + Range: 3 + Weapon: ParaBomb + Inherits: ^Plane + Health: + HP: 60 + Armor: + Type: Light + Plane: + ROT: 5 + Speed: 30 + LimitedAmmo: + Ammo: 30 + RenderUnit: + Image: mig + WithShadow: + IronCurtainable: + -Selectable: + -GainsExperience: + Tooltip: + Name: Badger + Contrail@1: + ContrailOffset: 11, -11 + Contrail@2: + ContrailOffset: -11, -11 + FallsToEarth: + Spins: no + Moves: yes + Explosion: UnitExplode + SmokeTrailWhenDamaged@0: + Offset: 11, -11 + Interval: 2 + SmokeTrailWhenDamaged@1: + Offset: -11, -11 + Interval: 2 + -EjectOnDeath: + -GpsDot: + +Sequences: + +Weapons: + 120mm: + ROF: 150 + Range: 10 + Report: CANNON1 + Burst: 6 + Projectile: Bullet + Speed: 12 + High: true + Inaccuracy: 40 + Image: 120MM + ContrailLength: 50 + Warhead: + Spread: 6 + Versus: + None: 75% + Wood: 75% + Light: 75% + Concrete: 100% + Explosion: self_destruct + WaterExplosion: self_destruct + InfDeath: 4 + SmudgeType: Crater + Damage: 150 + MammothTusk: + ROF: 300 + Range: 10 + Report: MISSILE6 + Burst: 2 + ValidTargets: Ground, Air + Projectile: Missile + Speed: 15 + Arm: 2 + High: true + Shadow: false + Proximity: true + Trail: smokey + ContrailLength: 10 + Inaccuracy: 20 + Image: DRAGON + ROT: 10 + RangeLimit: 80 + Warhead: + Spread: 12 + Versus: + None: 90% + Wood: 150% + Light: 150% + Heavy: 150% + Concrete: 200% + Explosion: nuke + WaterExplosion: nuke + InfDeath: 3 + SmudgeType: Crater + Damage: 250 + VolkNapalm: + ROF: 40 + Range: 7 + Report: volknapalm + ValidTargets: Ground + Burst: 6 + BurstDelay: 1 + Projectile: Bullet + Speed: 25 + Image: 120MM + Inaccuracy: 60 + Trail: smokey + ContrailLength: 2 + Warhead: + Spread: 8 + Versus: + None: 90% + Wood: 170% + Light: 100% + Heavy: 100% + Concrete: 100% + Explosion: small_explosion + WaterExplosion: small_explosion + InfDeath: 4 + SmudgeType: Scorch + ImpactSound: firebl3 + Damage: 15 + ParaBomb: + ROF: 5 + Range: 5 + Report: CHUTE1 + Projectile: GravityBomb + Image: BOMBLET + Warhead: + Spread: 10 + Versus: + None: 125% + Wood: 100% + Light: 60% + Concrete: 25% + Explosion: napalm + ImpactSound: firebl3 + WaterExplosion: napalm + InfDeath: 5 + SmudgeType: Crater + Damage: 200 + 155mm: + ROF: 10 + Range: 7.5 + Burst: 20 + MinRange: 3 + -Report: + Projectile: Bullet + Speed: 10 + Trail: fb4 + Image: fb3 + High: true + Angle: .1 + Inaccuracy: 40 + ContrailLength: 2 + Warhead: + Spread: 10 + Versus: + None: 100% + Wood: 100% + Light: 60% + Heavy: 25% + Concrete: 35% + Explosion: small_napalm + WaterExplosion: small_napalm + InfDeath: 5 + SmudgeType: Scorch + ImpactSound: firebl3 + Damage: 6 + SilencedPPK: + ROF: 80 + Range: 2.5 + Report: silppk + Projectile: Bullet + Speed: 100 + Warhead: + Spread: 3 + Versus: + Wood: 0% + Light: 0% + Heavy: 50% + Concrete: 0% + Explosion: piffs + InfDeath: 2 + Damage: 150 + +Voices: + +Notifications: diff --git a/mods/ra/maps/Survival02/map.bin b/mods/ra/maps/Survival02/map.bin new file mode 100644 index 0000000000000000000000000000000000000000..13fdf929d5a7d1a50321276a5b4c3d3ce7005169 GIT binary patch literal 32005 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