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

View File

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

View File

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

View File

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

View File

@@ -16,6 +16,8 @@ using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Air;
using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Effects;
using OpenRA.Mods.RA.Move;
using OpenRA.Network; using OpenRA.Network;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
@@ -24,15 +26,34 @@ namespace OpenRA.Mods.RA.Missions
{ {
class Allies02ScriptInfo : TraitInfo<Allies02Script>, Requires<SpawnMapActorsInfo> { } 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.", { FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) },
"Wait for the helicopter and extract Einstein. Tanya and Einstein must survive." { 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 sam1;
Actor sam2; Actor sam2;
@@ -42,17 +63,29 @@ namespace OpenRA.Mods.RA.Missions
Actor einstein; Actor einstein;
Actor engineer; Actor engineer;
Actor engineerMiss;
Actor chinookHusk; Actor chinookHusk;
Actor allies2BasePoint; Actor allies2BasePoint;
Actor reinforcementsEntryPoint; Actor reinforcementsEntryPoint;
Actor extractionLZEntryPoint; Actor extractionLZEntryPoint;
Actor extractionLZ; Actor extractionLZ;
Actor badgerEntryPoint; Actor badgerEntryPoint1;
Actor badgerDropPoint; Actor badgerEntryPoint2;
Actor badgerDropPoint1;
Actor badgerDropPoint2;
Actor badgerDropPoint3;
Actor parabombPoint1;
Actor parabombPoint2;
Actor sovietRallyPoint; Actor sovietRallyPoint;
Actor flamersEntryPoint; Actor flamersEntryPoint;
Actor tanksEntryPoint;
Actor townPoint;
Actor sovietTownAttackPoint1;
Actor sovietTownAttackPoint2;
Actor yakEntryPoint;
Actor yakAttackPoint;
Actor yak;
Actor sovietReinforcementsEntryPoint1;
Actor sovietReinforcementsEntryPoint2;
Actor einsteinChinook; Actor einsteinChinook;
@@ -67,36 +100,56 @@ namespace OpenRA.Mods.RA.Missions
CountdownTimer reinforcementsTimer; CountdownTimer reinforcementsTimer;
CountdownTimerWidget reinforcementsTimerWidget; CountdownTimerWidget reinforcementsTimerWidget;
List<Actor> sovietReinforcementsUnits = new List<Actor>();
const string InfantryQueueName = "Infantry"; const string InfantryQueueName = "Infantry";
const string VehicleQueueName = "Vehicle"; const string VehicleQueueName = "Vehicle";
readonly List<string> sovietInfantry = new List<string> { "e1", "e2", "e3" }; static readonly string[] SovietInfantry = { "e1", "e2", "e3" };
readonly List<string> sovietVehicles = new List<string> { "3tnk" }; static readonly string[] SovietVehicles1 = { "3tnk" };
static readonly string[] SovietVehicleAdditions = { "v2rl" }; static readonly string[] SovietVehicles2 = { "3tnk", "v2rl" };
const int SovietGroupSize = 5; const int SovietVehiclesUpgradeTicks = 1500 * 4;
const int SovietVehicleAdditionsTicks = 1500 * 4; const int SovietGroupSize = 8;
const int SovietHelperCash = 2000;
const int ReinforcementsTicks = 1500 * 12; 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" }; static readonly string[] Reinforcements =
const int ReinforcementsCash = 2000; {
"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; const int ParabombTicks = 750;
static readonly string[] Paratroopers = { "e1", "e1", "e1", "e2", "3tnk" };
const string BadgerName = "badr";
const int FlamersTicks = 1500 * 7; const int FlamersTicks = 1500 * 2;
static readonly string[] Flamers = { "e4", "e4", "e4", "e4", "e4" }; static readonly string[] Flamers = { "e4", "e4", "e4", "e4", "e4" };
const string ApcName = "apc"; const string ApcName = "apc";
const string ChinookName = "tran"; const int ParatroopersTicks = 1500 * 5;
const string SignalFlareName = "flare"; static readonly string[] Badger1Passengers = { "e1", "e1", "e1", "e2", "3tnk" };
const string EngineerName = "e6"; static readonly string[] Badger2Passengers = { "e1", "e1", "e1", "e2", "e2" };
const int EngineerMissClearRange = 5; static readonly string[] Badger3Passengers = { "e1", "e1", "e1", "e2", "e2" };
void DisplayObjective() const int TanksTicks = 1500 * 11;
{ static readonly string[] Tanks = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk" };
Game.AddChatLine(Color.LimeGreen, "Objective", Objectives[currentObjective]);
Sound.Play("bleep6.aud"); const string SignalFlareName = "flare";
} const string YakName = "yak";
const int AlliedTownTransferRange = 15;
const int SovietTownAttackGroupRange = 5;
const int SovietTownMoveNearEnough = 3;
void MissionFailed(string text) void MissionFailed(string text)
{ {
@@ -138,9 +191,9 @@ namespace OpenRA.Mods.RA.Missions
{ {
return; 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) if (world.FrameNumber == 1)
{ {
@@ -150,15 +203,35 @@ namespace OpenRA.Mods.RA.Missions
reinforcementsTimer.Tick(); reinforcementsTimer.Tick();
if (world.FrameNumber == ParatroopersTicks) 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) if (world.FrameNumber == FlamersTicks)
{ {
RushSovietFlamers(); 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) if (world.FrameNumber % 25 == 0)
{ {
@@ -166,30 +239,47 @@ namespace OpenRA.Mods.RA.Missions
BuildSovietUnits(); BuildSovietUnits();
ManageSovietUnits(); ManageSovietUnits();
} }
if (!engineerMiss.Destroyed && engineer == null && AlliesControlMiss()) UpdateDeaths();
if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress)
{ {
SpawnEngineerAtMiss(); if (AlliesNearTown())
engineerMiss.QueueActivity(new Demolish(engineerMiss, 0)); {
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) if (sam1.Destroyed && sam2.Destroyed && sam3.Destroyed && sam4.Destroyed)
{ {
currentObjective++; objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed;
DisplayObjective(); objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
OnObjectivesUpdated(true);
SpawnSignalFlare(); SpawnSignalFlare();
Sound.Play("flaren1.aud"); Sound.Play("flaren1.aud");
SendChinook(); ExtractEinsteinAtLZ();
} }
} }
else if (currentObjective == 1 && einsteinChinook != null) if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null)
{ {
if (einsteinChinook.Destroyed) if (einsteinChinook.Destroyed)
{ {
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
OnObjectivesUpdated(true);
MissionFailed("The extraction helicopter was destroyed."); MissionFailed("The extraction helicopter was destroyed.");
} }
else if (!world.Map.IsInMap(einsteinChinook.Location) && einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein)) 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."); MissionAccomplished("Einstein was rescued.");
} }
} }
@@ -201,18 +291,58 @@ namespace OpenRA.Mods.RA.Missions
{ {
MissionFailed("Einstein was killed."); MissionFailed("Einstein was killed.");
} }
else if (!world.Actors.Any(a => a.IsInWorld && a.HasTrait<Building>() && !a.HasTrait<Wall>() && a.Owner == allies2)) world.AddFrameEndTask(w =>
{ {
MissionFailed("The Allied reinforcements have been defeated."); 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() void AddSovietCashIfRequired()
{ {
var resources = soviets.PlayerActor.Trait<PlayerResources>(); 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) if (!sovietBarracks.Destroyed)
{ {
BuildSovietUnit(InfantryQueueName, sovietInfantry.Random(world.SharedRandom)); BuildSovietUnit(InfantryQueueName, SovietInfantry.Random(world.SharedRandom));
} }
if (!sovietWarFactory.Destroyed) if (!sovietWarFactory.Destroyed)
{ {
BuildSovietUnit(VehicleQueueName, sovietVehicles.Random(world.SharedRandom)); var vehicles = world.FrameNumber >= SovietVehiclesUpgradeTicks ? SovietVehicles2 : SovietVehicles1;
BuildSovietUnit(VehicleQueueName, vehicles.Random(world.SharedRandom));
} }
} }
void ManageSovietUnits() void ManageSovietUnits()
{ {
var idleSovietUnits = ForcesNearActor(allies2BasePoint, 10).Where(a => a.Owner == soviets && a.IsIdle); var idleSovietUnitsAtRP = world.FindAliveCombatantActorsInCircle(sovietRallyPoint.CenterLocation, 3).Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
var idleSovietUnitsAtRP = ForcesNearActor(sovietRallyPoint, 5).Where(a => a.Owner == soviets && a.IsIdle);
if (idleSovietUnitsAtRP.Count() >= SovietGroupSize) if (idleSovietUnitsAtRP.Count() >= SovietGroupSize)
{ {
idleSovietUnits = idleSovietUnits.Union(idleSovietUnitsAtRP); var firstUnit = idleSovietUnitsAtRP.FirstOrDefault();
if (firstUnit != null)
{
var closestAlliedBuilding = ClosestAlliedBuilding(firstUnit, 40);
if (closestAlliedBuilding != null)
{
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) foreach (var unit in idleSovietUnits)
{ {
var closestAlliedBuilding = ClosestAlliedBuilding(unit, 20); var closestAlliedBuilding = ClosestAlliedBuilding(unit, 40);
if (closestAlliedBuilding != null) if (closestAlliedBuilding != null)
{ {
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(closestAlliedBuilding.Location, 3))); unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Attack(Target.FromActor(closestAlliedBuilding), 3)));
} }
} }
} }
Actor ClosestAlliedBuilding(Actor actor, int range) Actor ClosestAlliedBuilding(Actor actor, int range)
{ {
return BuildingsNearActor(actor, range) return MissionUtils.ClosestPlayerBuilding(world, allies2, actor.CenterLocation, range);
.Where(a => a.Owner == allies2) }
.OrderBy(a => (actor.Location - a.Location).LengthSquared)
.FirstOrDefault(); IEnumerable<Actor> ClosestAlliedBuildings(Actor actor, int range)
{
return MissionUtils.ClosestPlayerBuildings(world, allies2, actor.CenterLocation, range);
} }
void InitializeSovietFactories() void InitializeSovietFactories()
{ {
sovietBarracks.Trait<RallyPoint>().rallyPoint = sovietRallyPoint.Location; var sbrp = sovietBarracks.Trait<RallyPoint>();
sovietWarFactory.Trait<RallyPoint>().rallyPoint = sovietRallyPoint.Location; var swrp = sovietWarFactory.Trait<RallyPoint>();
sbrp.rallyPoint = swrp.rallyPoint = sovietRallyPoint.Location;
sbrp.nearEnough = swrp.nearEnough = 3;
sovietBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietBarracks, true); sovietBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietBarracks, true);
sovietWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietWarFactory, 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) 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) if (queue == null)
{ {
return; return;
} }
var order = Order.StartProduction(queue.self, unit, 1);
if (Game.IsHost) 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() void StartReinforcementsTimer()
{ {
Sound.Play("timergo1.aud"); Sound.Play("timergo1.aud");
reinforcementsTimer = new CountdownTimer(ReinforcementsTicks, ReinforcementsTimerExpired); reinforcementsTimer = new CountdownTimer(ReinforcementsTicks, ReinforcementsTimerExpired, true);
reinforcementsTimerWidget = new CountdownTimerWidget(reinforcementsTimer, "Reinforcements arrive in", new float2(128, 96)); 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); 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), foreach (var unit in SovietReinforcements)
new OwnerInit(soviets), {
new FacingInit(Util.GetFacing(badgerDropPoint.Location - badgerEntryPoint.Location, 0)), var u = world.CreateActor(unit, new TypeDictionary
new AltitudeInit(Rules.Info[BadgerName].Traits.Get<PlaneInfo>().CruiseAltitude), {
}); new LocationInit(entryPoint.Location),
badger.QueueActivity(new FlyAttack(Target.FromCell(badgerDropPoint.Location))); new FacingInit(Util.GetFacing(allies2BasePoint.Location - entryPoint.Location, 0)),
badger.Trait<ParaDrop>().SetLZ(badgerDropPoint.Location); new OwnerInit(soviets)
var cargo = badger.Trait<Cargo>(); });
foreach (var unit in Paratroopers) u.QueueActivity(new Move.Move(sovietRallyPoint.Location, 3));
}
}
}
void ReinforcementsTimerExpired(CountdownTimer countdownTimer)
{
reinforcementsTimerWidget.Visible = false;
SendReinforcements();
Sound.Play("aarrivs1.aud");
}
void SendReinforcements()
{
foreach (var unit in Reinforcements)
{ {
cargo.Load(badger, world.CreateActor(false, unit, new TypeDictionary { new OwnerInit(soviets) })); 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() void RushSovietFlamers()
{ {
var closestAlliedBuilding = ClosestAlliedBuilding(badgerDropPoint, 10); var closestAlliedBuilding = ClosestAlliedBuilding(badgerDropPoint1, 40);
if (closestAlliedBuilding == null) if (closestAlliedBuilding == null)
{ {
return; return;
@@ -336,67 +519,41 @@ namespace OpenRA.Mods.RA.Missions
apc.QueueActivity(new UnloadCargo(true)); apc.QueueActivity(new UnloadCargo(true));
} }
void ReinforcementsTimerExpired(CountdownTimer countdownTimer) void ExtractEinsteinAtLZ()
{ {
reinforcementsTimerWidget.Visible = false; einsteinChinook = MissionUtils.ExtractUnitWithChinook(
SendReinforcements(); world,
allies1,
einstein,
extractionLZEntryPoint.Location,
extractionLZ.Location,
extractionLZEntryPoint.Location);
} }
void SendReinforcements() bool AlliesNearTown()
{ {
Sound.Play("reinfor1.aud"); return world.FindAliveCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange)
var resources = allies2.PlayerActor.Trait<PlayerResources>(); .Any(a => a.Owner == allies1 && a.HasTrait<IMove>());
resources.GiveCash(2000); }
foreach (var unit in Reinforcements)
void TransferTownUnitsToAllies()
{
foreach (var unit in world.FindAliveNonCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange).Where(a => a.HasTrait<IMove>()))
{ {
var actor = world.CreateActor(unit, new TypeDictionary unit.ChangeOwner(allies1);
{
new LocationInit(reinforcementsEntryPoint.Location),
new FacingInit(0),
new OwnerInit(allies2)
});
actor.QueueActivity(new Move.Move(allies2BasePoint.Location));
} }
} }
void SendChinook() void SovietsAttackTown()
{ {
einsteinChinook = world.CreateActor(ChinookName, new TypeDictionary { new OwnerInit(allies1), new LocationInit(extractionLZEntryPoint.Location) }); var sovietAttackUnits = world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint1.CenterLocation, SovietTownAttackGroupRange)
einsteinChinook.QueueActivity(new HeliFly(extractionLZ.CenterLocation)); .Union(world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint2.CenterLocation, SovietTownAttackGroupRange))
einsteinChinook.QueueActivity(new Turn(0)); .Union(world.FindAliveCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange))
einsteinChinook.QueueActivity(new HeliLand(true, 0)); .Where(a => a.HasTrait<IMove>() && a.Owner == soviets);
einsteinChinook.QueueActivity(new WaitFor(() => einsteinChinook.Trait<Cargo>().Passengers.Contains(einstein))); foreach (var unit in sovietAttackUnits)
einsteinChinook.QueueActivity(new Wait(150)); {
einsteinChinook.QueueActivity(new HeliFly(extractionLZEntryPoint.CenterLocation)); unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(townPoint.Location, SovietTownMoveNearEnough)));
einsteinChinook.QueueActivity(new RemoveSelf()); }
}
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) public void WorldLoaded(World w)
@@ -412,18 +569,31 @@ namespace OpenRA.Mods.RA.Missions
sam4 = actors["SAM4"]; sam4 = actors["SAM4"];
tanya = actors["Tanya"]; tanya = actors["Tanya"];
einstein = actors["Einstein"]; einstein = actors["Einstein"];
engineer = actors["Engineer"];
chinookHusk = actors["ChinookHusk"]; chinookHusk = actors["ChinookHusk"];
allies2BasePoint = actors["Allies2BasePoint"]; allies2BasePoint = actors["Allies2BasePoint"];
reinforcementsEntryPoint = actors["ReinforcementsEntryPoint"]; reinforcementsEntryPoint = actors["ReinforcementsEntryPoint"];
extractionLZ = actors["ExtractionLZ"]; extractionLZ = actors["ExtractionLZ"];
extractionLZEntryPoint = actors["ExtractionLZEntryPoint"]; extractionLZEntryPoint = actors["ExtractionLZEntryPoint"];
badgerEntryPoint = actors["BadgerEntryPoint"]; badgerEntryPoint1 = actors["BadgerEntryPoint1"];
badgerDropPoint = actors["BadgerDropPoint"]; badgerEntryPoint2 = actors["BadgerEntryPoint2"];
engineerMiss = actors["EngineerMiss"]; badgerDropPoint1 = actors["BadgerDropPoint1"];
badgerDropPoint2 = actors["BadgerDropPoint2"];
badgerDropPoint3 = actors["BadgerDropPoint3"];
parabombPoint1 = actors["ParabombPoint1"];
parabombPoint2 = actors["ParabombPoint2"];
sovietBarracks = actors["SovietBarracks"]; sovietBarracks = actors["SovietBarracks"];
sovietWarFactory = actors["SovietWarFactory"]; sovietWarFactory = actors["SovietWarFactory"];
sovietRallyPoint = actors["SovietRallyPoint"]; sovietRallyPoint = actors["SovietRallyPoint"];
flamersEntryPoint = actors["FlamersEntryPoint"]; 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>(); var shroud = w.WorldActor.Trait<Shroud>();
shroud.Explore(w, sam1.Location, 2); shroud.Explore(w, sam1.Location, 2);
shroud.Explore(w, sam2.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="ColorPickerPaletteModifier.cs" />
<Compile Include="Combat.cs" /> <Compile Include="Combat.cs" />
<Compile Include="ConquestVictoryConditions.cs" /> <Compile Include="ConquestVictoryConditions.cs" />
<Compile Include="ContainsCrate.cs" />
<Compile Include="Crate.cs" /> <Compile Include="Crate.cs" />
<Compile Include="CrateAction.cs" /> <Compile Include="CrateAction.cs" />
<Compile Include="CrateDrop.cs" /> <Compile Include="CrateDrop.cs" />
@@ -181,6 +182,7 @@
<Compile Include="Crates\GiveCashCrateAction.cs" /> <Compile Include="Crates\GiveCashCrateAction.cs" />
<Compile Include="Crates\GiveMcvCrateAction.cs" /> <Compile Include="Crates\GiveMcvCrateAction.cs" />
<Compile Include="Crates\GiveUnitCrateAction.cs" /> <Compile Include="Crates\GiveUnitCrateAction.cs" />
<Compile Include="Crates\HealUnitsCrateAction.cs" />
<Compile Include="Crates\HideMapCrateAction.cs" /> <Compile Include="Crates\HideMapCrateAction.cs" />
<Compile Include="Crates\LevelUpCrateAction.cs" /> <Compile Include="Crates\LevelUpCrateAction.cs" />
<Compile Include="Crates\RevealMapCrateAction.cs" /> <Compile Include="Crates\RevealMapCrateAction.cs" />
@@ -238,7 +240,10 @@
<Compile Include="Minelayer.cs" /> <Compile Include="Minelayer.cs" />
<Compile Include="Missions\Allies01Script.cs" /> <Compile Include="Missions\Allies01Script.cs" />
<Compile Include="Missions\Allies02Script.cs" /> <Compile Include="Missions\Allies02Script.cs" />
<Compile Include="Missions\CountdownTimer.cs" />
<Compile Include="Missions\DefaultShellmapScript.cs" /> <Compile Include="Missions\DefaultShellmapScript.cs" />
<Compile Include="Missions\MissionUtils.cs" />
<Compile Include="Missions\Objective.cs" />
<Compile Include="Modifiers\FrozenUnderFog.cs" /> <Compile Include="Modifiers\FrozenUnderFog.cs" />
<Compile Include="Modifiers\HiddenUnderFog.cs" /> <Compile Include="Modifiers\HiddenUnderFog.cs" />
<Compile Include="Move\Drag.cs" /> <Compile Include="Move\Drag.cs" />
@@ -361,6 +366,7 @@
<Compile Include="Widgets\Logic\LobbyUtils.cs" /> <Compile Include="Widgets\Logic\LobbyUtils.cs" />
<Compile Include="Widgets\Logic\MainMenuButtonsLogic.cs" /> <Compile Include="Widgets\Logic\MainMenuButtonsLogic.cs" />
<Compile Include="Widgets\Logic\MapChooserLogic.cs" /> <Compile Include="Widgets\Logic\MapChooserLogic.cs" />
<Compile Include="Widgets\Logic\MissionObjectivesLogic.cs" />
<Compile Include="Widgets\Logic\MusicPlayerLogic.cs" /> <Compile Include="Widgets\Logic\MusicPlayerLogic.cs" />
<Compile Include="Widgets\Logic\OrderButtonsChromeLogic.cs" /> <Compile Include="Widgets\Logic\OrderButtonsChromeLogic.cs" />
<Compile Include="Widgets\Logic\PerfDebugLogic.cs" /> <Compile Include="Widgets\Logic\PerfDebugLogic.cs" />
@@ -434,4 +440,4 @@
copy "$(TargetPath)" "$(SolutionDir)mods/ra/" copy "$(TargetPath)" "$(SolutionDir)mods/ra/"
cd "$(SolutionDir)"</PostBuildEvent> cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -91,7 +91,7 @@ namespace OpenRA.Mods.RA
if (mobile != null) if (mobile != null)
{ {
newUnit.QueueActivity(new AttackMove.AttackMoveActivity( newUnit.QueueActivity(new AttackMove.AttackMoveActivity(
newUnit, mobile.MoveTo(rp.rallyPoint, 1))); newUnit, mobile.MoveTo(rp.rallyPoint, rp.nearEnough)));
return rp.rallyPoint; 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) * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * 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 public class RallyPoint : IIssueOrder, IResolveOrder, ISync
{ {
[Sync] public CPos rallyPoint; [Sync] public CPos rallyPoint;
public int nearEnough = 1;
public RallyPoint(Actor self) public RallyPoint(Actor self)
{ {

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using OpenRA.Traits; using OpenRA.Traits;
using System.Linq;
using OpenRA.Widgets; using OpenRA.Widgets;
using System.Drawing; using System.Drawing;
@@ -38,6 +39,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
}; };
cheatsButton.IsVisible = () => world.LocalPlayer != null && world.LobbyInfo.GlobalSettings.AllowCheats; 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>("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world);
optionsBG.Get<ButtonWidget>("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU"); 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-bl: 512,82,1,1
corner-br: 594,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 # A copy of dialog2
button-hover: dialog.png button-hover: dialog.png
background: 513,1,126,126 background: 513,1,126,126
@@ -261,6 +272,17 @@ button-hover: dialog.png
corner-bl: 512,82,1,1 corner-bl: 512,82,1,1
corner-br: 594,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 # A copy of dialog2
button-disabled: dialog.png button-disabled: dialog.png
background: 513,1,126,126 background: 513,1,126,126
@@ -273,6 +295,17 @@ button-disabled: dialog.png
corner-bl: 512,82,1,1 corner-bl: 512,82,1,1
corner-br: 594,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 # A copy of dialog3
button-pressed: dialog.png button-pressed: dialog.png
background: 641,1,126,126 background: 641,1,126,126
@@ -284,7 +317,18 @@ button-pressed: dialog.png
corner-tr: 722,0,1,1 corner-tr: 722,0,1,1
corner-bl: 640,82,1,1 corner-bl: 640,82,1,1
corner-br: 722,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 scrollthumb: dialog.png
background: 513,1,126,126 background: 513,1,126,126
border-r: 639,1,1,126 border-r: 639,1,1,126

View File

@@ -81,6 +81,14 @@ Container@INGAME_ROOT:
Text:Cheats Text:Cheats
Visible:false Visible:false
Font:Bold Font:Bold
Button@OBJECTIVES_BUTTON:
X:486
Y:0
Width:160
Height:25
Text:Objectives
Visible:false
Font:Bold
RadarBin@INGAME_RADAR_BIN: RadarBin@INGAME_RADAR_BIN:
WorldInteractionController:INTERACTION_CONTROLLER WorldInteractionController:INTERACTION_CONTROLLER
PowerBin@INGAME_POWER_BIN: 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/dropdowns.yaml
mods/ra/chrome/modchooser.yaml mods/ra/chrome/modchooser.yaml
mods/ra/chrome/cheats.yaml mods/ra/chrome/cheats.yaml
mods/ra/chrome/objectives.yaml
Weapons: Weapons:
mods/ra/weapons.yaml mods/ra/weapons.yaml

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1107,6 +1107,23 @@ UnitExplodeSmall:
Explosion: large_explosion Explosion: large_explosion
InfDeath: 4 InfDeath: 4
ImpactSound: kaboom15 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: Crush:
Warhead: Warhead: