Add mission objectives logic/backend

This commit is contained in:
Scott_NZ
2012-09-26 01:04:33 +12:00
parent 48997725c3
commit 83d10ba838
10 changed files with 212 additions and 136 deletions

View File

@@ -8,66 +8,37 @@
*/ */
#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.Network; using OpenRA.Network;
using OpenRA.Scripting; using OpenRA.Scripting;
using OpenRA.Traits; using OpenRA.Traits;
using System;
namespace OpenRA.Mods.RA.Missions 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
{ {
[Flags] public event Action ObjectivesUpdated;
enum Allies01Objectives
{
None = 0,
FindEinstein = 1,
WaitForHelicopter = 2
}
IEnumerable<string> GetObjectiveText() public IEnumerable<Objective> Objectives { get { return objectives.Values; } }
{
var objectives = new List<string>();
if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.FindEinstein))
{
objectives.Add("Find Einstein. Tanya and Einstein must survive.");
}
if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.WaitForHelicopter))
{
objectives.Add("Wait for the helicopter and extract Einstein. Tanya and Einstein must survive.");
}
return objectives;
}
Allies01Objectives currentObjectives = Allies01Objectives.FindEinstein; Dictionary<int, Objective> objectives = new Dictionary<int, Objective>
void DisplayObjective(string objective)
{ {
Game.AddChatLine(Color.LimeGreen, "Objective", objective); { FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) },
Sound.Play("bleep6.aud"); { ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) }
} };
void DisplayHint(string hint) const int FindEinsteinID = 0;
{ const int ExtractEinsteinID = 1;
Game.AddChatLine(Color.Yellow, "Hint", hint);
Sound.Play("bleep6.aud");
}
void DisplayObjectives() 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.";
foreach (var objective in GetObjectiveText())
{
DisplayObjective(objective);
}
}
Player allies; Player allies;
Player soviets; Player soviets;
@@ -137,15 +108,11 @@ namespace OpenRA.Mods.RA.Missions
{ {
return; return;
} }
if (world.FrameNumber % 1500 == 1)
{
DisplayObjectives();
}
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)]);
} }
if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.FindEinstein)) if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress)
{ {
if (AlliesControlLab()) if (AlliesControlLab())
{ {
@@ -153,17 +120,19 @@ namespace OpenRA.Mods.RA.Missions
Sound.Play("flaren1.aud"); Sound.Play("flaren1.aud");
SpawnEinsteinAtLab(); SpawnEinsteinAtLab();
SendShips(); SendShips();
currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies01Objectives.FindEinstein); objectives[FindEinsteinID].Status = ObjectiveStatus.Completed;
currentObjectives = MissionUtils.AddFlag(currentObjectives, Allies01Objectives.WaitForHelicopter); objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
DisplayObjectives(); ObjectivesUpdated();
currentAttackWaveFrameNumber = world.FrameNumber; currentAttackWaveFrameNumber = world.FrameNumber;
} }
if (lab.Destroyed) if (lab.Destroyed)
{ {
objectives[FindEinsteinID].Status = ObjectiveStatus.Failed;
ObjectivesUpdated();
MissionFailed("Einstein was killed."); MissionFailed("Einstein was killed.");
} }
} }
if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.WaitForHelicopter)) if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress)
{ {
if (world.FrameNumber >= currentAttackWaveFrameNumber + 600) if (world.FrameNumber >= currentAttackWaveFrameNumber + 600)
{ {
@@ -184,10 +153,14 @@ namespace OpenRA.Mods.RA.Missions
{ {
if (einsteinChinook.Destroyed) if (einsteinChinook.Destroyed)
{ {
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
ObjectivesUpdated();
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;
ObjectivesUpdated();
MissionAccomplished("Einstein was rescued."); MissionAccomplished("Einstein was rescued.");
} }
} }
@@ -334,7 +307,6 @@ namespace OpenRA.Mods.RA.Missions
InsertTanyaAtLZ(); InsertTanyaAtLZ();
SendPatrol(); SendPatrol();
PlayMusic(); PlayMusic();
DisplayObjectives();
}); });
}); });
} }

View File

@@ -26,56 +26,29 @@ 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
{ {
[Flags] public event Action ObjectivesUpdated;
enum Allies02Objectives
{
None = 0,
FindEinstein = 1,
DestroySamSites = 2,
WaitForHelicopter = 4
}
IEnumerable<string> GetObjectiveText() public IEnumerable<Objective> Objectives { get { return objectives.Values; } }
{
var objectives = new List<string>();
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.FindEinstein))
{
objectives.Add("Find Einstein's crashed helicopter. Tanya must survive.");
}
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.DestroySamSites))
{
objectives.Add("Destroy the SAM sites. Tanya must survive.");
}
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.WaitForHelicopter))
{
objectives.Add("Wait for the helicopter and extract Einstein. Tanya and Einstein must survive.");
}
return objectives;
}
Allies02Objectives currentObjectives = Allies02Objectives.FindEinstein | Allies02Objectives.DestroySamSites; Dictionary<int, Objective> objectives = new Dictionary<int, Objective>()
void DisplayObjective(string objective)
{ {
Game.AddChatLine(Color.LimeGreen, "Objective", objective); { FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) },
Sound.Play("bleep6.aud"); { DestroySamSitesID, new Objective(ObjectiveType.Primary, DestroySamSites, ObjectiveStatus.InProgress) },
} { ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) },
{ MaintainPresenceID, new Objective(ObjectiveType.Secondary, MaintainPresence, ObjectiveStatus.InProgress) }
};
void DisplayHint(string hint) const int FindEinsteinID = 0;
{ const int DestroySamSitesID = 1;
Game.AddChatLine(Color.Yellow, "Hint", hint); const int ExtractEinsteinID = 2;
Sound.Play("bleep6.aud"); const int MaintainPresenceID = 3;
}
void DisplayObjectives() const string FindEinstein = "Find Einstein's crashed helicopter. Tanya must survive.";
{ const string DestroySamSites = "Destroy the SAM sites. Tanya must survive.";
foreach (var objective in GetObjectiveText()) 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.";
DisplayObjective(objective);
}
}
Actor sam1; Actor sam1;
Actor sam2; Actor sam2;
@@ -180,10 +153,6 @@ namespace OpenRA.Mods.RA.Missions
{ {
return; return;
} }
if (world.FrameNumber % 3500 == 1)
{
DisplayObjectives();
}
if (world.FrameNumber % 50 == 1 && chinookHusk.IsInWorld) if (world.FrameNumber % 50 == 1 && chinookHusk.IsInWorld)
{ {
world.Add(new Smoke(world, chinookHusk.CenterLocation, "smoke_m")); world.Add(new Smoke(world, chinookHusk.CenterLocation, "smoke_m"));
@@ -193,10 +162,6 @@ namespace OpenRA.Mods.RA.Missions
InitializeSovietFactories(); InitializeSovietFactories();
StartReinforcementsTimer(); StartReinforcementsTimer();
} }
if (world.FrameNumber == HintPowerTicks)
{
DisplayHint("Destroy the Soviet power stations to stop the attacks on the Allied reinforcements.");
}
reinforcementsTimer.Tick(); reinforcementsTimer.Tick();
if (world.FrameNumber == ParatroopersTicks) if (world.FrameNumber == ParatroopersTicks)
{ {
@@ -216,36 +181,40 @@ namespace OpenRA.Mods.RA.Missions
BuildSovietUnits(); BuildSovietUnits();
ManageSovietUnits(); ManageSovietUnits();
} }
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.FindEinstein)) if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress)
{ {
if (AlliesNearTown()) if (AlliesNearTown())
{ {
currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies02Objectives.FindEinstein); objectives[FindEinsteinID].Status = ObjectiveStatus.Completed;
DisplayObjectives(); ObjectivesUpdated();
TransferTownUnitsToAllies(); TransferTownUnitsToAllies();
SovietsAttackTown(); SovietsAttackTown();
} }
} }
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.DestroySamSites)) if (objectives[DestroySamSitesID].Status == ObjectiveStatus.InProgress)
{ {
if (sam1.Destroyed && sam2.Destroyed && sam3.Destroyed && sam4.Destroyed) if (sam1.Destroyed && sam2.Destroyed && sam3.Destroyed && sam4.Destroyed)
{ {
currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies02Objectives.DestroySamSites); objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed;
currentObjectives = MissionUtils.AddFlag(currentObjectives, Allies02Objectives.WaitForHelicopter); objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
DisplayObjectives(); ObjectivesUpdated();
SpawnSignalFlare(); SpawnSignalFlare();
Sound.Play("flaren1.aud"); Sound.Play("flaren1.aud");
ExtractEinsteinAtLZ(); ExtractEinsteinAtLZ();
} }
} }
if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.WaitForHelicopter) && einsteinChinook != null) if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null)
{ {
if (einsteinChinook.Destroyed) if (einsteinChinook.Destroyed)
{ {
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
ObjectivesUpdated();
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;
ObjectivesUpdated();
MissionAccomplished("Einstein was rescued."); MissionAccomplished("Einstein was rescued.");
} }
} }
@@ -261,6 +230,8 @@ namespace OpenRA.Mods.RA.Missions
{ {
if (!world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20).Any(a => a.HasTrait<Building>() && !a.HasTrait<Wall>() && a.Owner == allies2)) if (!world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20).Any(a => a.HasTrait<Building>() && !a.HasTrait<Wall>() && a.Owner == allies2))
{ {
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
ObjectivesUpdated();
MissionFailed("The Allied reinforcements have been defeated."); MissionFailed("The Allied reinforcements have been defeated.");
} }
}); });
@@ -497,6 +468,7 @@ namespace OpenRA.Mods.RA.Missions
{ {
Game.MoveViewport(allies2BasePoint.Location.ToFloat2()); Game.MoveViewport(allies2BasePoint.Location.ToFloat2());
} }
ObjectivesUpdated();
PlayMusic(); PlayMusic();
Game.ConnectionStateChanged += StopMusic; Game.ConnectionStateChanged += StopMusic;
} }

View File

@@ -16,7 +16,6 @@ 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.Traits; using OpenRA.Traits;
using System.Drawing;
namespace OpenRA.Mods.RA.Missions namespace OpenRA.Mods.RA.Missions
{ {
@@ -91,26 +90,5 @@ namespace OpenRA.Mods.RA.Missions
.Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category) .Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category)
.Select(a => a.Trait); .Select(a => a.Trait);
} }
public static T AddFlag<T>(T flags, T flag)
{
var fs = Convert.ToInt32(flags);
var f = Convert.ToInt32(flag);
return (T)(object)(fs | f);
}
public static T RemoveFlag<T>(T flags, T flag)
{
var fs = Convert.ToInt32(flags);
var f = Convert.ToInt32(flag);
return (T)(object)(fs & ~f);
}
public static bool HasFlag<T>(T flags, T flag)
{
var fs = Convert.ToInt32(flags);
var f = Convert.ToInt32(flag);
return (fs & f) == f;
}
} }
} }

View File

@@ -0,0 +1,52 @@
#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 interface IHasObjectives
{
event Action ObjectivesUpdated;
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

@@ -243,6 +243,7 @@
<Compile Include="Missions\CountdownTimer.cs" /> <Compile Include="Missions\CountdownTimer.cs" />
<Compile Include="Missions\DefaultShellmapScript.cs" /> <Compile Include="Missions\DefaultShellmapScript.cs" />
<Compile Include="Missions\MissionUtils.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" />
@@ -366,6 +367,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" />

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,19 @@ 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,84 @@
#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.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic
{
public class MissionObjectivesLogic
{
IHasObjectives objectives;
Widget primaryPanel;
Widget secondaryPanel;
Widget primaryTemplate;
Widget secondaryTemplate;
[ObjectCreator.UseCtor]
public MissionObjectivesLogic(World world, Widget widget)
{
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();
Game.ConnectionStateChanged += RemoveHandlers;
objectives.ObjectivesUpdated += UpdateObjectives;
UpdateObjectives();
}
public void RemoveHandlers(OrderManager orderManager)
{
if (!orderManager.GameStarted)
{
Game.ConnectionStateChanged -= RemoveHandlers;
objectives.ObjectivesUpdated -= UpdateObjectives;
}
}
public void UpdateObjectives()
{
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 "";
}
}
}
}

View File

@@ -1,4 +1,5 @@
Container@MISSION_OBJECTIVES: Container@MISSION_OBJECTIVES:
Logic:MissionObjectivesLogic
X:25 X:25
Y:50 Y:50
Width:512 Width:512

View File

@@ -349,6 +349,8 @@ Rules:
-SpawnMPUnits: -SpawnMPUnits:
-MPStartLocations: -MPStartLocations:
Allies01Script: Allies01Script:
MissionObjectivesPanel:
ObjectivesPanel: MISSION_OBJECTIVES
POWR: POWR:
Health: Health:
HP: 100 HP: 100

View File

@@ -2117,9 +2117,6 @@ Actors:
Actor694: dog Actor694: dog
Location: 87,79 Location: 87,79
Owner: Soviets Owner: Soviets
Actor710: dog
Location: 92,81
Owner: Soviets
Actor712: e1 Actor712: e1
Location: 71,86 Location: 71,86
Owner: Neutral Owner: Neutral
@@ -2266,6 +2263,8 @@ Rules:
-SpawnMPUnits: -SpawnMPUnits:
-MPStartLocations: -MPStartLocations:
Allies02Script: Allies02Script:
MissionObjectivesPanel:
ObjectivesPanel: MISSION_OBJECTIVES
TRAN.Husk1: TRAN.Husk1:
Burns: Burns:
Damage: 0 Damage: 0