Merge pull request #2683 from Mailaender/survival01
Survival01 by @NukemBro
This commit is contained in:
350
OpenRA.Mods.RA/Missions/Survival01Script.cs
Normal file
350
OpenRA.Mods.RA/Missions/Survival01Script.cs
Normal file
@@ -0,0 +1,350 @@
|
||||
#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 OpenRA.FileFormats;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
|
||||
namespace OpenRA.Mods.RA.Missions
|
||||
{
|
||||
class Survival01ScriptInfo : TraitInfo<Survival01Script>, Requires<SpawnMapActorsInfo> { }
|
||||
|
||||
class Survival01Script : IHasObjectives, IWorldLoaded, ITick
|
||||
{
|
||||
public event Action<bool> OnObjectivesUpdated = notify => { };
|
||||
|
||||
public IEnumerable<Objective> Objectives { get { return objectives.Values; } }
|
||||
|
||||
Dictionary<int, Objective> objectives = new Dictionary<int, Objective>
|
||||
{
|
||||
{ maintainPresenceID, new Objective(ObjectiveType.Primary, maintainPresence, ObjectiveStatus.InProgress) },
|
||||
{ destroySovietsID, new Objective(ObjectiveType.Primary, destroySoviets, ObjectiveStatus.Inactive) }
|
||||
};
|
||||
|
||||
const int maintainPresenceID = 0;
|
||||
const int destroySovietsID = 1;
|
||||
|
||||
const string maintainPresence = "Enforce your position and hold-out the onslaught until reinforcements arrive. We must not lose the base!";
|
||||
const string destroySoviets = "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 (objectives[destroySovietsID].Status == ObjectiveStatus.InProgress)
|
||||
{
|
||||
if (barrack1.Destroyed)
|
||||
{
|
||||
objectives[destroySovietsID].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(Util.CenterOfCell(sovietinfantryrally1.Location), 10)
|
||||
.Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
|
||||
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<Building>() && !u.HasTrait<Wall>()) || u.HasTrait<Mobile>()));
|
||||
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), 3)));
|
||||
}
|
||||
}
|
||||
|
||||
void ManageSovietUnits()
|
||||
{
|
||||
foreach (var rallyPoint in sovietRallyPoints)
|
||||
{
|
||||
var units = world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(rallyPoint), 4)
|
||||
.Where(u => u.IsIdle && u.HasTrait<Mobile>() && 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<Mobile>() && u.IsIdle && u.Owner == soviets)
|
||||
.Except(world.WorldActor.Trait<SpawnMapActors>().Actors.Values)
|
||||
.Except(sovietRallyPoints.SelectMany(rp => world.FindAliveCombatantActorsInCircle(Util.CenterOfCell(rp), 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();
|
||||
objectives[maintainPresenceID].Status = ObjectiveStatus.Completed;
|
||||
objectives[destroySovietsID].Status = ObjectiveStatus.InProgress;
|
||||
OnObjectivesUpdated(true);
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
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<SpawnMapActors>().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 = w.WorldActor.Trait<Shroud>();
|
||||
shroud.Explore(w, sam1.Location, 4);
|
||||
shroud.Explore(w, sam2.Location, 4);
|
||||
Game.MoveViewport(alliesbase.Location.ToFloat2());
|
||||
StartCountDownTimer();
|
||||
SendSquad1();
|
||||
SendSquad2();
|
||||
MissionUtils.PlayMissionMusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,7 @@
|
||||
<Compile Include="Missions\MonsterTankMadnessScript.cs" />
|
||||
<Compile Include="Missions\Objective.cs" />
|
||||
<Compile Include="Missions\Soviet01ClassicScript.cs" />
|
||||
<Compile Include="Missions\Survival01Script.cs" />
|
||||
<Compile Include="Modifiers\FrozenUnderFog.cs" />
|
||||
<Compile Include="Modifiers\HiddenUnderFog.cs" />
|
||||
<Compile Include="Move\Drag.cs" />
|
||||
|
||||
BIN
mods/ra/maps/Survival01/map.bin
Normal file
BIN
mods/ra/maps/Survival01/map.bin
Normal file
Binary file not shown.
1304
mods/ra/maps/Survival01/map.yaml
Normal file
1304
mods/ra/maps/Survival01/map.yaml
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user