317 lines
11 KiB
C#
317 lines
11 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2011 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 OpenRA.FileFormats;
|
|
using OpenRA.Mods.RA.Activities;
|
|
using OpenRA.Mods.RA.Air;
|
|
using OpenRA.Mods.RA.Buildings;
|
|
using OpenRA.Mods.RA.Move;
|
|
using OpenRA.Scripting;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.RA.Missions
|
|
{
|
|
class DesertShellmapScriptInfo : TraitInfo<DesertShellmapScript>, Requires<SpawnMapActorsInfo> { }
|
|
|
|
class DesertShellmapScript : ITick, IWorldLoaded
|
|
{
|
|
World world;
|
|
Player allies;
|
|
Player soviets;
|
|
Player neutral;
|
|
|
|
List<int2> viewportTargets = new List<int2>();
|
|
int2 viewportTarget;
|
|
int viewportTargetNumber;
|
|
int2 viewportOrigin;
|
|
float mul;
|
|
float div = 400;
|
|
int waitTicks = 0;
|
|
|
|
int nextCivilianMove = 1;
|
|
|
|
Actor attackLocation;
|
|
Actor coastWP1;
|
|
Actor coastWP2;
|
|
int coastUnitsLeft;
|
|
static readonly string[] CoastUnits = { "e1", "e1", "e2", "e3", "e4" };
|
|
|
|
Actor paradrop1LZ;
|
|
Actor paradrop1Entry;
|
|
Actor paradrop2LZ;
|
|
Actor paradrop2Entry;
|
|
static readonly string[] ParadropUnits = { "e1", "e1", "e1", "e2", "e2" };
|
|
|
|
Actor offmapAttackerSpawn1;
|
|
Actor offmapAttackerSpawn2;
|
|
Actor offmapAttackerSpawn3;
|
|
Actor[] offmapAttackerSpawns;
|
|
static readonly string[] OffmapAttackers = { "ftrk", "apc", "ttnk", "1tnk" };
|
|
static readonly string[] AttackerCargo = { "e1", "e2", "e3", "e4" };
|
|
|
|
static readonly string[] HeavyTanks = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk" };
|
|
Actor heavyTankSpawn;
|
|
Actor heavyTankWP;
|
|
static readonly string[] MediumTanks = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "2tnk" };
|
|
Actor mediumTankChronoSpawn;
|
|
|
|
static readonly string[] ChinookCargo = { "e1", "e1", "e1", "e1", "e3", "e3" };
|
|
|
|
static readonly string[] InfantryProductionUnits = { "e1", "e3" };
|
|
static readonly string[] VehicleProductionUnits = { "jeep", "1tnk", "2tnk", "arty" };
|
|
Actor alliedBarracks;
|
|
Actor alliedWarFactory;
|
|
|
|
Dictionary<string, Actor> actors;
|
|
|
|
Actor chronosphere;
|
|
Actor ironCurtain;
|
|
|
|
CPos[] mig1Waypoints;
|
|
CPos[] mig2Waypoints;
|
|
|
|
Actor chinook1Entry;
|
|
Actor chinook1LZ;
|
|
Actor chinook2Entry;
|
|
Actor chinook2LZ;
|
|
|
|
public void Tick(Actor self)
|
|
{
|
|
if (world.FrameNumber % 100 == 0)
|
|
{
|
|
var actor = OffmapAttackers.Random(world.SharedRandom);
|
|
var spawn = offmapAttackerSpawns.Random(world.SharedRandom);
|
|
var u = world.CreateActor(actor, soviets, spawn.Location, Util.GetFacing(attackLocation.Location - spawn.Location, 0));
|
|
var cargo = u.TraitOrDefault<Cargo>();
|
|
if (cargo != null)
|
|
{
|
|
while (cargo.HasSpace(1))
|
|
cargo.Load(u, world.CreateActor(false, AttackerCargo.Random(world.SharedRandom), soviets, null, null));
|
|
}
|
|
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
|
|
}
|
|
|
|
if (world.FrameNumber % 25 == 0)
|
|
{
|
|
foreach (var actor in world.Actors.Where(a => a.IsInWorld && a.IsIdle && !a.IsDead()
|
|
&& a.HasTrait<AttackBase>() && a.HasTrait<Mobile>()).Except(actors.Values))
|
|
MissionUtils.AttackNearestLandActor(true, actor, actor.Owner == soviets ? allies : soviets);
|
|
|
|
MissionUtils.StartProduction(world, allies, "Infantry", InfantryProductionUnits.Random(world.SharedRandom));
|
|
MissionUtils.StartProduction(world, allies, "Vehicle", VehicleProductionUnits.Random(world.SharedRandom));
|
|
}
|
|
|
|
if (world.FrameNumber % 20 == 0 && coastUnitsLeft-- > 0)
|
|
{
|
|
var u = world.CreateActor(CoastUnits.Random(world.SharedRandom), soviets, coastWP1.Location, null);
|
|
u.QueueActivity(new Move.Move(coastWP2.Location, 0));
|
|
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
|
|
}
|
|
|
|
if (world.FrameNumber == nextCivilianMove)
|
|
{
|
|
var civilians = world.Actors.Where(a => !a.IsDead() && a.IsInWorld && a.Owner == neutral && a.HasTrait<Mobile>());
|
|
if (civilians.Any())
|
|
{
|
|
var civilian = civilians.Random(world.SharedRandom);
|
|
civilian.Trait<Mobile>().Nudge(civilian, civilian, true);
|
|
nextCivilianMove += world.SharedRandom.Next(1, 75);
|
|
}
|
|
}
|
|
|
|
if (world.FrameNumber == 1)
|
|
{
|
|
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
|
|
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
|
|
}
|
|
|
|
if (--waitTicks <= 0)
|
|
{
|
|
if (++mul <= div)
|
|
Game.MoveViewport(float2.Lerp(viewportOrigin, viewportTarget, mul / div));
|
|
else
|
|
{
|
|
mul = 0;
|
|
viewportOrigin = viewportTarget;
|
|
viewportTarget = viewportTargets[(viewportTargetNumber = (viewportTargetNumber + 1) % viewportTargets.Count)];
|
|
waitTicks = 100;
|
|
|
|
if (viewportTargetNumber == 0)
|
|
{
|
|
coastUnitsLeft = 15;
|
|
SendChinookReinforcements(chinook1Entry.Location, chinook1LZ);
|
|
SendChinookReinforcements(chinook2Entry.Location, chinook2LZ);
|
|
}
|
|
if (viewportTargetNumber == 1)
|
|
{
|
|
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
|
|
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
|
|
}
|
|
if (viewportTargetNumber == 2)
|
|
{
|
|
AttackWithHeavyTanks();
|
|
ChronoSpawnMediumTanks();
|
|
}
|
|
if (viewportTargetNumber == 4)
|
|
{
|
|
FlyMigs(mig1Waypoints);
|
|
FlyMigs(mig2Waypoints);
|
|
}
|
|
}
|
|
}
|
|
|
|
MissionUtils.CapOre(soviets);
|
|
}
|
|
|
|
void AttackWithHeavyTanks()
|
|
{
|
|
foreach (var tank in HeavyTanks)
|
|
{
|
|
var u = world.CreateActor(tank, soviets, heavyTankSpawn.Location, Util.GetFacing(heavyTankWP.Location - heavyTankSpawn.Location, 0));
|
|
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(heavyTankWP.Location, 0)));
|
|
}
|
|
ironCurtain.Trait<IronCurtainPower>().Activate(ironCurtain, new Order { TargetLocation = heavyTankSpawn.Location });
|
|
}
|
|
|
|
void ChronoSpawnMediumTanks()
|
|
{
|
|
var chronoInfo = new List<Pair<Actor, CPos>>();
|
|
foreach (var tank in MediumTanks.Select((x, i) => new { x, i }))
|
|
{
|
|
var u = world.CreateActor(tank.x, allies, mediumTankChronoSpawn.Location, Util.GetFacing(heavyTankWP.Location - mediumTankChronoSpawn.Location, 0));
|
|
chronoInfo.Add(Pair.New(u, new CPos(mediumTankChronoSpawn.Location.X + tank.i, mediumTankChronoSpawn.Location.Y)));
|
|
}
|
|
RASpecialPowers.Chronoshift(world, chronoInfo, chronosphere, -1, false);
|
|
foreach (var tank in chronoInfo)
|
|
tank.First.QueueActivity(new AttackMove.AttackMoveActivity(tank.First, new Move.Move(heavyTankSpawn.Location, 0)));
|
|
}
|
|
|
|
void FlyMigs(CPos[] waypoints)
|
|
{
|
|
var m = world.CreateActor("mig", new TypeDictionary
|
|
{
|
|
new OwnerInit(soviets),
|
|
new LocationInit(waypoints[0]),
|
|
new FacingInit(Util.GetFacing(waypoints[1] - waypoints[0], 0))
|
|
});
|
|
foreach (var waypoint in waypoints)
|
|
m.QueueActivity(Fly.ToCell(waypoint));
|
|
m.QueueActivity(new RemoveSelf());
|
|
}
|
|
|
|
void SendChinookReinforcements(CPos entry, Actor lz)
|
|
{
|
|
var chinook = world.CreateActor("tran", allies, entry, Util.GetFacing(lz.Location - entry, 0));
|
|
var cargo = chinook.Trait<Cargo>();
|
|
|
|
while (cargo.HasSpace(1))
|
|
cargo.Load(chinook, world.CreateActor(false, ChinookCargo.Random(world.SharedRandom), allies, null, null));
|
|
|
|
var exit = lz.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
|
|
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
|
|
|
|
chinook.QueueActivity(new HeliFly(lz.CenterPosition + offset)); // no reservation of hpad but it's not needed
|
|
chinook.QueueActivity(new Turn(0));
|
|
chinook.QueueActivity(new HeliLand(false));
|
|
chinook.QueueActivity(new UnloadCargo(true));
|
|
chinook.QueueActivity(new Wait(150));
|
|
chinook.QueueActivity(new HeliFly(entry));
|
|
chinook.QueueActivity(new RemoveSelf());
|
|
}
|
|
|
|
void InitializeAlliedFactories()
|
|
{
|
|
alliedBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(alliedBarracks, true);
|
|
alliedWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(alliedWarFactory, true);
|
|
}
|
|
|
|
public void WorldLoaded(World w)
|
|
{
|
|
world = w;
|
|
|
|
allies = w.Players.Single(p => p.InternalName == "Allies");
|
|
soviets = w.Players.Single(p => p.InternalName == "Soviets");
|
|
neutral = w.Players.Single(p => p.InternalName == "Neutral");
|
|
|
|
actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
|
|
|
|
attackLocation = actors["AttackLocation"];
|
|
coastWP1 = actors["CoastWP1"];
|
|
coastWP2 = actors["CoastWP2"];
|
|
|
|
paradrop1LZ = actors["Paradrop1LZ"];
|
|
paradrop1Entry = actors["Paradrop1Entry"];
|
|
paradrop2LZ = actors["Paradrop2LZ"];
|
|
paradrop2Entry = actors["Paradrop2Entry"];
|
|
|
|
var t1 = actors["ViewportTarget1"];
|
|
var t2 = actors["ViewportTarget2"];
|
|
var t3 = actors["ViewportTarget3"];
|
|
var t4 = actors["ViewportTarget4"];
|
|
var t5 = actors["ViewportTarget5"];
|
|
viewportTargets = new[] { t1, t2, t3, t4, t5 }.Select(t => t.Location.ToInt2()).ToList();
|
|
|
|
offmapAttackerSpawn1 = actors["OffmapAttackerSpawn1"];
|
|
offmapAttackerSpawn2 = actors["OffmapAttackerSpawn2"];
|
|
offmapAttackerSpawn3 = actors["OffmapAttackerSpawn3"];
|
|
offmapAttackerSpawns = new[] { offmapAttackerSpawn1, offmapAttackerSpawn2, offmapAttackerSpawn3 };
|
|
|
|
heavyTankSpawn = actors["HeavyTankSpawn"];
|
|
heavyTankWP = actors["HeavyTankWP"];
|
|
mediumTankChronoSpawn = actors["MediumTankChronoSpawn"];
|
|
|
|
chronosphere = actors["Chronosphere"];
|
|
ironCurtain = actors["IronCurtain"];
|
|
|
|
mig1Waypoints = new[] { actors["Mig11"], actors["Mig12"], actors["Mig13"], actors["Mig14"] }.Select(a => a.Location).ToArray();
|
|
mig2Waypoints = new[] { actors["Mig21"], actors["Mig22"], actors["Mig23"], actors["Mig24"] }.Select(a => a.Location).ToArray();
|
|
|
|
chinook1Entry = actors["Chinook1Entry"];
|
|
chinook2Entry = actors["Chinook2Entry"];
|
|
chinook1LZ = actors["Chinook1LZ"];
|
|
chinook2LZ = actors["Chinook2LZ"];
|
|
|
|
alliedBarracks = actors["AlliedBarracks"];
|
|
alliedWarFactory = actors["AlliedWarFactory"];
|
|
|
|
InitializeAlliedFactories();
|
|
|
|
foreach (var actor in actors.Values)
|
|
{
|
|
if (actor.Owner == allies && actor.HasTrait<AutoTarget>())
|
|
actor.Trait<AutoTarget>().stance = UnitStance.Defend;
|
|
|
|
if (actor.IsInWorld && (actor.HasTrait<Bridge>() || actor.Owner == allies || (actor.Owner == soviets && actor.HasTrait<Building>())))
|
|
actor.AddTrait(new Invulnerable());
|
|
}
|
|
|
|
viewportOrigin = viewportTargets[0];
|
|
viewportTargetNumber = 1;
|
|
viewportTarget = viewportTargets[1];
|
|
Game.viewport.Center(viewportOrigin);
|
|
Sound.SoundVolumeModifier = 0.1f;
|
|
}
|
|
}
|
|
|
|
class DesertShellmapAutoUnloadInfo : TraitInfo<DesertShellmapAutoUnload>, Requires<CargoInfo> { }
|
|
|
|
class DesertShellmapAutoUnload : INotifyDamage
|
|
{
|
|
public void Damaged(Actor self, AttackInfo e)
|
|
{
|
|
var cargo = self.Trait<Cargo>();
|
|
if (!cargo.IsEmpty(self) && !(self.GetCurrentActivity() is UnloadCargo))
|
|
self.QueueActivity(false, new UnloadCargo(true));
|
|
}
|
|
}
|
|
}
|