Merge remote-tracking branch 'scott/allies'

This commit is contained in:
Chris Forbes
2012-10-13 13:52:21 +13:00
33 changed files with 4526 additions and 299 deletions

View File

@@ -23,8 +23,10 @@ namespace OpenRA.Widgets
public int VisualHeight = ChromeMetrics.Get<int>("ButtonDepth");
public string Font = ChromeMetrics.Get<string>("ButtonFont");
public bool Disabled = false;
public bool Highlighted = false;
public Func<string> GetText;
public Func<bool> IsDisabled;
public Func<bool> IsHighlighted;
public Action<MouseInput> OnMouseDown = _ => {};
public Action<MouseInput> OnMouseUp = _ => {};
@@ -39,6 +41,7 @@ namespace OpenRA.Widgets
OnMouseUp = _ => OnClick();
OnKeyPress = _ => OnClick();
IsDisabled = () => Disabled;
IsHighlighted = () => Highlighted;
}
protected ButtonWidget(ButtonWidget widget)
@@ -52,6 +55,8 @@ namespace OpenRA.Widgets
OnMouseDown = widget.OnMouseDown;
Disabled = widget.Disabled;
IsDisabled = widget.IsDisabled;
Highlighted = widget.Highlighted;
IsHighlighted = widget.IsHighlighted;
OnMouseUp = mi => OnClick();
OnKeyPress = _ => OnClick();
@@ -124,13 +129,14 @@ namespace OpenRA.Widgets
{
var rb = RenderBounds;
var disabled = IsDisabled();
var highlighted = IsHighlighted();
var font = Game.Renderer.Fonts[Font];
var text = GetText();
var s = font.Measure(text);
var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0);
DrawBackground(rb, disabled, Depressed, Ui.MouseOverWidget == this);
DrawBackground(rb, disabled, Depressed, Ui.MouseOverWidget == this, highlighted);
font.DrawText(text, new int2(rb.X + (UsableWidth - s.X)/ 2, rb.Y + (Bounds.Height - s.Y) / 2) + stateOffset,
disabled ? Color.Gray : Color.White);
}
@@ -138,17 +144,19 @@ namespace OpenRA.Widgets
public override Widget Clone() { return new ButtonWidget(this); }
public virtual int UsableWidth { get { return Bounds.Width; } }
public virtual void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover)
public virtual void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted)
{
ButtonWidget.DrawBackground("button", rect, disabled, pressed, hover);
ButtonWidget.DrawBackground("button", rect, disabled, pressed, hover, highlighted);
}
public static void DrawBackground(string baseName, Rectangle rect, bool disabled, bool pressed, bool hover)
public static void DrawBackground(string baseName, Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted)
{
var state = disabled ? "-disabled" :
pressed ? "-pressed" :
hover ? "-hover" :
"";
if (highlighted)
state += "-highlighted";
WidgetUtils.DrawPanel(baseName + state, rect);
}

View File

@@ -79,11 +79,11 @@ namespace OpenRA.Widgets
var thumbHover = Ui.MouseOverWidget == this && thumbRect.Contains(Viewport.LastMousePos);
WidgetUtils.DrawPanel(Background, backgroundRect);
WidgetUtils.DrawPanel("scrollpanel-bg", scrollbarRect);
ButtonWidget.DrawBackground("button", upButtonRect, upDisabled, UpPressed, upHover);
ButtonWidget.DrawBackground("button", downButtonRect, downDisabled, DownPressed, downHover);
ButtonWidget.DrawBackground("button", upButtonRect, upDisabled, UpPressed, upHover, false);
ButtonWidget.DrawBackground("button", downButtonRect, downDisabled, DownPressed, downHover, false);
if (thumbHeight > 0)
ButtonWidget.DrawBackground("scrollthumb", thumbRect, false, Focused && thumbHover, thumbHover);
ButtonWidget.DrawBackground("scrollthumb", thumbRect, false, Focused && thumbHover, thumbHover, false);
var upOffset = !UpPressed || upDisabled ? 4 : 4 + ButtonDepth;
var downOffset = !DownPressed || downDisabled ? 4 : 4 + ButtonDepth;

View File

@@ -118,7 +118,7 @@ namespace OpenRA.Widgets
// Thumb
var thumbHover = Ui.MouseOverWidget == this && tr.Contains(Viewport.LastMousePos);
ButtonWidget.DrawBackground("scrollthumb", tr, IsDisabled(), isMoving, thumbHover);
ButtonWidget.DrawBackground("scrollthumb", tr, IsDisabled(), isMoving, thumbHover, false);
}
}
}

View File

@@ -138,8 +138,8 @@ namespace OpenRA.Mods.Cnc.Widgets
var rightHover = Ui.MouseOverWidget == this && rightButtonRect.Contains(Viewport.LastMousePos);
WidgetUtils.DrawPanel("panel-black", rb);
ButtonWidget.DrawBackground("button", leftButtonRect, leftDisabled, leftPressed, leftHover);
ButtonWidget.DrawBackground("button", rightButtonRect, rightDisabled, rightPressed, rightHover);
ButtonWidget.DrawBackground("button", leftButtonRect, leftDisabled, leftPressed, leftHover, false);
ButtonWidget.DrawBackground("button", rightButtonRect, rightDisabled, rightPressed, rightHover, false);
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", leftPressed || leftDisabled ? "left_pressed" : "left_arrow"),
new float2(leftButtonRect.Left + 2, leftButtonRect.Top + 2));
@@ -157,7 +157,7 @@ namespace OpenRA.Mods.Cnc.Widgets
var rect = new Rectangle(origin.X + ContentWidth, origin.Y, TabWidth, rb.Height);
var hover = !leftHover && !rightHover && Ui.MouseOverWidget == this && rect.Contains(Viewport.LastMousePos);
var baseName = tab.Queue == CurrentQueue ? "button-toggled" : "button";
ButtonWidget.DrawBackground(baseName, rect, false, false, hover);
ButtonWidget.DrawBackground(baseName, rect, false, false, hover, false);
ContentWidth += TabWidth - 1;
int2 textSize = font.Measure(tab.Name);

View File

@@ -53,10 +53,10 @@ namespace OpenRA.Mods.Cnc.Widgets
tooltipContainer.Value.RemoveTooltip();
}
public override void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover)
public override void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted)
{
var baseName = IsToggled() ? "button-toggled" : "button";
ButtonWidget.DrawBackground(baseName, rect, disabled, pressed, hover);
ButtonWidget.DrawBackground(baseName, rect, disabled, pressed, hover, highlighted);
}
}
}

View File

@@ -0,0 +1,29 @@
#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 OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class ContainsCrateInfo : TraitInfo<ContainsCrate> { }
public class ContainsCrate : INotifyKilled
{
public void Killed(Actor self, AttackInfo e)
{
self.World.AddFrameEndTask(w => w.CreateActor("crate", new TypeDictionary
{
new LocationInit(self.Location),
new OwnerInit(self.World.WorldActor.Owner),
}));
}
}
}

View File

@@ -0,0 +1,39 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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.Linq;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Crates
{
class HealUnitsCrateActionInfo : CrateActionInfo
{
public override object Create(ActorInitializer init) { return new HealUnitsCrateAction(init.self, this); }
}
class HealUnitsCrateAction : CrateAction
{
public HealUnitsCrateAction(Actor self, HealUnitsCrateActionInfo info)
: base(self, info) { }
public override void Activate(Actor collector)
{
base.Activate(collector);
foreach (var unit in collector.World.Actors.Where(a => a.Owner == collector.Owner))
{
var health = unit.TraitOrDefault<Health>();
if (health != null && !health.IsDead)
{
health.InflictDamage(unit, unit, -(health.MaxHP - health.HP), null, true);
}
}
}
}
}

View File

@@ -8,12 +8,14 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
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;
@@ -22,15 +24,23 @@ namespace OpenRA.Mods.RA.Missions
{
class Allies01ScriptInfo : TraitInfo<Allies01Script>, Requires<SpawnMapActorsInfo> { }
class Allies01Script : IWorldLoaded, ITick
class Allies01Script : IHasObjectives, IWorldLoaded, ITick
{
static readonly string[] Objectives =
public event ObjectivesUpdatedEventHandler OnObjectivesUpdated;
public IEnumerable<Objective> Objectives { get { return objectives.Values; } }
Dictionary<int, Objective> objectives = new Dictionary<int, Objective>
{
"Find Einstein. Tanya and Einstein must survive.",
"Wait for the helicopter and extract Einstein. Tanya and Einstein must survive."
{ FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) },
{ ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) }
};
int currentObjective;
const int FindEinsteinID = 0;
const int ExtractEinsteinID = 1;
const string FindEinstein = "Find Einstein. Tanya and Einstein must survive.";
const string ExtractEinstein = "Wait for the helicopter and extract Einstein. Tanya and Einstein must survive.";
Player allies;
Player soviets;
@@ -65,15 +75,8 @@ namespace OpenRA.Mods.RA.Missions
const int LabClearRange = 5;
const string EinsteinName = "einstein";
const string TanyaName = "e7";
const string ChinookName = "tran";
const string SignalFlareName = "flare";
void DisplayObjective()
{
Game.AddChatLine(Color.LimeGreen, "Objective", Objectives[currentObjective]);
Sound.Play("bleep6.aud");
}
void MissionFailed(string text)
{
if (allies.WinState != WinState.Undefined)
@@ -106,18 +109,11 @@ namespace OpenRA.Mods.RA.Missions
{
return;
}
// display current objective every so often
if (world.FrameNumber % 1500 == 1)
{
DisplayObjective();
}
// taunt every so often
if (world.FrameNumber % 1000 == 0)
{
Sound.Play(Taunts[world.SharedRandom.Next(Taunts.Length)]);
}
// objectives
if (currentObjective == 0)
if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress)
{
if (AlliesControlLab())
{
@@ -125,40 +121,48 @@ namespace OpenRA.Mods.RA.Missions
Sound.Play("flaren1.aud");
SpawnEinsteinAtLab();
SendShips();
currentObjective++;
DisplayObjective();
objectives[FindEinsteinID].Status = ObjectiveStatus.Completed;
objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
OnObjectivesUpdated(true);
currentAttackWaveFrameNumber = world.FrameNumber;
}
if (lab.Destroyed)
{
objectives[FindEinsteinID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
MissionFailed("Einstein was killed.");
}
}
else if (currentObjective == 1)
if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress)
{
SendAttackWave();
if (world.FrameNumber >= currentAttackWaveFrameNumber + 600)
{
Sound.Play("enmyapp1.aud");
SendAttackWave(AttackWave);
SpawnAttackWave(AttackWave);
currentAttackWave++;
currentAttackWaveFrameNumber = world.FrameNumber;
if (currentAttackWave >= EinsteinChinookAttackWave)
{
SendAttackWave(LastAttackWaveAddition);
SpawnAttackWave(LastAttackWaveAddition);
}
if (currentAttackWave == EinsteinChinookAttackWave)
{
FlyEinsteinFromExtractionLZ();
ExtractEinsteinAtLZ();
}
}
if (einsteinChinook != null)
{
if (einsteinChinook.Destroyed)
{
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
MissionFailed("The extraction helicopter was destroyed.");
}
else if (!world.Map.IsInMap(einsteinChinook.Location) && einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein))
{
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Completed;
OnObjectivesUpdated(true);
MissionAccomplished("Einstein was rescued.");
}
}
@@ -186,22 +190,47 @@ namespace OpenRA.Mods.RA.Missions
world.CreateActor(SignalFlareName, new TypeDictionary { new OwnerInit(allies), new LocationInit(extractionLZ.Location) });
}
void SendAttackWave(IEnumerable<string> wave)
void SpawnAttackWave(IEnumerable<string> wave)
{
foreach (var unit in wave)
{
var spawnActor = world.SharedRandom.Next(2) == 0 ? attackEntryPoint1 : attackEntryPoint2;
var actor = world.CreateActor(unit, new TypeDictionary { new OwnerInit(soviets), new LocationInit(spawnActor.Location) });
}
}
void SendAttackWave()
{
foreach (var unit in world.Actors.Where(
a => a != world.WorldActor
&& a.IsInWorld
&& a.Owner == soviets
&& !a.IsDead()
&& a.IsIdle
&& a.HasTrait<Mobile>()
&& a.HasTrait<AttackBase>()))
{
Activity innerActivity;
if (einstein != null && einstein.IsInWorld)
if (einstein != null)
{
if (einstein.IsInWorld)
{
innerActivity = new Attack(Target.FromActor(einstein), 3);
}
else
{
var container = world.UnitContaining(einstein);
if (container != null && !container.HasTrait<Aircraft>() && container.HasTrait<Mobile>())
{
innerActivity = new Attack(Target.FromActor(container), 3);
}
else
{
innerActivity = new Move.Move(extractionLZ.Location, 3);
}
actor.QueueActivity(new AttackMove.AttackMoveActivity(actor, innerActivity));
}
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, innerActivity));
}
}
}
@@ -214,16 +243,9 @@ namespace OpenRA.Mods.RA.Missions
}
}
IEnumerable<Actor> UnitsNearActor(Actor actor, int range)
{
return world.FindUnitsInCircle(actor.CenterLocation, Game.CellSize * range)
.Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && a.HasTrait<IMove>() && !a.Owner.NonCombatant);
}
bool AlliesControlLab()
{
var units = UnitsNearActor(lab, LabClearRange);
return units.Any() && units.All(a => a.Owner == allies);
return MissionUtils.AreaSecuredWithUnits(world, allies, lab.CenterLocation, LabClearRange);
}
void SpawnEinsteinAtLab()
@@ -242,32 +264,31 @@ namespace OpenRA.Mods.RA.Missions
}
}
void FlyEinsteinFromExtractionLZ()
void ExtractEinsteinAtLZ()
{
einsteinChinook = world.CreateActor(ChinookName, new TypeDictionary { new OwnerInit(allies), new LocationInit(extractionLZEntryPoint.Location) });
einsteinChinook.QueueActivity(new HeliFly(extractionLZ.CenterLocation));
einsteinChinook.QueueActivity(new Turn(0));
einsteinChinook.QueueActivity(new HeliLand(true, 0));
einsteinChinook.QueueActivity(new WaitFor(() => einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein)));
einsteinChinook.QueueActivity(new Wait(150));
einsteinChinook.QueueActivity(new HeliFly(chinookExitPoint.CenterLocation));
einsteinChinook.QueueActivity(new RemoveSelf());
einsteinChinook = MissionUtils.ExtractUnitWithChinook(
world,
allies,
einstein,
extractionLZEntryPoint.Location,
extractionLZ.Location,
chinookExitPoint.Location);
}
void FlyTanyaToInsertionLZ()
void InsertTanyaAtLZ()
{
tanya = world.CreateActor(false, TanyaName, new TypeDictionary { new OwnerInit(allies) });
var chinook = world.CreateActor(ChinookName, new TypeDictionary { new OwnerInit(allies), new LocationInit(insertionLZEntryPoint.Location) });
chinook.Trait<Cargo>().Load(chinook, tanya);
chinook.QueueActivity(new HeliFly(insertionLZ.CenterLocation));
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0));
chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new CallFunc(() => Sound.Play("laugh1.aud")));
chinook.QueueActivity(new CallFunc(() => tanya.QueueActivity(new Move.Move(insertionLZ.Location - new CVec(1, 0)))));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(chinookExitPoint.CenterLocation));
chinook.QueueActivity(new RemoveSelf());
tanya = MissionUtils.InsertUnitWithChinook(
world,
allies,
TanyaName,
insertionLZEntryPoint.Location,
insertionLZ.Location,
chinookExitPoint.Location,
unit =>
{
Sound.Play("laugh1.aud");
unit.QueueActivity(new Move.Move(insertionLZ.Location - new CVec(1, 0)));
}).Second;
}
void SetAlliedUnitsToDefensiveStance()
@@ -310,7 +331,7 @@ namespace OpenRA.Mods.RA.Missions
{
Media.PlayFMVFullscreen(w, "landing.vqa", () =>
{
FlyTanyaToInsertionLZ();
InsertTanyaAtLZ();
SendPatrol();
PlayMusic();
});

View File

@@ -16,6 +16,8 @@ using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Air;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Effects;
using OpenRA.Mods.RA.Move;
using OpenRA.Network;
using OpenRA.Traits;
using OpenRA.Widgets;
@@ -24,15 +26,34 @@ namespace OpenRA.Mods.RA.Missions
{
class Allies02ScriptInfo : TraitInfo<Allies02Script>, Requires<SpawnMapActorsInfo> { }
class Allies02Script : IWorldLoaded, ITick
class Allies02Script : IHasObjectives, IWorldLoaded, ITick
{
static readonly string[] Objectives =
public event ObjectivesUpdatedEventHandler OnObjectivesUpdated;
public IEnumerable<Objective> Objectives { get { return objectives.Values; } }
Dictionary<int, Objective> objectives = new Dictionary<int, Objective>()
{
"Hold off the Soviet forces and destroy the SAM sites. Tanya and Einstein must survive.",
"Wait for the helicopter and extract Einstein. Tanya and Einstein must survive."
{ FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) },
{ DestroySamSitesID, new Objective(ObjectiveType.Primary, DestroySamSites, ObjectiveStatus.InProgress) },
{ ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) },
{ MaintainPresenceID, new Objective(ObjectiveType.Primary, MaintainPresence, ObjectiveStatus.InProgress) },
{ FewDeathsID, new Objective(ObjectiveType.Secondary, "", ObjectiveStatus.InProgress) }
};
int currentObjective;
const int FindEinsteinID = 0;
const int DestroySamSitesID = 1;
const int ExtractEinsteinID = 2;
const int MaintainPresenceID = 3;
const int FewDeathsID = 4;
const string FindEinstein = "Find Einstein's crashed helicopter. Tanya must survive.";
const string DestroySamSites = "Destroy the SAM sites. Tanya must survive.";
const string ExtractEinstein = "Wait for the helicopter and extract Einstein. Tanya and Einstein must survive.";
const string MaintainPresence = "Maintain an Allied presence in the area. Reinforcements will arrive soon.";
const string FewDeathsTemplate = "Lose fewer than {0}/{1} units.";
const int DeathsThreshold = 100;
Actor sam1;
Actor sam2;
@@ -42,17 +63,29 @@ namespace OpenRA.Mods.RA.Missions
Actor einstein;
Actor engineer;
Actor engineerMiss;
Actor chinookHusk;
Actor allies2BasePoint;
Actor reinforcementsEntryPoint;
Actor extractionLZEntryPoint;
Actor extractionLZ;
Actor badgerEntryPoint;
Actor badgerDropPoint;
Actor badgerEntryPoint1;
Actor badgerEntryPoint2;
Actor badgerDropPoint1;
Actor badgerDropPoint2;
Actor badgerDropPoint3;
Actor parabombPoint1;
Actor parabombPoint2;
Actor sovietRallyPoint;
Actor flamersEntryPoint;
Actor tanksEntryPoint;
Actor townPoint;
Actor sovietTownAttackPoint1;
Actor sovietTownAttackPoint2;
Actor yakEntryPoint;
Actor yakAttackPoint;
Actor yak;
Actor sovietReinforcementsEntryPoint1;
Actor sovietReinforcementsEntryPoint2;
Actor einsteinChinook;
@@ -67,36 +100,56 @@ namespace OpenRA.Mods.RA.Missions
CountdownTimer reinforcementsTimer;
CountdownTimerWidget reinforcementsTimerWidget;
List<Actor> sovietReinforcementsUnits = new List<Actor>();
const string InfantryQueueName = "Infantry";
const string VehicleQueueName = "Vehicle";
readonly List<string> sovietInfantry = new List<string> { "e1", "e2", "e3" };
readonly List<string> sovietVehicles = new List<string> { "3tnk" };
static readonly string[] SovietVehicleAdditions = { "v2rl" };
const int SovietGroupSize = 5;
const int SovietVehicleAdditionsTicks = 1500 * 4;
static readonly string[] SovietInfantry = { "e1", "e2", "e3" };
static readonly string[] SovietVehicles1 = { "3tnk" };
static readonly string[] SovietVehicles2 = { "3tnk", "v2rl" };
const int SovietVehiclesUpgradeTicks = 1500 * 4;
const int SovietGroupSize = 8;
const int SovietHelperCash = 2000;
const int ReinforcementsTicks = 1500 * 12;
static readonly string[] Reinforcements = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "1tnk", "1tnk", "jeep", "e1", "e1", "e1", "e1", "e3", "e3", "mcv" };
const int ReinforcementsCash = 2000;
static readonly string[] Reinforcements =
{
"2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "2tnk",
"1tnk", "1tnk",
"jeep",
"e1", "e1", "e1", "e1",
"e3", "e3",
"mcv",
"truk", "truk", "truk", "truk", "truk", "truk"
};
const int SovietReinforcementsTicks = 1500 * 16;
static readonly string[] SovietReinforcements =
{
"3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk",
"v2rl", "v2rl", "v2rl", "v2rl",
"ftrk", "ftrk"
};
const int ParatroopersTicks = 1500 * 10;
static readonly string[] Paratroopers = { "e1", "e1", "e1", "e2", "3tnk" };
const string BadgerName = "badr";
const int ParabombTicks = 750;
const int FlamersTicks = 1500 * 7;
const int FlamersTicks = 1500 * 2;
static readonly string[] Flamers = { "e4", "e4", "e4", "e4", "e4" };
const string ApcName = "apc";
const string ChinookName = "tran";
const string SignalFlareName = "flare";
const string EngineerName = "e6";
const int EngineerMissClearRange = 5;
const int ParatroopersTicks = 1500 * 5;
static readonly string[] Badger1Passengers = { "e1", "e1", "e1", "e2", "3tnk" };
static readonly string[] Badger2Passengers = { "e1", "e1", "e1", "e2", "e2" };
static readonly string[] Badger3Passengers = { "e1", "e1", "e1", "e2", "e2" };
void DisplayObjective()
{
Game.AddChatLine(Color.LimeGreen, "Objective", Objectives[currentObjective]);
Sound.Play("bleep6.aud");
}
const int TanksTicks = 1500 * 11;
static readonly string[] Tanks = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk" };
const string SignalFlareName = "flare";
const string YakName = "yak";
const int AlliedTownTransferRange = 15;
const int SovietTownAttackGroupRange = 5;
const int SovietTownMoveNearEnough = 3;
void MissionFailed(string text)
{
@@ -138,9 +191,9 @@ namespace OpenRA.Mods.RA.Missions
{
return;
}
if (world.FrameNumber % 3500 == 1)
if (world.FrameNumber % 50 == 1 && chinookHusk.IsInWorld)
{
DisplayObjective();
world.Add(new Smoke(world, chinookHusk.CenterLocation, "smoke_m"));
}
if (world.FrameNumber == 1)
{
@@ -150,15 +203,35 @@ namespace OpenRA.Mods.RA.Missions
reinforcementsTimer.Tick();
if (world.FrameNumber == ParatroopersTicks)
{
ParadropSovietUnits();
MissionUtils.Paradrop(world, soviets, Badger1Passengers, badgerEntryPoint1.Location, badgerDropPoint1.Location);
MissionUtils.Paradrop(world, soviets, Badger2Passengers, badgerEntryPoint1.Location + new CVec(3, 0), badgerDropPoint2.Location);
MissionUtils.Paradrop(world, soviets, Badger3Passengers, badgerEntryPoint1.Location + new CVec(6, 0), badgerDropPoint3.Location);
}
if (world.FrameNumber == FlamersTicks)
{
RushSovietFlamers();
}
if (world.FrameNumber == SovietVehicleAdditionsTicks)
if (world.FrameNumber == TanksTicks)
{
sovietVehicles.AddRange(SovietVehicleAdditions);
RushSovietUnits();
}
if (world.FrameNumber == ParabombTicks)
{
MissionUtils.Parabomb(world, soviets, badgerEntryPoint2.Location, parabombPoint1.Location);
MissionUtils.Parabomb(world, soviets, badgerEntryPoint2.Location + new CVec(0, 3), parabombPoint2.Location);
}
if (world.FrameNumber == SovietReinforcementsTicks)
{
SendSovietReinforcements();
}
if (yak == null || (yak != null && !yak.IsDead() && (yak.GetCurrentActivity() is FlyCircle || yak.IsIdle)))
{
var alliedUnitsNearYakPoint = world.FindAliveCombatantActorsInCircle(yakAttackPoint.CenterLocation, 10)
.Where(a => a.Owner != soviets && a.HasTrait<IMove>() && a != tanya && a != einstein && a != engineer);
if (alliedUnitsNearYakPoint.Any())
{
YakStrafe(alliedUnitsNearYakPoint);
}
}
if (world.FrameNumber % 25 == 0)
{
@@ -166,30 +239,47 @@ namespace OpenRA.Mods.RA.Missions
BuildSovietUnits();
ManageSovietUnits();
}
if (!engineerMiss.Destroyed && engineer == null && AlliesControlMiss())
UpdateDeaths();
if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress)
{
SpawnEngineerAtMiss();
engineerMiss.QueueActivity(new Demolish(engineerMiss, 0));
if (AlliesNearTown())
{
objectives[FindEinsteinID].Status = ObjectiveStatus.Completed;
OnObjectivesUpdated(true);
TransferTownUnitsToAllies();
SovietsAttackTown();
}
if (currentObjective == 0)
}
if (objectives[DestroySamSitesID].Status == ObjectiveStatus.InProgress)
{
if (sam1.Destroyed && sam2.Destroyed && sam3.Destroyed && sam4.Destroyed)
{
currentObjective++;
DisplayObjective();
objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed;
objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
OnObjectivesUpdated(true);
SpawnSignalFlare();
Sound.Play("flaren1.aud");
SendChinook();
ExtractEinsteinAtLZ();
}
}
else if (currentObjective == 1 && einsteinChinook != null)
if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null)
{
if (einsteinChinook.Destroyed)
{
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
MissionFailed("The extraction helicopter was destroyed.");
}
else if (!world.Map.IsInMap(einsteinChinook.Location) && einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein))
{
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Completed;
objectives[MaintainPresenceID].Status = ObjectiveStatus.Completed;
if (objectives[FewDeathsID].Status == ObjectiveStatus.InProgress)
{
objectives[FewDeathsID].Status = ObjectiveStatus.Completed;
}
OnObjectivesUpdated(true);
MissionAccomplished("Einstein was rescued.");
}
}
@@ -201,18 +291,58 @@ namespace OpenRA.Mods.RA.Missions
{
MissionFailed("Einstein was killed.");
}
else if (!world.Actors.Any(a => a.IsInWorld && a.HasTrait<Building>() && !a.HasTrait<Wall>() && a.Owner == allies2))
world.AddFrameEndTask(w =>
{
if (!world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20).Any(a => a.HasTrait<Building>() && !a.HasTrait<Wall>() && a.Owner == allies2))
{
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
MissionFailed("The Allied reinforcements have been defeated.");
}
});
}
void UpdateDeaths()
{
var unitDeaths = allies1.Deaths + allies2.Deaths;
objectives[FewDeathsID].Text = FewDeathsTemplate.F(unitDeaths, DeathsThreshold);
OnObjectivesUpdated(false);
if (unitDeaths >= DeathsThreshold && objectives[FewDeathsID].Status == ObjectiveStatus.InProgress)
{
objectives[FewDeathsID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
}
}
void YakStrafe(IEnumerable<Actor> candidates)
{
if (yak == null)
{
yak = world.CreateActor(YakName, new TypeDictionary
{
new LocationInit(yakEntryPoint.Location),
new OwnerInit(soviets),
new FacingInit(Util.GetFacing(yakAttackPoint.Location - yakEntryPoint.Location, 0)),
new AltitudeInit(Rules.Info[YakName].Traits.Get<PlaneInfo>().CruiseAltitude),
});
}
if (yak.Trait<LimitedAmmo>().HasAmmo())
{
yak.QueueActivity(new FlyAttack(Target.FromActor(candidates.Random(world.SharedRandom))));
}
else
{
yak.QueueActivity(new FlyOffMap());
yak.QueueActivity(new RemoveSelf());
}
}
void AddSovietCashIfRequired()
{
var resources = soviets.PlayerActor.Trait<PlayerResources>();
if (resources.Cash < ReinforcementsCash)
if (resources.Cash < SovietHelperCash)
{
resources.GiveCash(ReinforcementsCash);
resources.GiveCash(SovietHelperCash);
}
}
@@ -225,66 +355,75 @@ namespace OpenRA.Mods.RA.Missions
}
if (!sovietBarracks.Destroyed)
{
BuildSovietUnit(InfantryQueueName, sovietInfantry.Random(world.SharedRandom));
BuildSovietUnit(InfantryQueueName, SovietInfantry.Random(world.SharedRandom));
}
if (!sovietWarFactory.Destroyed)
{
BuildSovietUnit(VehicleQueueName, sovietVehicles.Random(world.SharedRandom));
var vehicles = world.FrameNumber >= SovietVehiclesUpgradeTicks ? SovietVehicles2 : SovietVehicles1;
BuildSovietUnit(VehicleQueueName, vehicles.Random(world.SharedRandom));
}
}
void ManageSovietUnits()
{
var idleSovietUnits = ForcesNearActor(allies2BasePoint, 10).Where(a => a.Owner == soviets && a.IsIdle);
var idleSovietUnitsAtRP = ForcesNearActor(sovietRallyPoint, 5).Where(a => a.Owner == soviets && a.IsIdle);
var idleSovietUnitsAtRP = world.FindAliveCombatantActorsInCircle(sovietRallyPoint.CenterLocation, 3).Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
if (idleSovietUnitsAtRP.Count() >= SovietGroupSize)
{
idleSovietUnits = idleSovietUnits.Union(idleSovietUnitsAtRP);
}
foreach (var unit in idleSovietUnits)
var firstUnit = idleSovietUnitsAtRP.FirstOrDefault();
if (firstUnit != null)
{
var closestAlliedBuilding = ClosestAlliedBuilding(unit, 20);
var closestAlliedBuilding = ClosestAlliedBuilding(firstUnit, 40);
if (closestAlliedBuilding != null)
{
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(closestAlliedBuilding.Location, 3)));
foreach (var unit in idleSovietUnitsAtRP)
{
unit.Trait<Mobile>().Nudge(unit, unit, true);
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Attack(Target.FromActor(closestAlliedBuilding), 3)));
}
}
}
}
var idleSovietUnits = world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20).Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
foreach (var unit in idleSovietUnits)
{
var closestAlliedBuilding = ClosestAlliedBuilding(unit, 40);
if (closestAlliedBuilding != null)
{
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Attack(Target.FromActor(closestAlliedBuilding), 3)));
}
}
}
Actor ClosestAlliedBuilding(Actor actor, int range)
{
return BuildingsNearActor(actor, range)
.Where(a => a.Owner == allies2)
.OrderBy(a => (actor.Location - a.Location).LengthSquared)
.FirstOrDefault();
return MissionUtils.ClosestPlayerBuilding(world, allies2, actor.CenterLocation, range);
}
IEnumerable<Actor> ClosestAlliedBuildings(Actor actor, int range)
{
return MissionUtils.ClosestPlayerBuildings(world, allies2, actor.CenterLocation, range);
}
void InitializeSovietFactories()
{
sovietBarracks.Trait<RallyPoint>().rallyPoint = sovietRallyPoint.Location;
sovietWarFactory.Trait<RallyPoint>().rallyPoint = sovietRallyPoint.Location;
var sbrp = sovietBarracks.Trait<RallyPoint>();
var swrp = sovietWarFactory.Trait<RallyPoint>();
sbrp.rallyPoint = swrp.rallyPoint = sovietRallyPoint.Location;
sbrp.nearEnough = swrp.nearEnough = 3;
sovietBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietBarracks, true);
sovietWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietWarFactory, true);
}
IEnumerable<ProductionQueue> FindQueues(Player player, string category)
{
return world.ActorsWithTrait<ProductionQueue>()
.Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category)
.Select(a => a.Trait);
}
void BuildSovietUnit(string category, string unit)
{
var queue = FindQueues(soviets, category).FirstOrDefault(q => q.CurrentItem() == null);
var queue = MissionUtils.FindQueues(world, soviets, category).FirstOrDefault(q => q.CurrentItem() == null);
if (queue == null)
{
return;
}
var order = Order.StartProduction(queue.self, unit, 1);
if (Game.IsHost)
{
world.IssueOrder(order);
world.IssueOrder(Order.StartProduction(queue.self, unit, 1));
}
}
@@ -296,32 +435,76 @@ namespace OpenRA.Mods.RA.Missions
void StartReinforcementsTimer()
{
Sound.Play("timergo1.aud");
reinforcementsTimer = new CountdownTimer(ReinforcementsTicks, ReinforcementsTimerExpired);
reinforcementsTimerWidget = new CountdownTimerWidget(reinforcementsTimer, "Reinforcements arrive in", new float2(128, 96));
reinforcementsTimer = new CountdownTimer(ReinforcementsTicks, ReinforcementsTimerExpired, true);
reinforcementsTimerWidget = new CountdownTimerWidget(
reinforcementsTimer,
"Allied reinforcements arrive in: {0}",
new float2(Game.viewport.Width * 0.35f, Game.viewport.Height * 0.9f));
Ui.Root.AddChild(reinforcementsTimerWidget);
}
void ParadropSovietUnits()
void SendSovietReinforcements()
{
var badger = world.CreateActor(BadgerName, new TypeDictionary
foreach (var entryPoint in new[] { sovietReinforcementsEntryPoint1, sovietReinforcementsEntryPoint2 })
{
new LocationInit(badgerEntryPoint.Location),
new OwnerInit(soviets),
new FacingInit(Util.GetFacing(badgerDropPoint.Location - badgerEntryPoint.Location, 0)),
new AltitudeInit(Rules.Info[BadgerName].Traits.Get<PlaneInfo>().CruiseAltitude),
foreach (var unit in SovietReinforcements)
{
var u = world.CreateActor(unit, new TypeDictionary
{
new LocationInit(entryPoint.Location),
new FacingInit(Util.GetFacing(allies2BasePoint.Location - entryPoint.Location, 0)),
new OwnerInit(soviets)
});
badger.QueueActivity(new FlyAttack(Target.FromCell(badgerDropPoint.Location)));
badger.Trait<ParaDrop>().SetLZ(badgerDropPoint.Location);
var cargo = badger.Trait<Cargo>();
foreach (var unit in Paratroopers)
u.QueueActivity(new Move.Move(sovietRallyPoint.Location, 3));
}
}
}
void ReinforcementsTimerExpired(CountdownTimer countdownTimer)
{
cargo.Load(badger, world.CreateActor(false, unit, new TypeDictionary { new OwnerInit(soviets) }));
reinforcementsTimerWidget.Visible = false;
SendReinforcements();
Sound.Play("aarrivs1.aud");
}
void SendReinforcements()
{
foreach (var unit in Reinforcements)
{
var u = world.CreateActor(unit, new TypeDictionary
{
new LocationInit(reinforcementsEntryPoint.Location),
new FacingInit(0),
new OwnerInit(allies2)
});
u.QueueActivity(new Move.Move(allies2BasePoint.Location));
}
}
void RushSovietUnits()
{
var closestAlliedBuildings = ClosestAlliedBuildings(badgerDropPoint1, 40);
if (!closestAlliedBuildings.Any())
{
return;
}
foreach (var tank in Tanks)
{
var unit = world.CreateActor(tank, new TypeDictionary
{
new OwnerInit(soviets),
new LocationInit(tanksEntryPoint.Location)
});
foreach (var building in closestAlliedBuildings)
{
unit.QueueActivity(new Attack(Target.FromActor(building), 3));
}
}
}
void RushSovietFlamers()
{
var closestAlliedBuilding = ClosestAlliedBuilding(badgerDropPoint, 10);
var closestAlliedBuilding = ClosestAlliedBuilding(badgerDropPoint1, 40);
if (closestAlliedBuilding == null)
{
return;
@@ -336,67 +519,41 @@ namespace OpenRA.Mods.RA.Missions
apc.QueueActivity(new UnloadCargo(true));
}
void ReinforcementsTimerExpired(CountdownTimer countdownTimer)
void ExtractEinsteinAtLZ()
{
reinforcementsTimerWidget.Visible = false;
SendReinforcements();
einsteinChinook = MissionUtils.ExtractUnitWithChinook(
world,
allies1,
einstein,
extractionLZEntryPoint.Location,
extractionLZ.Location,
extractionLZEntryPoint.Location);
}
void SendReinforcements()
bool AlliesNearTown()
{
Sound.Play("reinfor1.aud");
var resources = allies2.PlayerActor.Trait<PlayerResources>();
resources.GiveCash(2000);
foreach (var unit in Reinforcements)
return world.FindAliveCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange)
.Any(a => a.Owner == allies1 && a.HasTrait<IMove>());
}
void TransferTownUnitsToAllies()
{
var actor = world.CreateActor(unit, new TypeDictionary
foreach (var unit in world.FindAliveNonCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange).Where(a => a.HasTrait<IMove>()))
{
new LocationInit(reinforcementsEntryPoint.Location),
new FacingInit(0),
new OwnerInit(allies2)
});
actor.QueueActivity(new Move.Move(allies2BasePoint.Location));
unit.ChangeOwner(allies1);
}
}
void SendChinook()
void SovietsAttackTown()
{
einsteinChinook = world.CreateActor(ChinookName, new TypeDictionary { new OwnerInit(allies1), new LocationInit(extractionLZEntryPoint.Location) });
einsteinChinook.QueueActivity(new HeliFly(extractionLZ.CenterLocation));
einsteinChinook.QueueActivity(new Turn(0));
einsteinChinook.QueueActivity(new HeliLand(true, 0));
einsteinChinook.QueueActivity(new WaitFor(() => einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein)));
einsteinChinook.QueueActivity(new Wait(150));
einsteinChinook.QueueActivity(new HeliFly(extractionLZEntryPoint.CenterLocation));
einsteinChinook.QueueActivity(new RemoveSelf());
var sovietAttackUnits = world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint1.CenterLocation, SovietTownAttackGroupRange)
.Union(world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint2.CenterLocation, SovietTownAttackGroupRange))
.Union(world.FindAliveCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange))
.Where(a => a.HasTrait<IMove>() && a.Owner == soviets);
foreach (var unit in sovietAttackUnits)
{
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(townPoint.Location, SovietTownMoveNearEnough)));
}
IEnumerable<Actor> UnitsNearActor(Actor actor, int range)
{
return world.FindUnitsInCircle(actor.CenterLocation, Game.CellSize * range)
.Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && !a.Owner.NonCombatant);
}
IEnumerable<Actor> BuildingsNearActor(Actor actor, int range)
{
return UnitsNearActor(actor, range).Where(a => a.HasTrait<Building>() && !a.HasTrait<Wall>());
}
IEnumerable<Actor> ForcesNearActor(Actor actor, int range)
{
return UnitsNearActor(actor, range).Where(a => a.HasTrait<IMove>());
}
bool AlliesControlMiss()
{
var units = ForcesNearActor(engineerMiss, EngineerMissClearRange);
return units.Any() && units.All(a => a.Owner == allies1);
}
void SpawnEngineerAtMiss()
{
engineer = world.CreateActor(EngineerName, new TypeDictionary { new OwnerInit(allies1), new LocationInit(engineerMiss.Location) });
engineer.QueueActivity(new Move.Move(engineerMiss.Location + new CVec(5, 0)));
}
public void WorldLoaded(World w)
@@ -412,18 +569,31 @@ namespace OpenRA.Mods.RA.Missions
sam4 = actors["SAM4"];
tanya = actors["Tanya"];
einstein = actors["Einstein"];
engineer = actors["Engineer"];
chinookHusk = actors["ChinookHusk"];
allies2BasePoint = actors["Allies2BasePoint"];
reinforcementsEntryPoint = actors["ReinforcementsEntryPoint"];
extractionLZ = actors["ExtractionLZ"];
extractionLZEntryPoint = actors["ExtractionLZEntryPoint"];
badgerEntryPoint = actors["BadgerEntryPoint"];
badgerDropPoint = actors["BadgerDropPoint"];
engineerMiss = actors["EngineerMiss"];
badgerEntryPoint1 = actors["BadgerEntryPoint1"];
badgerEntryPoint2 = actors["BadgerEntryPoint2"];
badgerDropPoint1 = actors["BadgerDropPoint1"];
badgerDropPoint2 = actors["BadgerDropPoint2"];
badgerDropPoint3 = actors["BadgerDropPoint3"];
parabombPoint1 = actors["ParabombPoint1"];
parabombPoint2 = actors["ParabombPoint2"];
sovietBarracks = actors["SovietBarracks"];
sovietWarFactory = actors["SovietWarFactory"];
sovietRallyPoint = actors["SovietRallyPoint"];
flamersEntryPoint = actors["FlamersEntryPoint"];
tanksEntryPoint = actors["TanksEntryPoint"];
townPoint = actors["TownPoint"];
sovietTownAttackPoint1 = actors["SovietTownAttackPoint1"];
sovietTownAttackPoint2 = actors["SovietTownAttackPoint2"];
yakEntryPoint = actors["YakEntryPoint"];
yakAttackPoint = actors["YakAttackPoint"];
sovietReinforcementsEntryPoint1 = actors["SovietReinforcementsEntryPoint1"];
sovietReinforcementsEntryPoint2 = actors["SovietReinforcementsEntryPoint2"];
var shroud = w.WorldActor.Trait<Shroud>();
shroud.Explore(w, sam1.Location, 2);
shroud.Explore(w, sam2.Location, 2);
@@ -460,81 +630,4 @@ namespace OpenRA.Mods.RA.Missions
}
}
}
public class CountdownTimer
{
public int TicksLeft { get; set; }
public Action<CountdownTimer> OnExpired { get; set; }
public Action<CountdownTimer> OnOneMinuteRemaining { get; set; }
public Action<CountdownTimer> OnTwoMinutesRemaining { get; set; }
public Action<CountdownTimer> OnThreeMinutesRemaining { get; set; }
public Action<CountdownTimer> OnFourMinutesRemaining { get; set; }
public Action<CountdownTimer> OnFiveMinutesRemaining { get; set; }
public Action<CountdownTimer> OnTenMinutesRemaining { get; set; }
public Action<CountdownTimer> OnTwentyMinutesRemaining { get; set; }
public Action<CountdownTimer> OnThirtyMinutesRemaining { get; set; }
public Action<CountdownTimer> OnFortyMinutesRemaining { get; set; }
public CountdownTimer(int ticksLeft, Action<CountdownTimer> onExpired)
{
TicksLeft = ticksLeft;
OnExpired = onExpired;
OnOneMinuteRemaining = t => Sound.Play("1minr.aud");
OnTwoMinutesRemaining = t => Sound.Play("2minr.aud");
OnThreeMinutesRemaining = t => Sound.Play("3minr.aud");
OnFourMinutesRemaining = t => Sound.Play("4minr.aud");
OnFiveMinutesRemaining = t => Sound.Play("5minr.aud");
OnTenMinutesRemaining = t => Sound.Play("10minr.aud");
OnTwentyMinutesRemaining = t => Sound.Play("20minr.aud");
OnThirtyMinutesRemaining = t => Sound.Play("30minr.aud");
OnFortyMinutesRemaining = t => Sound.Play("40minr.aud");
}
public void Tick()
{
if (TicksLeft > 0)
{
TicksLeft--;
switch (TicksLeft)
{
case 1500 * 00: OnExpired(this); break;
case 1500 * 01: OnOneMinuteRemaining(this); break;
case 1500 * 02: OnTwoMinutesRemaining(this); break;
case 1500 * 03: OnThreeMinutesRemaining(this); break;
case 1500 * 04: OnFourMinutesRemaining(this); break;
case 1500 * 05: OnFiveMinutesRemaining(this); break;
case 1500 * 10: OnTenMinutesRemaining(this); break;
case 1500 * 20: OnTwentyMinutesRemaining(this); break;
case 1500 * 30: OnThirtyMinutesRemaining(this); break;
case 1500 * 40: OnFortyMinutesRemaining(this); break;
}
}
}
}
public class CountdownTimerWidget : Widget
{
public CountdownTimer CountdownTimer { get; set; }
public string Header { get; set; }
public float2 Position { get; set; }
public CountdownTimerWidget(CountdownTimer countdownTimer, string header, float2 position)
{
CountdownTimer = countdownTimer;
Header = header;
Position = position;
}
public override void Draw()
{
if (!IsVisible())
{
return;
}
var font = Game.Renderer.Fonts["Bold"];
var text = "{0}: {1}".F(Header, WidgetUtils.FormatTime(CountdownTimer.TicksLeft));
font.DrawTextWithContrast(text, Position, CountdownTimer.TicksLeft == 0 && Game.LocalTick % 60 >= 30 ? Color.Red : Color.White, Color.Black, 1);
}
}
}

View File

@@ -0,0 +1,96 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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.Drawing;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Missions
{
public class CountdownTimer
{
public int TicksLeft { get; set; }
public event Action<CountdownTimer> OnExpired = t => { };
public event Action<CountdownTimer> OnOneMinuteRemaining = t => { };
public event Action<CountdownTimer> OnTwoMinutesRemaining = t => { };
public event Action<CountdownTimer> OnThreeMinutesRemaining = t => { };
public event Action<CountdownTimer> OnFourMinutesRemaining = t => { };
public event Action<CountdownTimer> OnFiveMinutesRemaining = t => { };
public event Action<CountdownTimer> OnTenMinutesRemaining = t => { };
public event Action<CountdownTimer> OnTwentyMinutesRemaining = t => { };
public event Action<CountdownTimer> OnThirtyMinutesRemaining = t => { };
public event Action<CountdownTimer> OnFortyMinutesRemaining = t => { };
public CountdownTimer(int ticksLeft, Action<CountdownTimer> onExpired, bool withNotifications)
{
TicksLeft = ticksLeft;
OnExpired += onExpired;
if (withNotifications)
{
OnOneMinuteRemaining += t => Sound.Play("1minr.aud");
OnTwoMinutesRemaining += t => Sound.Play("2minr.aud");
OnThreeMinutesRemaining += t => Sound.Play("3minr.aud");
OnFourMinutesRemaining += t => Sound.Play("4minr.aud");
OnFiveMinutesRemaining += t => Sound.Play("5minr.aud");
OnTenMinutesRemaining += t => Sound.Play("10minr.aud");
OnTwentyMinutesRemaining += t => Sound.Play("20minr.aud");
OnThirtyMinutesRemaining += t => Sound.Play("30minr.aud");
OnFortyMinutesRemaining += t => Sound.Play("40minr.aud");
}
}
public void Tick()
{
if (TicksLeft > 0)
{
TicksLeft--;
switch (TicksLeft)
{
case 1500 * 00: OnExpired(this); break;
case 1500 * 01: OnOneMinuteRemaining(this); break;
case 1500 * 02: OnTwoMinutesRemaining(this); break;
case 1500 * 03: OnThreeMinutesRemaining(this); break;
case 1500 * 04: OnFourMinutesRemaining(this); break;
case 1500 * 05: OnFiveMinutesRemaining(this); break;
case 1500 * 10: OnTenMinutesRemaining(this); break;
case 1500 * 20: OnTwentyMinutesRemaining(this); break;
case 1500 * 30: OnThirtyMinutesRemaining(this); break;
case 1500 * 40: OnFortyMinutesRemaining(this); break;
}
}
}
}
public class CountdownTimerWidget : Widget
{
public CountdownTimer Timer { get; set; }
public string Format { get; set; }
public float2 Position { get; set; }
public CountdownTimerWidget(CountdownTimer timer, string format, float2 position)
{
Timer = timer;
Format = format;
Position = position;
}
public override void Draw()
{
if (!IsVisible())
{
return;
}
var font = Game.Renderer.Fonts["Bold"];
var text = Format.F(WidgetUtils.FormatTime(Timer.TicksLeft));
font.DrawTextWithContrast(text, Position, Timer.TicksLeft <= 25 * 10 && Game.LocalTick % 50 < 25 ? Color.Red : Color.White, Color.Black, 1);
}
}
}

View File

@@ -0,0 +1,140 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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.Mods.RA.Activities;
using OpenRA.Mods.RA.Air;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Missions
{
public static class MissionUtils
{
public static IEnumerable<Actor> FindAliveCombatantActorsInCircle(this World world, PPos location, int range)
{
return world.FindUnitsInCircle(location, Game.CellSize * range)
.Where(a => a.IsInWorld && a != world.WorldActor && !a.IsDead() && !a.Owner.NonCombatant);
}
public static IEnumerable<Actor> FindAliveNonCombatantActorsInCircle(this World world, PPos location, int range)
{
return world.FindUnitsInCircle(location, Game.CellSize * range)
.Where(a => a.IsInWorld && a != world.WorldActor && !a.IsDead() && a.Owner.NonCombatant);
}
public static Actor ExtractUnitWithChinook(World world, Player owner, Actor unit, CPos entry, CPos lz, CPos exit)
{
var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz)));
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0));
chinook.QueueActivity(new WaitFor(() => chinook.Trait<Cargo>().Passengers.Contains(unit)));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(exit)));
chinook.QueueActivity(new RemoveSelf());
return chinook;
}
public static Pair<Actor, Actor> InsertUnitWithChinook(World world, Player owner, string unitName, CPos entry, CPos lz, CPos exit, Action<Actor> afterUnload)
{
var unit = world.CreateActor(false, unitName, new TypeDictionary { new OwnerInit(owner) });
var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
chinook.Trait<Cargo>().Load(chinook, unit);
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz)));
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0));
chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new CallFunc(() => afterUnload(unit)));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(exit)));
chinook.QueueActivity(new RemoveSelf());
return Pair.New(chinook, unit);
}
public static void Paradrop(World world, Player owner, IEnumerable<string> units, CPos entry, CPos location)
{
var badger = world.CreateActor("badr", new TypeDictionary
{
new LocationInit(entry),
new OwnerInit(owner),
new FacingInit(Util.GetFacing(location - entry, 0)),
new AltitudeInit(Rules.Info["badr"].Traits.Get<PlaneInfo>().CruiseAltitude),
});
badger.QueueActivity(new FlyAttack(Target.FromCell(location)));
badger.Trait<ParaDrop>().SetLZ(location);
var cargo = badger.Trait<Cargo>();
foreach (var unit in units)
{
cargo.Load(badger, world.CreateActor(false, unit, new TypeDictionary { new OwnerInit(owner) }));
}
}
public static void Parabomb(World world, Player owner, CPos entry, CPos location)
{
var badger = world.CreateActor("badr.bomber", new TypeDictionary
{
new LocationInit(entry),
new OwnerInit(owner),
new FacingInit(Util.GetFacing(location - entry, 0)),
new AltitudeInit(Rules.Info["badr.bomber"].Traits.Get<PlaneInfo>().CruiseAltitude),
});
badger.Trait<CarpetBomb>().SetTarget(location);
badger.QueueActivity(Fly.ToCell(location));
badger.QueueActivity(new FlyOffMap());
badger.QueueActivity(new RemoveSelf());
}
public static bool AreaSecuredWithUnits(World world, Player player, PPos location, int range)
{
var units = world.FindAliveCombatantActorsInCircle(location, range).Where(a => a.HasTrait<IMove>());
return units.Any() && units.All(a => a.Owner == player);
}
public static Actor ClosestPlayerUnit(World world, Player player, PPos location, int range)
{
return ClosestPlayerUnits(world, player, location, range).FirstOrDefault();
}
public static IEnumerable<Actor> ClosestPlayerUnits(World world, Player player, PPos location, int range)
{
return world.FindAliveCombatantActorsInCircle(location, range)
.Where(a => a.Owner == player && a.HasTrait<IMove>())
.OrderBy(a => (location - a.CenterLocation).LengthSquared);
}
public static Actor ClosestPlayerBuilding(World world, Player player, PPos location, int range)
{
return ClosestPlayerBuildings(world, player, location, range).FirstOrDefault();
}
public static IEnumerable<Actor> ClosestPlayerBuildings(World world, Player player, PPos location, int range)
{
return world.FindAliveCombatantActorsInCircle(location, range)
.Where(a => a.Owner == player && a.HasTrait<Building>() && !a.HasTrait<Wall>())
.OrderBy(a => (location - a.CenterLocation).LengthSquared);
}
public static IEnumerable<ProductionQueue> FindQueues(World world, Player player, string category)
{
return world.ActorsWithTrait<ProductionQueue>()
.Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category)
.Select(a => a.Trait);
}
public static Actor UnitContaining(this World world, Actor actor)
{
return world.Actors.FirstOrDefault(a => a.HasTrait<Cargo>() && a.Trait<Cargo>().Passengers.Contains(actor));
}
}
}

View File

@@ -0,0 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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 OpenRA.Traits;
namespace OpenRA.Mods.RA.Missions
{
public class Objective
{
public ObjectiveType Type { get; set; }
public string Text { get; set; }
public ObjectiveStatus Status { get; set; }
public Objective(ObjectiveType type, string text, ObjectiveStatus status)
{
Type = type;
Text = text;
Status = status;
}
}
public enum ObjectiveType { Primary, Secondary }
public enum ObjectiveStatus { Inactive, InProgress, Completed, Failed }
public delegate void ObjectivesUpdatedEventHandler(bool notify);
public interface IHasObjectives
{
event ObjectivesUpdatedEventHandler OnObjectivesUpdated;
IEnumerable<Objective> Objectives { get; }
}
public class MissionObjectivesPanelInfo : ITraitInfo
{
public string ObjectivesPanel = null;
public object Create(ActorInitializer init) { return new MissionObjectivesPanel(this); }
}
public class MissionObjectivesPanel : IObjectivesPanel
{
MissionObjectivesPanelInfo info;
public MissionObjectivesPanel(MissionObjectivesPanelInfo info) { this.info = info; }
public string ObjectivesPanel { get { return info.ObjectivesPanel; } }
}
}

View File

@@ -172,6 +172,7 @@
<Compile Include="ColorPickerPaletteModifier.cs" />
<Compile Include="Combat.cs" />
<Compile Include="ConquestVictoryConditions.cs" />
<Compile Include="ContainsCrate.cs" />
<Compile Include="Crate.cs" />
<Compile Include="CrateAction.cs" />
<Compile Include="CrateDrop.cs" />
@@ -181,6 +182,7 @@
<Compile Include="Crates\GiveCashCrateAction.cs" />
<Compile Include="Crates\GiveMcvCrateAction.cs" />
<Compile Include="Crates\GiveUnitCrateAction.cs" />
<Compile Include="Crates\HealUnitsCrateAction.cs" />
<Compile Include="Crates\HideMapCrateAction.cs" />
<Compile Include="Crates\LevelUpCrateAction.cs" />
<Compile Include="Crates\RevealMapCrateAction.cs" />
@@ -238,7 +240,10 @@
<Compile Include="Minelayer.cs" />
<Compile Include="Missions\Allies01Script.cs" />
<Compile Include="Missions\Allies02Script.cs" />
<Compile Include="Missions\CountdownTimer.cs" />
<Compile Include="Missions\DefaultShellmapScript.cs" />
<Compile Include="Missions\MissionUtils.cs" />
<Compile Include="Missions\Objective.cs" />
<Compile Include="Modifiers\FrozenUnderFog.cs" />
<Compile Include="Modifiers\HiddenUnderFog.cs" />
<Compile Include="Move\Drag.cs" />
@@ -361,6 +366,7 @@
<Compile Include="Widgets\Logic\LobbyUtils.cs" />
<Compile Include="Widgets\Logic\MainMenuButtonsLogic.cs" />
<Compile Include="Widgets\Logic\MapChooserLogic.cs" />
<Compile Include="Widgets\Logic\MissionObjectivesLogic.cs" />
<Compile Include="Widgets\Logic\MusicPlayerLogic.cs" />
<Compile Include="Widgets\Logic\OrderButtonsChromeLogic.cs" />
<Compile Include="Widgets\Logic\PerfDebugLogic.cs" />

View File

@@ -91,7 +91,7 @@ namespace OpenRA.Mods.RA
if (mobile != null)
{
newUnit.QueueActivity(new AttackMove.AttackMoveActivity(
newUnit, mobile.MoveTo(rp.rallyPoint, 1)));
newUnit, mobile.MoveTo(rp.rallyPoint, rp.nearEnough)));
return rp.rallyPoint;
}

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information
#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
@@ -24,6 +24,7 @@ namespace OpenRA.Mods.RA
public class RallyPoint : IIssueOrder, IResolveOrder, ISync
{
[Sync] public CPos rallyPoint;
public int nearEnough = 1;
public RallyPoint(Actor self)
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using System.Linq;
using OpenRA.Widgets;
using System.Drawing;
@@ -38,6 +39,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
};
cheatsButton.IsVisible = () => world.LocalPlayer != null && world.LobbyInfo.GlobalSettings.AllowCheats;
var iop = world.WorldActor.TraitsImplementing<IObjectivesPanel>().FirstOrDefault();
if (iop != null && iop.ObjectivesPanel != null)
{
var objectivesButton = gameRoot.Get<ButtonWidget>("OBJECTIVES_BUTTON");
var objectivesWidget = Game.LoadWidget(world, iop.ObjectivesPanel, Ui.Root, new WidgetArgs());
objectivesWidget.Visible = false;
objectivesButton.OnClick += () => objectivesWidget.Visible = !objectivesWidget.Visible;
objectivesButton.IsVisible = () => world.LocalPlayer != null;
}
optionsBG.Get<ButtonWidget>("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world);
optionsBG.Get<ButtonWidget>("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU");

View File

@@ -0,0 +1,95 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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.Linq;
using OpenRA.Mods.RA.Missions;
using OpenRA.Network;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic
{
public class MissionObjectivesLogic
{
IHasObjectives objectives;
Widget primaryPanel;
Widget secondaryPanel;
Widget primaryTemplate;
Widget secondaryTemplate;
ButtonWidget objectivesButton;
[ObjectCreator.UseCtor]
public MissionObjectivesLogic(World world, Widget widget)
{
var gameRoot = Ui.Root.Get("INGAME_ROOT");
primaryPanel = widget.Get("PRIMARY_OBJECTIVES");
secondaryPanel = widget.Get("SECONDARY_OBJECTIVES");
primaryTemplate = primaryPanel.Get("PRIMARY_OBJECTIVE_TEMPLATE");
secondaryTemplate = secondaryPanel.Get("SECONDARY_OBJECTIVE_TEMPLATE");
objectives = world.WorldActor.TraitsImplementing<IHasObjectives>().First();
objectivesButton = gameRoot.Get<ButtonWidget>("OBJECTIVES_BUTTON");
objectivesButton.IsHighlighted = () => Game.LocalTick % 50 < 25 && objectivesButton.Highlighted;
objectivesButton.OnClick += () => objectivesButton.Highlighted = false;
objectives.OnObjectivesUpdated += UpdateObjectives;
UpdateObjectives(true);
Game.ConnectionStateChanged += RemoveHandlers;
}
public void RemoveHandlers(OrderManager orderManager)
{
if (!orderManager.GameStarted)
{
Game.ConnectionStateChanged -= RemoveHandlers;
objectives.OnObjectivesUpdated -= UpdateObjectives;
}
}
public void UpdateObjectives(bool notify)
{
if (notify)
{
objectivesButton.Highlighted = true;
}
primaryPanel.RemoveChildren();
secondaryPanel.RemoveChildren();
foreach (var o in objectives.Objectives.Where(o => o.Status != ObjectiveStatus.Inactive))
{
var objective = o;
if (objective.Type == ObjectiveType.Secondary)
{
var template = secondaryTemplate.Clone();
template.Get<LabelWidget>("SECONDARY_OBJECTIVE").GetText = () => objective.Text;
template.Get<LabelWidget>("SECONDARY_STATUS").GetText = () => GetObjectiveStatusText(objective.Status);
secondaryPanel.AddChild(template);
}
else
{
var template = primaryTemplate.Clone();
template.Get<LabelWidget>("PRIMARY_OBJECTIVE").GetText = () => objective.Text;
template.Get<LabelWidget>("PRIMARY_STATUS").GetText = () => GetObjectiveStatusText(objective.Status);
primaryPanel.AddChild(template);
}
}
}
static string GetObjectiveStatusText(ObjectiveStatus status)
{
switch (status)
{
case ObjectiveStatus.InProgress: return "In Progress";
case ObjectiveStatus.Completed: return "Completed";
case ObjectiveStatus.Failed: return "Failed";
default: return "";
}
}
}
}

BIN
mods/ra/bits/invun.shp Normal file

Binary file not shown.

View File

@@ -249,6 +249,17 @@ button: dialog.png
corner-bl: 512,82,1,1
corner-br: 594,82,1,1
button-highlighted: dialog.png
background: 513,145,126,126
border-r: 639,145,1,126
border-l: 512,145,1,126
border-b: 513,271,126,1
border-t: 513,144,126,1
corner-tl: 512,144,1,1
corner-tr: 594,144,1,1
corner-bl: 512,271,1,1
corner-br: 594,271,1,1
# A copy of dialog2
button-hover: dialog.png
background: 513,1,126,126
@@ -261,6 +272,17 @@ button-hover: dialog.png
corner-bl: 512,82,1,1
corner-br: 594,82,1,1
button-hover-highlighted: dialog.png
background: 513,145,126,126
border-r: 639,145,1,126
border-l: 512,145,1,126
border-b: 513,271,126,1
border-t: 513,144,126,1
corner-tl: 512,144,1,1
corner-tr: 594,144,1,1
corner-bl: 512,271,1,1
corner-br: 594,271,1,1
# A copy of dialog2
button-disabled: dialog.png
background: 513,1,126,126
@@ -273,6 +295,17 @@ button-disabled: dialog.png
corner-bl: 512,82,1,1
corner-br: 594,82,1,1
button-disabled-highlighted: dialog.png
background: 513,145,126,126
border-r: 639,145,1,126
border-l: 512,145,1,126
border-b: 513,271,126,1
border-t: 513,144,126,1
corner-tl: 512,144,1,1
corner-tr: 594,144,1,1
corner-bl: 512,271,1,1
corner-br: 594,271,1,1
# A copy of dialog3
button-pressed: dialog.png
background: 641,1,126,126
@@ -285,6 +318,17 @@ button-pressed: dialog.png
corner-bl: 640,82,1,1
corner-br: 722,82,1,1
button-pressed-highlighted: dialog.png
background: 641,145,126,126
border-r: 767,145,1,126
border-l: 640,145,1,126
border-b: 641,271,126,1
border-t: 641,144,126,1
corner-tl: 640,144,1,1
corner-tr: 722,144,1,1
corner-bl: 640,271,1,1
corner-br: 722,271,1,1
scrollthumb: dialog.png
background: 513,1,126,126
border-r: 639,1,1,126

View File

@@ -81,6 +81,14 @@ Container@INGAME_ROOT:
Text:Cheats
Visible:false
Font:Bold
Button@OBJECTIVES_BUTTON:
X:486
Y:0
Width:160
Height:25
Text:Objectives
Visible:false
Font:Bold
RadarBin@INGAME_RADAR_BIN:
WorldInteractionController:INTERACTION_CONTROLLER
PowerBin@INGAME_POWER_BIN:

View File

@@ -0,0 +1,102 @@
Container@MISSION_OBJECTIVES:
Logic:MissionObjectivesLogic
X:25
Y:50
Width:512
Height:530
Children:
Background@BACKGROUND:
Width:512
Height:530
Background:dialog
Children:
Label@TITLE:
X:0
Y:15
Width:PARENT_RIGHT
Height:25
Font:Bold
Align:Center
Text:Objectives
Label@PRIMARY_OBJECTIVE_HEADER:
X:40
Y:40
Width:300
Height:25
Font:Bold
Text:Primary Objectives
Label@PRIMARY_STATUS_HEADER:
X:350
Y:40
Width:122
Height:25
Font:Bold
Text:Status
ScrollPanel@PRIMARY_OBJECTIVES:
X:25
Y:70
Width:PARENT_RIGHT-50
Height:200
ItemSpacing:5
Children:
Container@PRIMARY_OBJECTIVE_TEMPLATE:
X:15
Y:0-15
Width:PARENT_RIGHT
Height:60
Children:
Label@PRIMARY_OBJECTIVE:
X:0
Y:0
Width:300
Height:PARENT_BOTTOM
Font:Regular
WordWrap:True
Label@PRIMARY_STATUS:
X:310
Y:0
Width:122
Height:PARENT_BOTTOM
Font:Bold
WordWrap:True
Label@SECONDARY_OBJECTIVE_HEADER:
X:40
Y:275
Width:300
Height:25
Font:Bold
Text:Secondary Objectives
Label@SECONDARY_STATUS_HEADER:
X:350
Y:275
Width:122
Height:25
Font:Bold
Text:Status
ScrollPanel@SECONDARY_OBJECTIVES:
X:25
Y:305
Width:PARENT_RIGHT-50
Height:200
ItemSpacing:5
Children:
Container@SECONDARY_OBJECTIVE_TEMPLATE:
X:15
Y:0-15
Width:PARENT_RIGHT
Height:60
Children:
Label@SECONDARY_OBJECTIVE:
X:0
Y:0
Width:300
Height:PARENT_BOTTOM
Font:Regular
WordWrap:True
Label@SECONDARY_STATUS:
X:310
Y:0
Width:122
Height:PARENT_BOTTOM
Font:Bold
WordWrap:True

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,403 @@
Selectable: True
MapFormat: 5
RequiresMod: ra
Title: Allies 01
Description: Allies' first mission
Author: Scott_NZ
Tileset: SNOW
MapSize: 48,64
Bounds: 8,8,32,38
UseAsShellmap: False
Type: Mission
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
Race: allies
PlayerReference@Creeps:
Name: Creeps
NonCombatant: True
Race: allies
PlayerReference@Allies:
Name: Allies
Playable: True
AllowBots: False
LockRace: True
Race: allies
LockColor: True
ColorRamp: 153,240,130,10
LockSpawn: True
LockTeam: True
Allies: Creeps
Enemies: Soviets
PlayerReference@Soviets:
Name: Soviets
Race: soviet
ColorRamp: 0,255,128,10
Enemies: Allies,Creeps
Actors:
Actor1: tc01
Location: 13,9
Owner: Neutral
Actor10: oilb
Location: 17,19
Owner: Soviets
Actor3: t13
Location: 17,13
Owner: Neutral
Actor5: t16
Location: 25,9
Owner: Neutral
Actor4: t17
Location: 17,10
Owner: Neutral
Actor8: brl3
Location: 19,21
Owner: Soviets
Actor7: barl
Location: 19,20
Owner: Soviets
Actor2: brl3
Location: 19,19
Owner: Soviets
Actor6: brl3
Location: 20,19
Owner: Soviets
Actor71: t01
Location: 33,31
Owner: Neutral
Actor11: powr
Location: 20,20
Owner: Soviets
Actor12: powr
Location: 24,20
Owner: Soviets
Actor13: powr
Location: 26,20
Owner: Soviets
Actor14: t08
Location: 25,13
Owner: Neutral
Actor15: fenc
Location: 27,18
Owner: Soviets
Actor16: fenc
Location: 28,18
Owner: Soviets
Actor17: fenc
Location: 27,17
Owner: Soviets
Actor18: jeep
Location: 21,13
Owner: Allies
Actor19: jeep
Location: 22,13
Owner: Allies
Actor20: jeep
Location: 23,13
Owner: Allies
Actor22: e2
Location: 21,19
Owner: Soviets
Actor23: e1
Location: 17,23
Owner: Soviets
Actor28: e1
Location: 23,12
Owner: Allies
Actor26: e1
Location: 22,12
Owner: Allies
Actor25: e1
Location: 21,12
Owner: Allies
Actor65: fenc
Location: 33,33
Owner: Soviets
Actor31: mine
Location: 33,14
Owner: Neutral
Actor32: tc03
Location: 28,13
Owner: Neutral
Actor33: v04
Location: 35,8
Owner: Neutral
Actor34: tsla
Location: 30,22
Owner: Soviets
Actor35: proc
Location: 32,21
Owner: Soviets
Actor37: e1
Location: 23,24
Owner: Soviets
Actor0: e2
Location: 22,27
Owner: Soviets
Actor21: e2
Location: 20,27
Owner: Soviets
Actor40: weap
Location: 24,25
Owner: Soviets
Actor41: fact
Location: 28,25
Owner: Soviets
Actor42: barr
Location: 20,28
Owner: Soviets
Actor43: silo
Location: 18,28
Owner: Soviets
Actor44: dome
Location: 26,28
Owner: Soviets
Actor45: t12
Location: 15,19
Owner: Neutral
Actor46: t12
Location: 15,25
Owner: Neutral
Actor47: fenc
Location: 14,27
Owner: Soviets
Actor48: fenc
Location: 14,28
Owner: Soviets
Actor49: fenc
Location: 14,29
Owner: Soviets
Actor50: fenc
Location: 14,30
Owner: Soviets
Actor51: tsla
Location: 19,30
Owner: Soviets
Actor52: tsla
Location: 26,30
Owner: Soviets
Actor53: fenc
Location: 14,31
Owner: Soviets
Actor54: fenc
Location: 15,31
Owner: Soviets
Actor55: fenc
Location: 16,31
Owner: Soviets
Actor56: fenc
Location: 17,31
Owner: Soviets
Actor57: fenc
Location: 17,32
Owner: Soviets
Actor70: fenc
Location: 35,33
Owner: Soviets
Actor59: e1
Location: 23,31
Owner: Soviets
Actor60: e1
Location: 21,31
Owner: Soviets
Actor61: powr
Location: 34,30
Owner: Soviets
Actor58: powr
Location: 36,27
Owner: Soviets
Actor64: t05
Location: 32,27
Owner: Neutral
Actor62: powr
Location: 36,30
Owner: Soviets
Actor63: fenc
Location: 32,33
Owner: Soviets
Actor30: powr
Location: 34,27
Owner: Soviets
Actor67: fenc
Location: 34,33
Owner: Soviets
Actor68: c1
Location: 28,16
Owner: Creeps
Actor69: c2
Location: 30,17
Owner: Creeps
Actor72: e1
Location: 35,29
Owner: Soviets
Actor66: e1
Location: 31,29
Owner: Soviets
Actor9: barl
Location: 18,21
Owner: Soviets
Actor74: tc02
Location: 11,23
Owner: Neutral
Actor73: tc03
Location: 37,22
Owner: Neutral
Actor75: t02
Location: 29,31
Owner: Neutral
Actor76: t02
Location: 12,34
Owner: Neutral
Actor79: fenc
Location: 14,21
Owner: Soviets
Actor78: fenc
Location: 14,22
Owner: Soviets
Actor77: fenc
Location: 14,23
Owner: Soviets
Actor85: 3tnk
Location: 17,25
Owner: Soviets
Facing: 0
Actor92: wood
Location: 34,9
Owner: Neutral
Actor94: c1
Location: 19,24
Owner: Soviets
Actor95: c2
Location: 31,23
Owner: Soviets
InsertionLZ: waypoint
Location: 22,10
Owner: Neutral
Lab: stek
Location: 20,24
Owner: Soviets
Actor24: e2
Location: 27,24
Owner: Soviets
ShipSpawnPoint: waypoint
Location: 23,45
Owner: Neutral
ShipMovePoint: waypoint
Location: 23,40
Owner: Neutral
InsertionLZEntryPoint: waypoint
Location: 22,4
Owner: Neutral
Actor27: e2
Location: 27,27
Owner: Soviets
ChinookExitPoint: waypoint
Location: 55,11
Owner: Neutral
ExtractionLZEntryPoint: waypoint
Location: 31,48
Owner: Neutral
SovietAttackEntryPoint2: waypoint
Location: 39,11
Owner: Neutral
ExtractionLZ: waypoint
Location: 13,12
Owner: Neutral
Actor36: e1
Location: 20,12
Owner: Allies
Actor38: e1
Location: 24,12
Owner: Allies
Actor39: e3
Location: 21,11
Owner: Allies
Actor80: e3
Location: 22,11
Owner: Allies
Actor81: e3
Location: 23,11
Owner: Allies
SovietAttackEntryPoint1: waypoint
Location: 8,30
Owner: Neutral
Actor29: kenn
Location: 23,28
Owner: Soviets
Smudges:
Rules:
Player:
-ConquestVictoryConditions:
World:
-CrateDrop:
-SpawnMPUnits:
-MPStartLocations:
Allies01Script:
MissionObjectivesPanel:
ObjectivesPanel: MISSION_OBJECTIVES
TRAN:
-Selectable:
RevealsShroud:
Range: 0
E7:
AutoTarget:
InitialStance: ReturnFire
Passenger:
Weight: 0
EINSTEIN:
Passenger:
Weight: 0
JEEP:
Cargo:
MaxWeight: 0
PipCount: 0
Sequences:
Weapons:
8Inch:
ROF: 200
Range: 25
Burst: 2
Report: TURRET1
Projectile: Bullet
Speed: 30
High: true
Angle: .1
Inaccuracy: 100
Image: 120MM
ContrailLength: 10
Warhead:
Spread: 5
Versus:
None: 60%
Wood: 75%
Light: 60%
Heavy: 25%
Explosion: large_explosion
WaterExplosion: large_splash
InfDeath: 2
SmudgeType: Crater
Damage: 500
ImpactSound: kaboom12
WaterImpactSound: splash9
Voices:
Notifications:

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,7 @@ ChromeLayout:
mods/ra/chrome/dropdowns.yaml
mods/ra/chrome/modchooser.yaml
mods/ra/chrome/cheats.yaml
mods/ra/chrome/objectives.yaml
Weapons:
mods/ra/weapons.yaml

View File

@@ -8,6 +8,8 @@ FCOM:
HP: 400
Armor:
Type: Wood
Tooltip:
Name: Forward Command
RevealsShroud:
Range: 10
Bib:
@@ -136,6 +138,7 @@ BARL:
Health:
HP: 10
Explodes:
Weapon: BarrelExplode
Tooltip:
Name: Explosive Barrel
@@ -146,6 +149,7 @@ BRL3:
Health:
HP: 10
Explodes:
Weapon: BarrelExplode
Tooltip:
Name: Explosive Barrel

View File

@@ -1214,6 +1214,7 @@ KENN:
Range: 4
IronCurtainable:
-EmitInfantryOnSell:
-AcceptsSupplies:
FIX:
Inherits: ^Building

View File

@@ -355,6 +355,10 @@ CRATE:
HideMapCrateAction:
SelectionShares: 5
Effect: hide-map
HealUnitsCrateAction:
Notification: heal2.aud
SelectionShares: 2
Effect: heal
RevealMapCrateAction:
SelectionShares: 1
Effect: reveal-map

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1108,6 +1108,23 @@ UnitExplodeSmall:
InfDeath: 4
ImpactSound: kaboom15
BarrelExplode:
Warhead:
Damage: 500
Spread: 10
Versus:
None: 120%
Wood: 200%
Light: 50%
Heavy: 25%
Concrete: 10%
Explosion: napalm
InfDeath: 4
ImpactSound: firebl3
SmudgeType: Scorch
Delay: 5
Size: 2,2
Crush:
Warhead:
ImpactSound: squishy2