From 83d10ba838c63a068681bb053e5458e6dcd4d81a Mon Sep 17 00:00:00 2001 From: Scott_NZ Date: Wed, 26 Sep 2012 01:04:33 +1200 Subject: [PATCH] Add mission objectives logic/backend --- OpenRA.Mods.RA/Missions/Allies01Script.cs | 74 +++++---------- OpenRA.Mods.RA/Missions/Allies02Script.cs | 92 +++++++------------ OpenRA.Mods.RA/Missions/MissionUtils.cs | 22 ----- OpenRA.Mods.RA/Missions/Objective.cs | 52 +++++++++++ OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 2 + .../Widgets/Logic/IngameChromeLogic.cs | 14 +++ .../Widgets/Logic/MissionObjectivesLogic.cs | 84 +++++++++++++++++ mods/ra/chrome/objectives.yaml | 1 + mods/ra/maps/allies-01/map.yaml | 2 + mods/ra/maps/allies-02/map.yaml | 5 +- 10 files changed, 212 insertions(+), 136 deletions(-) create mode 100644 OpenRA.Mods.RA/Missions/Objective.cs create mode 100644 OpenRA.Mods.RA/Widgets/Logic/MissionObjectivesLogic.cs diff --git a/OpenRA.Mods.RA/Missions/Allies01Script.cs b/OpenRA.Mods.RA/Missions/Allies01Script.cs index be61f4f0ce..e8957314e2 100644 --- a/OpenRA.Mods.RA/Missions/Allies01Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies01Script.cs @@ -8,66 +8,37 @@ */ #endregion +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.FileFormats; using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Air; using OpenRA.Network; using OpenRA.Scripting; using OpenRA.Traits; -using System; namespace OpenRA.Mods.RA.Missions { class Allies01ScriptInfo : TraitInfo, Requires { } - class Allies01Script : IWorldLoaded, ITick + class Allies01Script : IHasObjectives, IWorldLoaded, ITick { - [Flags] - enum Allies01Objectives - { - None = 0, - FindEinstein = 1, - WaitForHelicopter = 2 - } + public event Action ObjectivesUpdated; - IEnumerable GetObjectiveText() - { - var objectives = new List(); - 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; - } + public IEnumerable Objectives { get { return objectives.Values; } } - Allies01Objectives currentObjectives = Allies01Objectives.FindEinstein; - - void DisplayObjective(string objective) + Dictionary objectives = new Dictionary { - Game.AddChatLine(Color.LimeGreen, "Objective", objective); - Sound.Play("bleep6.aud"); - } + { FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) }, + { ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) } + }; - void DisplayHint(string hint) - { - Game.AddChatLine(Color.Yellow, "Hint", hint); - Sound.Play("bleep6.aud"); - } + const int FindEinsteinID = 0; + const int ExtractEinsteinID = 1; - void DisplayObjectives() - { - foreach (var objective in GetObjectiveText()) - { - DisplayObjective(objective); - } - } + const string FindEinstein = "Find Einstein. Tanya and Einstein must survive."; + const string ExtractEinstein = "Wait for the helicopter and extract Einstein. Tanya and Einstein must survive."; Player allies; Player soviets; @@ -137,15 +108,11 @@ namespace OpenRA.Mods.RA.Missions { return; } - if (world.FrameNumber % 1500 == 1) - { - DisplayObjectives(); - } if (world.FrameNumber % 1000 == 0) { Sound.Play(Taunts[world.SharedRandom.Next(Taunts.Length)]); } - if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.FindEinstein)) + if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress) { if (AlliesControlLab()) { @@ -153,17 +120,19 @@ namespace OpenRA.Mods.RA.Missions Sound.Play("flaren1.aud"); SpawnEinsteinAtLab(); SendShips(); - currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies01Objectives.FindEinstein); - currentObjectives = MissionUtils.AddFlag(currentObjectives, Allies01Objectives.WaitForHelicopter); - DisplayObjectives(); + objectives[FindEinsteinID].Status = ObjectiveStatus.Completed; + objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress; + ObjectivesUpdated(); currentAttackWaveFrameNumber = world.FrameNumber; } if (lab.Destroyed) { + objectives[FindEinsteinID].Status = ObjectiveStatus.Failed; + ObjectivesUpdated(); MissionFailed("Einstein was killed."); } } - if (MissionUtils.HasFlag(currentObjectives, Allies01Objectives.WaitForHelicopter)) + if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress) { if (world.FrameNumber >= currentAttackWaveFrameNumber + 600) { @@ -184,10 +153,14 @@ namespace OpenRA.Mods.RA.Missions { if (einsteinChinook.Destroyed) { + objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed; + ObjectivesUpdated(); MissionFailed("The extraction helicopter was destroyed."); } else if (!world.Map.IsInMap(einsteinChinook.Location) && einsteinChinook.Trait().Passengers.Contains(einstein)) { + objectives[ExtractEinsteinID].Status = ObjectiveStatus.Completed; + ObjectivesUpdated(); MissionAccomplished("Einstein was rescued."); } } @@ -334,7 +307,6 @@ namespace OpenRA.Mods.RA.Missions InsertTanyaAtLZ(); SendPatrol(); PlayMusic(); - DisplayObjectives(); }); }); } diff --git a/OpenRA.Mods.RA/Missions/Allies02Script.cs b/OpenRA.Mods.RA/Missions/Allies02Script.cs index bfd861485d..64c2f9c3bd 100644 --- a/OpenRA.Mods.RA/Missions/Allies02Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies02Script.cs @@ -26,56 +26,29 @@ namespace OpenRA.Mods.RA.Missions { class Allies02ScriptInfo : TraitInfo, Requires { } - class Allies02Script : IWorldLoaded, ITick + class Allies02Script : IHasObjectives, IWorldLoaded, ITick { - [Flags] - enum Allies02Objectives - { - None = 0, - FindEinstein = 1, - DestroySamSites = 2, - WaitForHelicopter = 4 - } + public event Action ObjectivesUpdated; - IEnumerable GetObjectiveText() - { - var objectives = new List(); - 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; - } + public IEnumerable Objectives { get { return objectives.Values; } } - Allies02Objectives currentObjectives = Allies02Objectives.FindEinstein | Allies02Objectives.DestroySamSites; - - void DisplayObjective(string objective) + Dictionary objectives = new Dictionary() { - Game.AddChatLine(Color.LimeGreen, "Objective", objective); - Sound.Play("bleep6.aud"); - } + { FindEinsteinID, new Objective(ObjectiveType.Primary, FindEinstein, ObjectiveStatus.InProgress) }, + { DestroySamSitesID, new Objective(ObjectiveType.Primary, DestroySamSites, ObjectiveStatus.InProgress) }, + { ExtractEinsteinID, new Objective(ObjectiveType.Primary, ExtractEinstein, ObjectiveStatus.Inactive) }, + { MaintainPresenceID, new Objective(ObjectiveType.Secondary, MaintainPresence, ObjectiveStatus.InProgress) } + }; - void DisplayHint(string hint) - { - Game.AddChatLine(Color.Yellow, "Hint", hint); - Sound.Play("bleep6.aud"); - } + const int FindEinsteinID = 0; + const int DestroySamSitesID = 1; + const int ExtractEinsteinID = 2; + const int MaintainPresenceID = 3; - void DisplayObjectives() - { - foreach (var objective in GetObjectiveText()) - { - DisplayObjective(objective); - } - } + 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."; Actor sam1; Actor sam2; @@ -180,10 +153,6 @@ namespace OpenRA.Mods.RA.Missions { return; } - if (world.FrameNumber % 3500 == 1) - { - DisplayObjectives(); - } if (world.FrameNumber % 50 == 1 && chinookHusk.IsInWorld) { world.Add(new Smoke(world, chinookHusk.CenterLocation, "smoke_m")); @@ -193,10 +162,6 @@ namespace OpenRA.Mods.RA.Missions InitializeSovietFactories(); StartReinforcementsTimer(); } - if (world.FrameNumber == HintPowerTicks) - { - DisplayHint("Destroy the Soviet power stations to stop the attacks on the Allied reinforcements."); - } reinforcementsTimer.Tick(); if (world.FrameNumber == ParatroopersTicks) { @@ -216,36 +181,40 @@ namespace OpenRA.Mods.RA.Missions BuildSovietUnits(); ManageSovietUnits(); } - if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.FindEinstein)) + if (objectives[FindEinsteinID].Status == ObjectiveStatus.InProgress) { if (AlliesNearTown()) { - currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies02Objectives.FindEinstein); - DisplayObjectives(); + objectives[FindEinsteinID].Status = ObjectiveStatus.Completed; + ObjectivesUpdated(); TransferTownUnitsToAllies(); SovietsAttackTown(); } } - if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.DestroySamSites)) + if (objectives[DestroySamSitesID].Status == ObjectiveStatus.InProgress) { if (sam1.Destroyed && sam2.Destroyed && sam3.Destroyed && sam4.Destroyed) { - currentObjectives = MissionUtils.RemoveFlag(currentObjectives, Allies02Objectives.DestroySamSites); - currentObjectives = MissionUtils.AddFlag(currentObjectives, Allies02Objectives.WaitForHelicopter); - DisplayObjectives(); + objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed; + objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress; + ObjectivesUpdated(); SpawnSignalFlare(); Sound.Play("flaren1.aud"); ExtractEinsteinAtLZ(); } } - if (MissionUtils.HasFlag(currentObjectives, Allies02Objectives.WaitForHelicopter) && einsteinChinook != null) + if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null) { if (einsteinChinook.Destroyed) { + objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed; + ObjectivesUpdated(); MissionFailed("The extraction helicopter was destroyed."); } else if (!world.Map.IsInMap(einsteinChinook.Location) && einsteinChinook.Trait().Passengers.Contains(einstein)) { + objectives[ExtractEinsteinID].Status = ObjectiveStatus.Completed; + ObjectivesUpdated(); MissionAccomplished("Einstein was rescued."); } } @@ -261,6 +230,8 @@ namespace OpenRA.Mods.RA.Missions { if (!world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20).Any(a => a.HasTrait() && !a.HasTrait() && a.Owner == allies2)) { + objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed; + ObjectivesUpdated(); MissionFailed("The Allied reinforcements have been defeated."); } }); @@ -497,6 +468,7 @@ namespace OpenRA.Mods.RA.Missions { Game.MoveViewport(allies2BasePoint.Location.ToFloat2()); } + ObjectivesUpdated(); PlayMusic(); Game.ConnectionStateChanged += StopMusic; } diff --git a/OpenRA.Mods.RA/Missions/MissionUtils.cs b/OpenRA.Mods.RA/Missions/MissionUtils.cs index fd9ce25921..5d694d8905 100644 --- a/OpenRA.Mods.RA/Missions/MissionUtils.cs +++ b/OpenRA.Mods.RA/Missions/MissionUtils.cs @@ -16,7 +16,6 @@ using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; using OpenRA.Traits; -using System.Drawing; 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) .Select(a => a.Trait); } - - public static T AddFlag(T flags, T flag) - { - var fs = Convert.ToInt32(flags); - var f = Convert.ToInt32(flag); - return (T)(object)(fs | f); - } - - public static T RemoveFlag(T flags, T flag) - { - var fs = Convert.ToInt32(flags); - var f = Convert.ToInt32(flag); - return (T)(object)(fs & ~f); - } - - public static bool HasFlag(T flags, T flag) - { - var fs = Convert.ToInt32(flags); - var f = Convert.ToInt32(flag); - return (fs & f) == f; - } } } diff --git a/OpenRA.Mods.RA/Missions/Objective.cs b/OpenRA.Mods.RA/Missions/Objective.cs new file mode 100644 index 0000000000..616cfe177e --- /dev/null +++ b/OpenRA.Mods.RA/Missions/Objective.cs @@ -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 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; } } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 0042008f01..d46ecfe5e8 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -243,6 +243,7 @@ + @@ -366,6 +367,7 @@ + diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs index c54ba06f9a..5a91a546de 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs @@ -9,6 +9,7 @@ #endregion using OpenRA.Traits; +using System.Linq; using OpenRA.Widgets; using System.Drawing; @@ -38,6 +39,19 @@ namespace OpenRA.Mods.RA.Widgets.Logic }; cheatsButton.IsVisible = () => world.LocalPlayer != null && world.LobbyInfo.GlobalSettings.AllowCheats; + var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); + if (iop != null && iop.ObjectivesPanel != null) + { + var objectivesButton = gameRoot.Get("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("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world); optionsBG.Get("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU"); diff --git a/OpenRA.Mods.RA/Widgets/Logic/MissionObjectivesLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MissionObjectivesLogic.cs new file mode 100644 index 0000000000..391d63a6d9 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/MissionObjectivesLogic.cs @@ -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().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("SECONDARY_OBJECTIVE").GetText = () => objective.Text; + template.Get("SECONDARY_STATUS").GetText = () => GetObjectiveStatusText(objective.Status); + secondaryPanel.AddChild(template); + } + else + { + var template = primaryTemplate.Clone(); + template.Get("PRIMARY_OBJECTIVE").GetText = () => objective.Text; + template.Get("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 ""; + } + } + } +} diff --git a/mods/ra/chrome/objectives.yaml b/mods/ra/chrome/objectives.yaml index c01521fd2f..3da3275072 100644 --- a/mods/ra/chrome/objectives.yaml +++ b/mods/ra/chrome/objectives.yaml @@ -1,4 +1,5 @@ Container@MISSION_OBJECTIVES: + Logic:MissionObjectivesLogic X:25 Y:50 Width:512 diff --git a/mods/ra/maps/allies-01/map.yaml b/mods/ra/maps/allies-01/map.yaml index 7ac1f747fb..e0e040a0d6 100644 --- a/mods/ra/maps/allies-01/map.yaml +++ b/mods/ra/maps/allies-01/map.yaml @@ -349,6 +349,8 @@ Rules: -SpawnMPUnits: -MPStartLocations: Allies01Script: + MissionObjectivesPanel: + ObjectivesPanel: MISSION_OBJECTIVES POWR: Health: HP: 100 diff --git a/mods/ra/maps/allies-02/map.yaml b/mods/ra/maps/allies-02/map.yaml index 6e5a62d416..1deceaf284 100644 --- a/mods/ra/maps/allies-02/map.yaml +++ b/mods/ra/maps/allies-02/map.yaml @@ -2117,9 +2117,6 @@ Actors: Actor694: dog Location: 87,79 Owner: Soviets - Actor710: dog - Location: 92,81 - Owner: Soviets Actor712: e1 Location: 71,86 Owner: Neutral @@ -2266,6 +2263,8 @@ Rules: -SpawnMPUnits: -MPStartLocations: Allies02Script: + MissionObjectivesPanel: + ObjectivesPanel: MISSION_OBJECTIVES TRAN.Husk1: Burns: Damage: 0