diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 780673dd7f..e8fb764998 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -271,7 +271,16 @@ namespace OpenRA.Traits public interface ILintPass { void Run(Action emitError, Action emitWarning, Map map); } - public interface IObjectivesPanel { string ObjectivesPanel { get; } } + public interface IObjectivesPanel { string PanelName { get; } } + + public interface INotifyObjectivesUpdated + { + void OnPlayerWon(Player winner); + void OnPlayerLost(Player loser); + void OnObjectiveAdded(Player player, int objectiveID); + void OnObjectiveCompleted(Player player, int objectiveID); + void OnObjectiveFailed(Player player, int objectiveID); + } public static class DisableExts { diff --git a/OpenRA.Game/Widgets/CheckboxWidget.cs b/OpenRA.Game/Widgets/CheckboxWidget.cs index ad7e7c251b..29a2726ac4 100644 --- a/OpenRA.Game/Widgets/CheckboxWidget.cs +++ b/OpenRA.Game/Widgets/CheckboxWidget.cs @@ -50,7 +50,8 @@ namespace OpenRA.Widgets var colordisabled = GetColorDisabled(); var contrast = GetContrastColor(); var rect = RenderBounds; - var textSize = font.Measure(Text); + var text = GetText(); + var textSize = font.Measure(text); var check = new Rectangle(rect.Location, new Size(Bounds.Height, Bounds.Height)); var state = disabled ? "checkbox-disabled" : highlighted ? "checkbox-highlighted" : @@ -62,10 +63,10 @@ namespace OpenRA.Widgets var position = new float2(rect.Left + rect.Height * 1.5f, RenderOrigin.Y - BaseLine + (Bounds.Height - textSize.Y)/2); if (Contrast) - font.DrawTextWithContrast(Text, position, + font.DrawTextWithContrast(text, position, disabled ? colordisabled : color, contrast, 2); else - font.DrawText(Text, position, + font.DrawText(text, position, disabled ? colordisabled : color); if (IsChecked() || (Depressed && HasPressedState && !disabled)) diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index 030fba1e7e..4ef77ecd88 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -51,6 +51,11 @@ namespace OpenRA.Widgets return window; } + public static Widget CurrentWindow() + { + return WindowList.Count > 0 ? WindowList.Peek() : null; + } + public static T LoadWidget(string id, Widget parent, WidgetArgs args) where T : Widget { var widget = LoadWidget(id, parent, args) as T; diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index d58d68e474..a2ac5c1ca4 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -42,8 +42,19 @@ namespace OpenRA public void AddPlayer(Player p) { Players.Add(p); } public Player LocalPlayer { get; private set; } - Player renderPlayer; + public event Action GameOver = () => { }; + bool gameOver; + public void EndGame() + { + if (!gameOver) + { + gameOver = true; + GameOver(); + } + } + public bool ObserveAfterWinOrLose; + Player renderPlayer; public Player RenderPlayer { get { return renderPlayer == null || (ObserveAfterWinOrLose && renderPlayer.WinState != WinState.Undefined) ? null : renderPlayer; } diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index 9f86250d9f..de31845598 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -75,8 +75,6 @@ - - diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameMenuLogic.cs b/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameMenuLogic.cs deleted file mode 100644 index 3826fff390..0000000000 --- a/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameMenuLogic.cs +++ /dev/null @@ -1,131 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Widgets; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Cnc.Widgets.Logic -{ - public class CncIngameMenuLogic - { - Widget menu; - - enum PanelType { Objectives, Debug } - - [ObjectCreator.UseCtor] - public CncIngameMenuLogic(Widget widget, World world, Action onExit, WorldRenderer worldRenderer) - { - var resumeDisabled = false; - menu = widget.Get("INGAME_MENU"); - var mpe = world.WorldActor.Trait(); - mpe.Fade(MenuPaletteEffect.EffectType.Desaturated); - - menu.Get("VERSION_LABEL").Text = Game.modData.Manifest.Mod.Version; - - var hideButtons = false; - menu.Get("MENU_BUTTONS").IsVisible = () => !hideButtons; - - // TODO: Create a mechanism to do things like this cleaner. Also needed for scripted missions - Action onQuit = () => - { - Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", null); - resumeDisabled = true; - Game.RunAfterDelay(1200, () => mpe.Fade(MenuPaletteEffect.EffectType.Black)); - Game.RunAfterDelay(1200 + 40 * mpe.Info.FadeLength, () => - { - Game.Disconnect(); - Ui.ResetAll(); - Game.LoadShellMap(); - }); - }; - - Action doNothing = () => { }; - - menu.Get("QUIT_BUTTON").OnClick = () => - ConfirmationDialogs.PromptConfirmAction("Abort Mission", "Leave this game and return to the menu?", onQuit, doNothing); - - Action onSurrender = () => world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor, false)); - var surrenderButton = menu.Get("SURRENDER_BUTTON"); - surrenderButton.IsDisabled = () => (world.LocalPlayer == null || world.LocalPlayer.WinState != WinState.Undefined); - surrenderButton.OnClick = () => - ConfirmationDialogs.PromptConfirmAction("Surrender", "Are you sure you want to surrender?", onSurrender, doNothing); - - menu.Get("MUSIC_BUTTON").OnClick = () => - { - hideButtons = true; - Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs() - { - { "onExit", () => hideButtons = false }, - { "world", world } - }); - }; - - menu.Get("SETTINGS_BUTTON").OnClick = () => - { - hideButtons = true; - Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs() - { - { "world", world }, - { "worldRenderer", worldRenderer }, - { "onExit", () => hideButtons = false }, - }); - }; - - var resumeButton = menu.Get("RESUME_BUTTON"); - resumeButton.IsDisabled = () => resumeDisabled; - resumeButton.OnClick = () => - { - Ui.CloseWindow(); - Ui.Root.RemoveChild(menu); - world.WorldActor.Trait().Fade(MenuPaletteEffect.EffectType.None); - onExit(); - }; - - // Menu panels - ordered from lowest to highest priority - var panelParent = Game.OpenWindow(world, "INGAME_MENU_PANEL"); - var panelType = PanelType.Objectives; - var visibleButtons = 0; - - // Debug / Cheats panel - var debugButton = panelParent.Get("DEBUG_BUTTON"); - debugButton.OnClick = () => panelType = PanelType.Debug; - debugButton.IsHighlighted = () => panelType == PanelType.Debug; - - if (world.LocalPlayer != null && world.LobbyInfo.GlobalSettings.AllowCheats) - { - panelType = PanelType.Debug; - visibleButtons++; - var debugPanel = Game.LoadWidget(world, "DEBUG_PANEL", panelParent, new WidgetArgs() { { "onExit", doNothing }, { "transient", true } }); - debugPanel.IsVisible = () => panelType == PanelType.Debug; - debugButton.IsVisible = () => visibleButtons > 1; - } - - // Mission objectives - var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); - var objectivesButton = panelParent.Get("OBJECTIVES_BUTTON"); - objectivesButton.OnClick = () => panelType = PanelType.Objectives; - objectivesButton.IsHighlighted = () => panelType == PanelType.Objectives; - - if (iop != null && iop.ObjectivesPanel != null) - { - panelType = PanelType.Objectives; - visibleButtons++; - var objectivesPanel = Game.LoadWidget(world, iop.ObjectivesPanel, panelParent, new WidgetArgs()); - objectivesPanel.IsVisible = () => panelType == PanelType.Objectives; - objectivesButton.IsVisible = () => visibleButtons > 1; - } - } - } -} diff --git a/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs b/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs index db55cffc9d..4c7ddeb0d2 100644 --- a/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs +++ b/OpenRA.Mods.D2k/Widgets/Logic/IngameChromeLogic.cs @@ -8,11 +8,14 @@ */ #endregion +using System; using System.Drawing; using System.Linq; using OpenRA.Mods.RA; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Widgets; +using OpenRA.Mods.RA.Widgets.Logic; +using OpenRA.Mods.D2k.Widgets; using OpenRA.Traits; using OpenRA.Widgets; @@ -40,54 +43,19 @@ namespace OpenRA.Mods.D2k.Widgets.Logic void InitRootWidgets() { - var cachedPause = false; - Widget optionsBG = null; - optionsBG = Game.LoadWidget(world, "INGAME_OPTIONS_BG", Ui.Root, new WidgetArgs - { - { "transient", false }, - { "onExit", () => - { - optionsBG.Visible = false; - - if (world.LobbyInfo.IsSinglePlayer) - world.SetPauseState(cachedPause); - } - } - }); - - optionsBG.Visible = false; - - gameRoot.Get("INGAME_OPTIONS_BUTTON").OnClick = () => - { - optionsBG.Visible ^= true; - if (optionsBG.Visible) - { - cachedPause = world.PredictedPaused; - - if (world.LobbyInfo.IsSinglePlayer) - world.SetPauseState(true); - } - else - world.SetPauseState(cachedPause); - }; - Game.LoadWidget(world, "CHAT_PANEL", gameRoot, new WidgetArgs()); + + Action ShowLeaveRestartDialog = () => + { + gameRoot.IsVisible = () => false; + Game.LoadWidget(world, "LEAVE_RESTART_WIDGET", Ui.Root, new WidgetArgs()); + }; + world.GameOver += ShowLeaveRestartDialog; } void InitObserverWidgets() { - var observerWidgets = Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs()); - - Widget observerstats = null; - observerstats = Game.LoadWidget(world, "INGAME_OBSERVERSTATS_BG", observerWidgets, new WidgetArgs - { - { "transient", false }, - { "onExit", () => observerstats.Visible = false } - }); - observerstats.Visible = false; - - var statsButton = observerWidgets.Get("OBSERVER_STATS_BUTTON"); - statsButton.OnClick = () => observerstats.Visible ^= true; + Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs()); } enum RadarBinState { Closed, BinAnimating, RadarAnimating, Open }; @@ -95,41 +63,6 @@ namespace OpenRA.Mods.D2k.Widgets.Logic { var playerWidgets = Game.LoadWidget(world, "PLAYER_WIDGETS", playerRoot, new WidgetArgs()); - Widget diplomacy = null; - diplomacy = Game.LoadWidget(world, "INGAME_DIPLOMACY_BG", playerWidgets, new WidgetArgs - { - { "transient", false }, - { "onExit", () => diplomacy.Visible = false } - }); - diplomacy.Visible = false; - - var diplomacyButton = playerWidgets.Get("INGAME_DIPLOMACY_BUTTON"); - diplomacyButton.OnClick = () => diplomacy.Visible ^= true; - var validPlayers = 0; - validPlayers = world.Players.Where(a => a != world.LocalPlayer && !a.NonCombatant).Count(); - diplomacyButton.IsVisible = () => validPlayers > 0; - - Widget cheats = null; - cheats = Game.LoadWidget(world, "INGAME_DEBUG_BG", playerWidgets, new WidgetArgs - { - { "transient", false }, - { "onExit", () => cheats.Visible = false } - }); - cheats.Visible = false; - - var cheatsButton = playerWidgets.Get("INGAME_DEBUG_BUTTON"); - cheatsButton.OnClick = () => cheats.Visible ^= true; - cheatsButton.IsVisible = () => world.LobbyInfo.GlobalSettings.AllowCheats; - - var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); - if (iop != null && iop.ObjectivesPanel != null) - { - var objectivesButton = playerWidgets.Get("OBJECTIVES_BUTTON"); - var objectivesWidget = Game.LoadWidget(world, iop.ObjectivesPanel, playerWidgets, new WidgetArgs()); - objectivesButton.Visible = true; - objectivesButton.OnClick += () => objectivesWidget.Visible ^= true; - } - var radarActive = false; var binState = RadarBinState.Closed; var radarBin = playerWidgets.Get("INGAME_RADAR_BIN"); diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index e0f5c9048e..8e37a578ea 100644 --- a/OpenRA.Mods.RA/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.RA/ConquestVictoryConditions.cs @@ -13,98 +13,82 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class ConquestVictoryConditionsInfo : ITraitInfo + public class ConquestVictoryConditionsInfo : ITraitInfo, Requires { - [Desc("Milliseconds")] + [Desc("Delay for the end game notification in milliseconds.")] public int NotificationDelay = 1500; - public object Create(ActorInitializer init) { return new ConquestVictoryConditions(init.world, this); } + public object Create(ActorInitializer init) { return new ConquestVictoryConditions(init.self, this); } } - public class ConquestVictoryConditions : ITick, IResolveOrder + public class ConquestVictoryConditions : ITick, INotifyObjectivesUpdated { - ConquestVictoryConditionsInfo Info; - public ConquestVictoryConditions(World world, ConquestVictoryConditionsInfo info) + readonly ConquestVictoryConditionsInfo info; + readonly MissionObjectives mo; + int objectiveID = -1; + + public ConquestVictoryConditions(Actor self, ConquestVictoryConditionsInfo cvcInfo) { - world.ObserveAfterWinOrLose = true; - Info = info; + info = cvcInfo; + mo = self.Trait(); } public void Tick(Actor self) { if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; - var hasAnything = self.World.ActorsWithTrait() - .Any(a => a.Actor.Owner == self.Owner); + if (objectiveID < 0) + objectiveID = mo.Add(self.Owner, "Destroy all opposition!"); - if (!hasAnything && !self.Owner.NonCombatant) - Lose(self); + if (!self.Owner.NonCombatant && self.Owner.HasNoRequiredUnits()) + mo.MarkFailed(self.Owner, objectiveID); var others = self.World.Players.Where(p => !p.NonCombatant - && p != self.Owner && p.Stances[self.Owner] != Stance.Ally); + && !p.IsAlliedWith(self.Owner)); if (!others.Any()) return; if (others.All(p => p.WinState == WinState.Lost)) - Win(self); + mo.MarkCompleted(self.Owner, objectiveID); } public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "Surrender") - Lose(self); + mo.MarkFailed(self.Owner, objectiveID); } - public void Lose(Actor self) + public void OnPlayerLost(Player player) { - if (self.Owner.WinState == WinState.Lost) return; - self.Owner.WinState = WinState.Lost; - self.World.OnPlayerWinStateChanged(self.Owner); + Game.Debug("{0} is defeated.".F(player.PlayerName)); - Game.Debug("{0} is defeated.".F(self.Owner.PlayerName)); - - foreach (var a in self.World.Actors.Where(a => a.Owner == self.Owner)) + foreach (var a in player.World.Actors.Where(a => a.Owner == player)) a.Kill(a); - if (self.Owner == self.World.LocalPlayer) + if (player == player.World.LocalPlayer) { - Game.RunAfterDelay(Info.NotificationDelay, () => + Game.RunAfterDelay(info.NotificationDelay, () => { - if (Game.IsCurrentWorld(self.World)) - Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", "Lose", self.Owner.Country.Race); + if (Game.IsCurrentWorld(player.World)) + Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Country.Race); }); } } - public void Win(Actor self) + public void OnPlayerWon(Player player) { - if (self.Owner.WinState == WinState.Won) return; - self.Owner.WinState = WinState.Won; - self.World.OnPlayerWinStateChanged(self.Owner); + Game.Debug("{0} is victorious.".F(player.PlayerName)); - Game.Debug("{0} is victorious.".F(self.Owner.PlayerName)); - - if (self.Owner == self.World.LocalPlayer) - Game.RunAfterDelay(Info.NotificationDelay, () => Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", "Win", self.Owner.Country.Race)); + if (player == player.World.LocalPlayer) + Game.RunAfterDelay(info.NotificationDelay, () => Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Country.Race)); } + + public void OnObjectiveAdded(Player player, int id) {} + public void OnObjectiveCompleted(Player player, int id) {} + public void OnObjectiveFailed(Player player, int id) {} } [Desc("Tag trait for things that must be destroyed for a short game to end.")] public class MustBeDestroyedInfo : TraitInfo { } public class MustBeDestroyed { } - - [Desc("Provides game mode information for players/observers.", - "Goes on WorldActor - observers don't have a player it can live on.")] - public class ConquestObjectivesPanelInfo : ITraitInfo - { - public string ObjectivesPanel = null; - public object Create(ActorInitializer init) { return new ConquestObjectivesPanel(this); } - } - - public class ConquestObjectivesPanel : IObjectivesPanel - { - ConquestObjectivesPanelInfo info; - public ConquestObjectivesPanel(ConquestObjectivesPanelInfo info) { this.info = info; } - public string ObjectivesPanel { get { return info.ObjectivesPanel; } } - } } diff --git a/OpenRA.Mods.RA/MenuPaletteEffect.cs b/OpenRA.Mods.RA/MenuPaletteEffect.cs index feee5ea158..b206fff4fc 100644 --- a/OpenRA.Mods.RA/MenuPaletteEffect.cs +++ b/OpenRA.Mods.RA/MenuPaletteEffect.cs @@ -21,9 +21,12 @@ namespace OpenRA.Mods.RA [Desc("Time (in ticks) to fade between states")] public readonly int FadeLength = 10; - [Desc("Effect style to fade to. Accepts values of None or Desaturated")] + [Desc("Effect style to fade to during gameplay. Accepts values of None or Desaturated.")] public readonly MenuPaletteEffect.EffectType Effect = MenuPaletteEffect.EffectType.None; + [Desc("Effect style to fade to when opening the in-game menu. Accepts values of None, Black or Desaturated.")] + public readonly MenuPaletteEffect.EffectType MenuEffect = MenuPaletteEffect.EffectType.None; + public object Create(ActorInitializer init) { return new MenuPaletteEffect(this); } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 6c4548cde7..85dab4f5b9 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -284,6 +284,7 @@ + @@ -372,6 +373,11 @@ + + + + + @@ -484,6 +490,7 @@ + @@ -551,6 +558,7 @@ + diff --git a/OpenRA.Mods.RA/Player/Extensions.cs b/OpenRA.Mods.RA/Player/Extensions.cs new file mode 100644 index 0000000000..840ef08ec7 --- /dev/null +++ b/OpenRA.Mods.RA/Player/Extensions.cs @@ -0,0 +1,23 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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; + +namespace OpenRA +{ + public static class Extensions + { + public static bool HasNoRequiredUnits(this Player player) + { + return player.World.ActorsWithTrait().All(p => p.Actor.Owner != player); + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Player/MissionObjectives.cs b/OpenRA.Mods.RA/Player/MissionObjectives.cs new file mode 100644 index 0000000000..8c907495eb --- /dev/null +++ b/OpenRA.Mods.RA/Player/MissionObjectives.cs @@ -0,0 +1,229 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public enum ObjectiveType { Primary, Secondary }; + public enum ObjectiveState { Incomplete, Completed, Failed }; + + public class MissionObjective + { + public readonly ObjectiveType Type; + public readonly string Description; + public ObjectiveState State; + + public MissionObjective(ObjectiveType type, string description) + { + Type = type; + Description = description; + State = ObjectiveState.Incomplete; + } + } + + public class MissionObjectivesInfo : ITraitInfo + { + [Desc("Set this to true if multiple cooperative players have a distinct set of " + + "objectives that each of them has to complete to win the game. This is mainly " + + "useful for multiplayer coop missions. Do not use this for skirmish team games.")] + public readonly bool Cooperative = false; + + [Desc("If set to true, this setting causes the game to end immediately once the first " + + "player (or team of cooperative players) fails or completes his objectives. If " + + "set to false, players that fail their objectives will stick around and become observers.")] + public readonly bool EarlyGameOver = false; + + [Desc("Delay between the game over condition being met, and the game actually ending, in milliseconds.")] + public readonly int GameOverDelay = 1500; + + public object Create(ActorInitializer init) { return new MissionObjectives(init.world, this); } + } + + public class MissionObjectives : INotifyObjectivesUpdated, ISync, IResolveOrder + { + readonly MissionObjectivesInfo info; + readonly List objectives = new List(); + public ReadOnlyList Objectives; + + [Sync] + public int ObjectivesHash { get { return Objectives.Aggregate(0, (code, objective) => code ^ Sync.hash(objective.State)); } } + + // This property is used as a flag in 'Cooperative' games to mark that the player has completed all his objectives. + // The player's WinState is only updated when his allies have all completed their objective as well. + public WinState WinStateCooperative { get; private set; } + + public MissionObjectives(World world, MissionObjectivesInfo moInfo) + { + info = moInfo; + Objectives = new ReadOnlyList(objectives); + + world.ObserveAfterWinOrLose = !info.EarlyGameOver; + } + + public int Add(Player player, string description, ObjectiveType type = ObjectiveType.Primary) + { + var newID = objectives.Count; + + objectives.Insert(newID, new MissionObjective(type, description)); + + ObjectiveAdded(player); + foreach (var imo in player.PlayerActor.TraitsImplementing()) + imo.OnObjectiveAdded(player, newID); + + return newID; + } + + public void MarkCompleted(Player player, int objectiveID) + { + if (objectiveID >= objectives.Count || objectives[objectiveID].State == ObjectiveState.Completed) + return; + + objectives[objectiveID].State = ObjectiveState.Completed; + + if (objectives[objectiveID].Type == ObjectiveType.Primary) + { + var playerWon = objectives.Where(o => o.Type == ObjectiveType.Primary).All(o => o.State == ObjectiveState.Completed); + + foreach (var imo in player.PlayerActor.TraitsImplementing()) + { + imo.OnObjectiveCompleted(player, objectiveID); + + if (playerWon) + imo.OnPlayerWon(player); + } + + if (playerWon) + CheckIfGameIsOver(player); + } + } + + public void MarkFailed(Player player, int objectiveID) + { + if (objectiveID >= objectives.Count || objectives[objectiveID].State == ObjectiveState.Failed) + return; + + objectives[objectiveID].State = ObjectiveState.Failed; + + if (objectives[objectiveID].Type == ObjectiveType.Primary) + { + var playerLost = objectives.Where(o => o.Type == ObjectiveType.Primary).Any(o => o.State == ObjectiveState.Failed); + + foreach (var imo in player.PlayerActor.TraitsImplementing()) + { + imo.OnObjectiveFailed(player, objectiveID); + + if (playerLost) + imo.OnPlayerLost(player); + } + + if (playerLost) + CheckIfGameIsOver(player); + } + } + + void CheckIfGameIsOver(Player player) + { + var players = player.World.Players.Where(p => !p.NonCombatant); + var allies = players.Where(p => p.IsAlliedWith(player)); + + var gameOver = ((info.EarlyGameOver && !info.Cooperative && player.WinState != WinState.Undefined) || + (info.EarlyGameOver && info.Cooperative && allies.All(p => p.WinState != WinState.Undefined)) || + players.All(p => p.WinState != WinState.Undefined)); + + if (gameOver) + { + Game.RunAfterDelay(info.GameOverDelay, () => + { + player.World.EndGame(); + player.World.SetPauseState(true); + player.World.PauseStateLocked = true; + }); + } + } + + public void OnPlayerWon(Player player) + { + if (info.Cooperative) + { + WinStateCooperative = WinState.Won; + var players = player.World.Players.Where(p => !p.NonCombatant); + var allies = players.Where(p => p.IsAlliedWith(player)); + + if (allies.All(p => p.PlayerActor.Trait().WinStateCooperative == WinState.Won)) + foreach (var p in allies) + { + p.WinState = WinState.Won; + p.World.OnPlayerWinStateChanged(p); + } + } + else + { + player.WinState = WinState.Won; + player.World.OnPlayerWinStateChanged(player); + } + } + + public void OnPlayerLost(Player player) + { + if (info.Cooperative) + { + WinStateCooperative = WinState.Lost; + var players = player.World.Players.Where(p => !p.NonCombatant); + var allies = players.Where(p => p.IsAlliedWith(player)); + + if (allies.Any(p => p.PlayerActor.Trait().WinStateCooperative == WinState.Lost)) + foreach (var p in allies) + { + p.WinState = WinState.Lost; + p.World.OnPlayerWinStateChanged(p); + } + } + else + { + player.WinState = WinState.Lost; + player.World.OnPlayerWinStateChanged(player); + } + } + + public event Action ObjectiveAdded = player => { }; + + public void OnObjectiveAdded(Player player, int id) {} + public void OnObjectiveCompleted(Player player, int id) {} + public void OnObjectiveFailed(Player player, int id) {} + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Surrender") + for (var id = 0; id < objectives.Count; id++) + MarkFailed(self.Owner, id); + } + } + + [Desc("Provides game mode progress information for players.", + "Goes on WorldActor - observers don't have a player it can live on.", + "Current options for PanelName are 'SKIRMISH_STATS' and 'MISSION_OBJECTIVES'.")] + public class ObjectivesPanelInfo : ITraitInfo + { + public string PanelName = null; + public object Create(ActorInitializer init) { return new ObjectivesPanel(this); } + } + + public class ObjectivesPanel : IObjectivesPanel + { + ObjectivesPanelInfo info; + public ObjectivesPanel(ObjectivesPanelInfo info) { this.info = info; } + public string PanelName { get { return info.PanelName; } } + } +} diff --git a/OpenRA.Mods.RA/Scripting/Global/MediaGlobal.cs b/OpenRA.Mods.RA/Scripting/Global/MediaGlobal.cs index dad0f4e886..463de6f73d 100644 --- a/OpenRA.Mods.RA/Scripting/Global/MediaGlobal.cs +++ b/OpenRA.Mods.RA/Scripting/Global/MediaGlobal.cs @@ -8,14 +8,58 @@ */ #endregion +using System; using System.Drawing; +using Eluant; +using OpenRA.Scripting; namespace OpenRA.Scripting { [ScriptGlobal("Media")] public class MediaGlobal : ScriptGlobal { - public MediaGlobal(ScriptContext context) : base(context) { } + World world; + public MediaGlobal(ScriptContext context) : base(context) + { + world = context.World; + } + [Desc("Play an announcer voice listed in notifications.yaml")] + public void PlaySpeechNotification(Player player, string notification) + { + Sound.PlayNotification(world.Map.Rules, player, "Speech", notification, player != null ? player.Country.Race : null); + } + + [Desc("Play a sound listed in notifications.yaml")] + public void PlaySoundNotification(Player player, string notification) + { + Sound.PlayNotification(world.Map.Rules, player, "Sounds", notification, player != null ? player.Country.Race : null); + } + + Action onComplete; + [Desc("Play a VQA video including the file extension.")] + public void PlayMovieFullscreen(string movie, LuaFunction func = null) + { + if (func != null) + { + var f = func.CopyReference() as LuaFunction; + onComplete = () => + { + try + { + using (f) + f.Call(); + } + catch (LuaException e) + { + context.FatalError(e.Message); + } + }; + } + else + onComplete = () => { }; + + Media.PlayFMVFullscreen(world, movie, onComplete); + } [Desc("Display a text message to the player.")] public void DisplayMessage(string text, string prefix = "Mission") // TODO: expose HSLColor to Lua and add as parameter diff --git a/OpenRA.Mods.RA/Scripting/Global/TriggerGlobal.cs b/OpenRA.Mods.RA/Scripting/Global/TriggerGlobal.cs index 9ed2f74738..a2dca58344 100644 --- a/OpenRA.Mods.RA/Scripting/Global/TriggerGlobal.cs +++ b/OpenRA.Mods.RA/Scripting/Global/TriggerGlobal.cs @@ -56,21 +56,21 @@ namespace OpenRA.Mods.RA.Scripting "The callback function will be called as func(Actor self).")] public void OnIdle(Actor a, LuaFunction func) { - GetScriptTriggers(a).RegisterIdleCallback(func, context); + GetScriptTriggers(a).RegisterCallback(Trigger.OnIdle, func, context); } [Desc("Call a function when the actor is damaged. The callback " + "function will be called as func(Actor self, Actor attacker).")] public void OnDamaged(Actor a, LuaFunction func) { - GetScriptTriggers(a).RegisterDamagedCallback(func, context); + GetScriptTriggers(a).RegisterCallback(Trigger.OnDamaged, func, context); } [Desc("Call a function when the actor is killed. The callback " + "function will be called as func(Actor self, Actor killer).")] public void OnKilled(Actor a, LuaFunction func) { - GetScriptTriggers(a).RegisterKilledCallback(func, context); + GetScriptTriggers(a).RegisterCallback(Trigger.OnKilled, func, context); } [Desc("Call a function when all of the actors in a group are killed. The callback " + @@ -106,7 +106,56 @@ namespace OpenRA.Mods.RA.Scripting "The callback function will be called as func(Actor producer, Actor produced).")] public void OnProduction(Actor a, LuaFunction func) { - GetScriptTriggers(a).RegisterProductionCallback(func, context); + GetScriptTriggers(a).RegisterCallback(Trigger.OnProduction, func, context); + } + + [Desc("Call a function when this player completes all primary objectives. " + + "The callback function will be called as func(Player player).")] + public void OnPlayerWon(Player player, LuaFunction func) + { + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerWon, func, context); + } + + [Desc("Call a function when this player fails any primary objective. " + + "The callback function will be called as func(Player player).")] + public void OnPlayerLost(Player player, LuaFunction func) + { + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerLost, func, context); + } + + [Desc("Call a function when this player is assigned a new objective. " + + "The callback function will be called as func(Player player, int objectiveID).")] + public void OnObjectiveAdded(Player player, LuaFunction func) + { + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveAdded, func, context); + } + + [Desc("Call a function when this player completes an objective " + + "The callback function will be called as func(Player player, int objectiveID).")] + public void OnObjectiveCompleted(Player player, LuaFunction func) + { + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveCompleted, func, context); + } + + [Desc("Call a function when this player fails an objective " + + "The callback function will be called as func(Player player, int objectiveID).")] + public void OnObjectiveFailed(Player player, LuaFunction func) + { + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveFailed, func, context); + } + + [Desc("Removes all triggers from this actor")] + public void ClearAll(Actor a) + { + GetScriptTriggers(a).ClearAll(); + } + + [Desc("Removes the specified trigger from this actor")] + public void Clear(Actor a, string triggerName) + { + var trigger = (Trigger)Enum.Parse(typeof(Trigger), triggerName); + + GetScriptTriggers(a).Clear(trigger); } } } diff --git a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs index 84cf7020fc..fd304d4e83 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs @@ -319,7 +319,7 @@ namespace OpenRA.Mods.RA.Scripting [LuaGlobal] public bool RequiredUnitsAreDestroyed(Player player) { - return world.ActorsWithTrait().All(p => p.Actor.Owner != player); + return player.HasNoRequiredUnits(); } [LuaGlobal] diff --git a/OpenRA.Mods.RA/Scripting/Properties/MissionObjectiveProperties.cs b/OpenRA.Mods.RA/Scripting/Properties/MissionObjectiveProperties.cs new file mode 100644 index 0000000000..b11a6b6af4 --- /dev/null +++ b/OpenRA.Mods.RA/Scripting/Properties/MissionObjectiveProperties.cs @@ -0,0 +1,70 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 OpenRA.Traits; +using OpenRA.Scripting; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Scripting +{ + [ScriptPropertyGroup("MissionObjectives")] + public class MissionObjectiveProperties : ScriptPlayerProperties + { + readonly MissionObjectives mo; + + public MissionObjectiveProperties(Player player) + : base(player) + { + mo = player.PlayerActor.Trait(); + } + + [ScriptActorPropertyActivity] + [Desc("Add a primary mission objective for this player. The function returns the " + + "ID of the newly created objective, so that it can be referred to later.")] + public int AddPrimaryObjective(string description) + { + return mo.Add(player, description, ObjectiveType.Primary); + } + + [ScriptActorPropertyActivity] + [Desc("Add a secondary mission objective for this player. The function returns the " + + "ID of the newly created objective, so that it can be referred to later.")] + public int AddSecondaryObjective(string description) + { + return mo.Add(player, description, ObjectiveType.Secondary); + } + + [ScriptActorPropertyActivity] + [Desc("Mark an objective as completed. This needs the objective ID returned " + + "by AddObjective as argument. When the player has completed all primary " + + "objectives, (s)he has won the game.")] + public void MarkCompletedObjective(int id) + { + mo.MarkCompleted(player, id); + } + + [ScriptActorPropertyActivity] + [Desc("Mark an objective as failed. This needs the objective ID returned " + + "by AddObjective as argument. Secondary objectives do not have any " + + "influence whatsoever on the outcome of the game.")] + public void MarkFailedObjective(int id) + { + mo.MarkFailed(player, id); + } + + [ScriptActorPropertyActivity] + [Desc("Returns true if 'player' has lost all units/actors that have the 'MustBeDestroyed' trait.")] + public bool HasNoRequiredUnits() + { + return player.HasNoRequiredUnits(); + } + } +} diff --git a/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs b/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs index d68e9c2112..9c2a8e597b 100644 --- a/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs +++ b/OpenRA.Mods.RA/Scripting/ScriptTriggers.cs @@ -18,41 +18,31 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Scripting { + public enum Trigger { OnIdle, OnDamaged, OnKilled, OnProduction, OnPlayerWon, OnPlayerLost, OnObjectiveAdded, OnObjectiveCompleted, OnObjectiveFailed }; + [Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")] public class ScriptTriggersInfo : TraitInfo { } - public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, IDisposable + public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyObjectivesUpdated, IDisposable { public event Action OnKilledInternal = _ => {}; - List> onIdle = new List>(); - List> onDamaged = new List>(); - List> onKilled = new List>(); - List> onProduction = new List>(); + public Dictionary>> Triggers = new Dictionary>>(); - public void RegisterIdleCallback(LuaFunction func, ScriptContext context) + public ScriptTriggers() { - onIdle.Add(Pair.New((LuaFunction)func.CopyReference(), context)); + foreach (var t in Enum.GetValues(typeof(Trigger)).Cast()) + Triggers.Add(t, new List>()); } - public void RegisterDamagedCallback(LuaFunction func, ScriptContext context) + public void RegisterCallback(Trigger trigger, LuaFunction func, ScriptContext context) { - onDamaged.Add(Pair.New((LuaFunction)func.CopyReference(), context)); - } - - public void RegisterKilledCallback(LuaFunction func, ScriptContext context) - { - onKilled.Add(Pair.New((LuaFunction)func.CopyReference(), context)); - } - - public void RegisterProductionCallback(LuaFunction func, ScriptContext context) - { - onProduction.Add(Pair.New((LuaFunction)func.CopyReference(), context)); + Triggers[trigger].Add(Pair.New((LuaFunction)func.CopyReference(), context)); } public void TickIdle(Actor self) { - foreach (var f in onIdle) + foreach (var f in Triggers[Trigger.OnIdle]) { var a = self.ToLuaValue(f.Second); f.First.Call(a).Dispose(); @@ -62,7 +52,7 @@ namespace OpenRA.Mods.RA.Scripting public void Damaged(Actor self, AttackInfo e) { - foreach (var f in onDamaged) + foreach (var f in Triggers[Trigger.OnDamaged]) { var a = self.ToLuaValue(f.Second); var b = e.Attacker.ToLuaValue(f.Second); @@ -75,7 +65,7 @@ namespace OpenRA.Mods.RA.Scripting public void Killed(Actor self, AttackInfo e) { // Run lua callbacks - foreach (var f in onKilled) + foreach (var f in Triggers[Trigger.OnKilled]) { var a = self.ToLuaValue(f.Second); var b = e.Attacker.ToLuaValue(f.Second); @@ -90,7 +80,7 @@ namespace OpenRA.Mods.RA.Scripting public void UnitProduced(Actor self, Actor other, CPos exit) { - foreach (var f in onProduction) + foreach (var f in Triggers[Trigger.OnProduction]) { var a = self.ToLuaValue(f.Second); var b = other.ToLuaValue(f.Second); @@ -100,9 +90,76 @@ namespace OpenRA.Mods.RA.Scripting } } + public void OnPlayerWon(Player player) + { + foreach (var f in Triggers[Trigger.OnPlayerWon]) + { + var a = player.ToLuaValue(f.Second); + f.First.Call(a).Dispose(); + a.Dispose(); + } + } + + public void OnPlayerLost(Player player) + { + foreach (var f in Triggers[Trigger.OnPlayerLost]) + { + var a = player.ToLuaValue(f.Second); + f.First.Call(a).Dispose(); + a.Dispose(); + } + } + + public void OnObjectiveAdded(Player player, int id) + { + foreach (var f in Triggers[Trigger.OnObjectiveAdded]) + { + var a = player.ToLuaValue(f.Second); + var b = id.ToLuaValue(f.Second); + f.First.Call(a, b).Dispose(); + a.Dispose(); + b.Dispose(); + } + } + + public void OnObjectiveCompleted(Player player, int id) + { + foreach (var f in Triggers[Trigger.OnObjectiveCompleted]) + { + var a = player.ToLuaValue(f.Second); + var b = id.ToLuaValue(f.Second); + f.First.Call(a, b).Dispose(); + a.Dispose(); + b.Dispose(); + } + } + + public void OnObjectiveFailed(Player player, int id) + { + foreach (var f in Triggers[Trigger.OnObjectiveFailed]) + { + var a = player.ToLuaValue(f.Second); + var b = id.ToLuaValue(f.Second); + f.First.Call(a, b).Dispose(); + a.Dispose(); + b.Dispose(); + } + } + + public void Clear(Trigger trigger) + { + Triggers[trigger].Clear(); + } + + public void ClearAll() + { + foreach (var trigger in Triggers) + trigger.Value.Clear(); + } + public void Dispose() { - var pairs = new[] { onIdle, onDamaged, onKilled, onProduction }; + var pairs = Triggers.Values; pairs.SelectMany(l => l).Select(p => p.First).Do(f => f.Dispose()); pairs.Do(l => l.Clear()); } diff --git a/OpenRA.Mods.RA/StrategicVictoryConditions.cs b/OpenRA.Mods.RA/StrategicVictoryConditions.cs index 86c1344741..9e079990bb 100644 --- a/OpenRA.Mods.RA/StrategicVictoryConditions.cs +++ b/OpenRA.Mods.RA/StrategicVictoryConditions.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -17,41 +17,68 @@ namespace OpenRA.Mods.RA public class StrategicPointInfo : TraitInfo {} public class StrategicPoint {} - public class StrategicVictoryConditionsInfo : ITraitInfo, Requires + public class StrategicVictoryConditionsInfo : ITraitInfo, Requires { + [Desc("Amount of time (in game ticks) that the player has to hold all the strategic points.")] public readonly int TicksToHold = 25 * 60 * 5; // ~5 minutes + + [Desc("Should the timer reset when the player loses hold of a strategic point.")] public readonly bool ResetOnHoldLost = true; + + [Desc("Percentage of strategic points the player has to hold to win.")] public readonly float RatioRequired = 0.5f; // 50% required of all koth locations + [Desc("Delay for the end game notification in milliseconds.")] + public int NotificationDelay = 1500; + public object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.self, this); } } - public class StrategicVictoryConditions : ITick, ISync + public class StrategicVictoryConditions : ITick, ISync, INotifyObjectivesUpdated { - Actor self; - StrategicVictoryConditionsInfo info; + readonly StrategicVictoryConditionsInfo info; - [Sync] public int TicksLeft = 0; + [Sync] public int TicksLeft; + readonly Player player; + readonly MissionObjectives mo; + int objectiveID = -1; - public StrategicVictoryConditions(Actor self, StrategicVictoryConditionsInfo info) + public StrategicVictoryConditions(Actor self, StrategicVictoryConditionsInfo svcInfo) { - this.self = self; - this.info = info; + info = svcInfo; + TicksLeft = info.TicksToHold; + player = self.Owner; + mo = self.Trait(); } public IEnumerable> AllPoints { - get { return self.World.ActorsWithTrait(); } + get { return player.World.ActorsWithTrait(); } } public int Total { get { return AllPoints.Count(); } } - int Owned { get { return AllPoints.Count( a => WorldUtils.AreMutualAllies( self.Owner, a.Actor.Owner )); } } + int Owned { get { return AllPoints.Count(a => WorldUtils.AreMutualAllies(player, a.Actor.Owner)); } } public bool Holding { get { return Owned >= info.RatioRequired * Total; } } public void Tick(Actor self) { - if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; + if (player.WinState != WinState.Undefined || player.NonCombatant) return; + + if (objectiveID < 0) + objectiveID = mo.Add(player, "Hold all the strategic positions for a specified time!"); + + if (!self.Owner.NonCombatant && self.Owner.HasNoRequiredUnits()) + mo.MarkFailed(self.Owner, objectiveID); + + var others = self.World.Players.Where(p => !p.NonCombatant + && !p.IsAlliedWith(self.Owner)); + + if (others.All(p => p.WinState == WinState.Lost)) + mo.MarkCompleted(player, objectiveID); + + if (others.Any(p => p.WinState == WinState.Won)) + mo.MarkFailed(player, objectiveID); // See if any of the conditions are met to increase the count if (Total > 0) @@ -59,10 +86,8 @@ namespace OpenRA.Mods.RA if (Holding) { // Hah! We met ths critical owned condition - if (TicksLeft == 0) - TicksLeft = info.TicksToHold; // first tick -- this is crap. - else if (--TicksLeft == 0) - Won(); + if (--TicksLeft == 0) + mo.MarkCompleted(player, objectiveID); } else if (TicksLeft != 0) if (info.ResetOnHoldLost) @@ -70,18 +95,33 @@ namespace OpenRA.Mods.RA } } - void Won() + public void OnPlayerLost(Player player) { - // Player has won - foreach (var p in self.World.Players) - { - var cvc = p.PlayerActor.Trait(); + Game.Debug("{0} is defeated.".F(player.PlayerName)); - if (p.WinState == WinState.Undefined && WorldUtils.AreMutualAllies(self.Owner, p)) - cvc.Win(p.PlayerActor); - else if (p.WinState == WinState.Undefined) - cvc.Lose(p.PlayerActor); + foreach (var a in player.World.Actors.Where(a => a.Owner == player)) + a.Kill(a); + + if (player == player.World.LocalPlayer) + { + Game.RunAfterDelay(info.NotificationDelay, () => + { + if (Game.IsCurrentWorld(player.World)) + Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Country.Race); + }); } } + + public void OnPlayerWon(Player player) + { + Game.Debug("{0} is victorious.".F(player.PlayerName)); + + if (player == player.World.LocalPlayer) + Game.RunAfterDelay(info.NotificationDelay, () => Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Country.Race)); + } + + public void OnObjectiveAdded(Player player, int id) {} + public void OnObjectiveCompleted(Player player, int id) {} + public void OnObjectiveFailed(Player player, int id) {} } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/DebugMenuLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/DebugMenuLogic.cs index e1f27035f7..8b56cef6a3 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/DebugMenuLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/DebugMenuLogic.cs @@ -18,7 +18,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic public class DebugMenuLogic { [ObjectCreator.UseCtor] - public DebugMenuLogic(Widget widget, Action onExit, World world, bool transient) + public DebugMenuLogic(Widget widget, World world) { var devTrait = world.LocalPlayer.PlayerActor.Trait(); @@ -112,21 +112,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic showAstarCostCheckbox.IsChecked = () => dbgOverlay != null ? dbgOverlay.Visible : false; showAstarCostCheckbox.OnClick = () => { if (dbgOverlay != null) dbgOverlay.Visible ^= true; }; } - - var close = widget.GetOrNull("CLOSE"); - if (close != null) - { - close.OnClick = () => - { - if (transient) - { - Ui.CloseWindow(); - Ui.Root.RemoveChild(widget); - } - - onExit(); - }; - } } public void Order(World world, string order) diff --git a/OpenRA.Mods.RA/Widgets/Logic/DiplomacyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/DiplomacyLogic.cs index 6a3d822f15..4f2301ac32 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/DiplomacyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/DiplomacyLogic.cs @@ -23,7 +23,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic ScrollPanelWidget diplomacyPanel; [ObjectCreator.UseCtor] - public DiplomacyLogic(Widget widget, Action onExit, World world, bool transient) + public DiplomacyLogic(Widget widget, Action onExit, World world) { this.world = world; @@ -33,18 +33,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic var close = widget.GetOrNull("CLOSE"); if (close != null) - { close.OnClick = () => { - if (transient) - { - Ui.CloseWindow(); - Ui.Root.RemoveChild(widget); - } - + Ui.CloseWindow(); + Ui.Root.RemoveChild(widget); onExit(); }; - } } void LayoutPlayers() diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoBriefingLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoBriefingLogic.cs new file mode 100644 index 0000000000..32114e4d59 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoBriefingLogic.cs @@ -0,0 +1,38 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Linq; +using OpenRA.Widgets; +using OpenRA.Traits; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Widgets.Logic +{ + class GameInfoBriefingLogic + { + [ObjectCreator.UseCtor] + public GameInfoBriefingLogic(Widget widget, World world) + { + var previewWidget = widget.Get("MAP_PREVIEW"); + previewWidget.Preview = () => Game.modData.MapCache[world.Map.Uid]; + + var mapDescriptionPanel = widget.Get("MAP_DESCRIPTION_PANEL"); + var mapDescription = widget.Get("MAP_DESCRIPTION"); + var mapFont = Game.Renderer.Fonts[mapDescription.Font]; + var text = world.Map.Description != null ? world.Map.Description.Replace("\\n", "\n") : ""; + text = WidgetUtils.WrapText(text, mapDescription.Bounds.Width, mapFont); + mapDescription.Text = text; + mapDescription.Bounds.Height = mapFont.Measure(text).Y; + mapDescriptionPanel.ScrollToTop(); + mapDescriptionPanel.Layout.AdjustChildren(); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoLogic.cs new file mode 100644 index 0000000000..23b5dc9541 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoLogic.cs @@ -0,0 +1,109 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Linq; +using OpenRA.Widgets; +using OpenRA.Traits; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Widgets.Logic +{ + public enum IngameInfoPanel { AutoSelect, Map, Objectives, Debug }; + + class GameInfoLogic + { + [ObjectCreator.UseCtor] + public GameInfoLogic(Widget widget, World world, IngameInfoPanel activePanel) + { + var lp = world.LocalPlayer; + var numTabs = 0; + + widget.IsVisible = () => activePanel != IngameInfoPanel.AutoSelect; + + // Objectives/Stats tab + var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); + if (lp != null && iop != null && iop.PanelName != null) + { + numTabs++; + var objectivesTabButton = widget.Get(string.Concat("BUTTON", numTabs.ToString())); + objectivesTabButton.GetText = () => "Objectives"; + objectivesTabButton.IsVisible = () => lp != null && numTabs > 1; + objectivesTabButton.OnClick = () => activePanel = IngameInfoPanel.Objectives; + objectivesTabButton.IsHighlighted = () => activePanel == IngameInfoPanel.Objectives; + + var objectivesPanel = widget.Get("OBJECTIVES_PANEL"); + objectivesPanel.IsVisible = () => activePanel == IngameInfoPanel.Objectives; + + Game.LoadWidget(world, iop.PanelName, objectivesPanel, new WidgetArgs()); + + if (activePanel == IngameInfoPanel.AutoSelect) + activePanel = IngameInfoPanel.Objectives; + } + + // Briefing tab + if (world.Map.CustomPreview != null) + { + numTabs++; + var mapTabButton = widget.Get(string.Concat("BUTTON", numTabs.ToString())); + mapTabButton.Text = "Briefing"; + mapTabButton.IsVisible = () => numTabs > 1; + mapTabButton.OnClick = () => activePanel = IngameInfoPanel.Map; + mapTabButton.IsHighlighted = () => activePanel == IngameInfoPanel.Map; + + var mapPanel = widget.Get("MAP_PANEL"); + mapPanel.IsVisible = () => activePanel == IngameInfoPanel.Map; + + Game.LoadWidget(world, "MAP_PANEL", mapPanel, new WidgetArgs()); + + if (activePanel == IngameInfoPanel.AutoSelect) + activePanel = IngameInfoPanel.Map; + } + + // Debug/Cheats tab + if (lp != null && world.LobbyInfo.GlobalSettings.AllowCheats) + { + numTabs++; + var debugTabButton = widget.Get(string.Concat("BUTTON", numTabs.ToString())); + debugTabButton.Text = "Debug"; + debugTabButton.IsVisible = () => lp != null && world.LobbyInfo.GlobalSettings.AllowCheats && numTabs > 1; + debugTabButton.OnClick = () => activePanel = IngameInfoPanel.Debug; + debugTabButton.IsHighlighted = () => activePanel == IngameInfoPanel.Debug; + + var debugPanelContainer = widget.Get("DEBUG_PANEL"); + debugPanelContainer.IsVisible = () => activePanel == IngameInfoPanel.Debug; + + Game.LoadWidget(world, "DEBUG_PANEL", debugPanelContainer, new WidgetArgs()); + + if (activePanel == IngameInfoPanel.AutoSelect) + activePanel = IngameInfoPanel.Debug; + } + + // Handle empty space when tabs aren't displayed + var titleText = widget.Get("TITLE"); + var titleTextNoTabs = widget.GetOrNull("TITLE_NO_TABS"); + + titleText.IsVisible = () => numTabs > 1 || (numTabs == 1 && titleTextNoTabs == null); + titleText.GetText = () => string.Concat(world.Map.Type, ": ", world.Map.Title); + if (titleTextNoTabs != null) + { + titleTextNoTabs.IsVisible = () => numTabs == 1; + titleTextNoTabs.GetText = () => string.Concat(world.Map.Type, ": ", world.Map.Title); + } + + var bg = widget.Get("BACKGROUND"); + var bgNoTabs = widget.GetOrNull("BACKGROUND_NO_TABS"); + + bg.IsVisible = () => numTabs > 1 || (numTabs == 1 && bgNoTabs == null); + if (bgNoTabs != null) + bgNoTabs.IsVisible = () => numTabs == 1; + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoObjectivesLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoObjectivesLogic.cs new file mode 100644 index 0000000000..b167a47f60 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoObjectivesLogic.cs @@ -0,0 +1,72 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Linq; +using System.Drawing; +using OpenRA.Widgets; +using OpenRA.Traits; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Widgets.Logic +{ + class GameInfoObjectivesLogic + { + ContainerWidget template; + + [ObjectCreator.UseCtor] + public GameInfoObjectivesLogic(Widget widget, World world) + { + var lp = world.LocalPlayer; + + var missionStatus = widget.Get("MISSION_STATUS"); + missionStatus.GetText = () => lp.WinState == WinState.Undefined ? "In progress" : + lp.WinState == WinState.Won ? "Accomplished" : "Failed"; + missionStatus.GetColor = () => lp.WinState == WinState.Undefined ? Color.White : + lp.WinState == WinState.Won ? Color.LimeGreen : Color.Red; + + var mo = lp.PlayerActor.TraitOrDefault(); + if (mo == null) + return; + + var objectivesPanel = widget.Get("OBJECTIVES_PANEL"); + template = objectivesPanel.Get("OBJECTIVE_TEMPLATE"); + + PopulateObjectivesList(mo, objectivesPanel, template); + + Action RedrawObjectives = player => + { + if (player == lp) + PopulateObjectivesList(mo, objectivesPanel, template); + }; + mo.ObjectiveAdded += RedrawObjectives; + } + + void PopulateObjectivesList(MissionObjectives mo, ScrollPanelWidget parent, ContainerWidget template) + { + parent.RemoveChildren(); + + foreach (var objective in mo.Objectives.OrderBy(o => o.Type)) + { + var widget = template.Clone(); + + var label = widget.Get("OBJECTIVE_TYPE"); + label.GetText = () => objective.Type == ObjectiveType.Primary ? "Primary" : "Secondary"; + + var checkbox = widget.Get("OBJECTIVE_STATUS"); + checkbox.IsChecked = () => objective.State != ObjectiveState.Incomplete; + checkbox.GetCheckType = () => objective.State == ObjectiveState.Completed ? "checked" : "crossed"; + checkbox.GetText = () => objective.Description; + + parent.AddChild(widget); + } + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncConquestObjectivesLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoStatsLogic.cs similarity index 53% rename from OpenRA.Mods.Cnc/Widgets/Logic/CncConquestObjectivesLogic.cs rename to OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoStatsLogic.cs index 9e7e2df3e7..0b56ef02d4 100644 --- a/OpenRA.Mods.Cnc/Widgets/Logic/CncConquestObjectivesLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/GameInfoStatsLogic.cs @@ -1,6 +1,6 @@ -#region Copyright & License Information +#region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -8,46 +8,42 @@ */ #endregion +using System; using System.Drawing; using System.Linq; -using OpenRA.Mods.RA; using OpenRA.Widgets; +using OpenRA.Traits; +using OpenRA.Mods.RA; -namespace OpenRA.Mods.Cnc.Widgets.Logic +namespace OpenRA.Mods.RA.Widgets.Logic { - public class CncConquestObjectivesLogic + class GameInfoStatsLogic { [ObjectCreator.UseCtor] - public CncConquestObjectivesLogic(Widget widget, World world) + public GameInfoStatsLogic(Widget widget, World world) { - var panel = widget.Get("CONQUEST_OBJECTIVES"); - panel.Get("TITLE").GetText = () => "Conquest: " + world.Map.Title; + var lp = world.LocalPlayer; - var statusLabel = panel.Get("STATUS"); - statusLabel.IsVisible = () => world.LocalPlayer != null; + var checkbox = widget.Get("STATS_CHECKBOX"); + checkbox.IsChecked = () => lp.WinState != WinState.Undefined; + checkbox.GetCheckType = () => lp.WinState == WinState.Won ? + "checked" : "crossed"; - if (world.LocalPlayer != null) - { - var lp = world.LocalPlayer; - var objectiveCheckbox = panel.Get("1"); - objectiveCheckbox.IsChecked = () => lp.WinState != WinState.Undefined; - objectiveCheckbox.GetCheckType = () => lp.WinState == WinState.Won ? - "checked" : "crossed"; + var statusLabel = widget.Get("STATS_STATUS"); - statusLabel.GetText = () => lp.WinState == WinState.Won ? "Complete" : - lp.WinState == WinState.Lost ? "Failed" : "Incomplete"; - statusLabel.GetColor = () => lp.WinState == WinState.Won ? Color.Green : - lp.WinState == WinState.Lost ? Color.Red : Color.White; - } + statusLabel.GetText = () => lp.WinState == WinState.Won ? "Accomplished" : + lp.WinState == WinState.Lost ? "Failed" : "In progress"; + statusLabel.GetColor = () => lp.WinState == WinState.Won ? Color.LimeGreen : + lp.WinState == WinState.Lost ? Color.Red : Color.White; - var scrollpanel = panel.Get("PLAYER_LIST"); - var itemTemplate = scrollpanel.Get("PLAYER_TEMPLATE"); - scrollpanel.RemoveChildren(); + var playerPanel = widget.Get("PLAYER_LIST"); + var playerTemplate = playerPanel.Get("PLAYER_TEMPLATE"); + playerPanel.RemoveChildren(); foreach (var p in world.Players.Where(a => !a.NonCombatant)) { var pp = p; - var item = itemTemplate.Clone(); + var item = playerTemplate.Clone(); var nameLabel = item.Get("NAME"); nameLabel.GetText = () => pp.WinState == WinState.Lost ? pp.PlayerName + " (Dead)" : pp.PlayerName; nameLabel.GetColor = () => pp.Color.RGB; @@ -61,7 +57,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic var client = world.LobbyInfo.ClientWithIndex(pp.ClientIndex); var teamNumber = (client == null) ? 0 : client.Team; team.GetText = () => (teamNumber == 0) ? "-" : teamNumber.ToString(); - scrollpanel.AddChild(item); + playerPanel.AddChild(item); var stats = pp.PlayerActor.TraitOrDefault(); if (stats == null) diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/LeaveMapLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/LeaveMapLogic.cs new file mode 100644 index 0000000000..f8f1405e54 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/LeaveMapLogic.cs @@ -0,0 +1,70 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Network; +using OpenRA.Traits; +using OpenRA.Widgets; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Widgets +{ + class LeaveMapLogic + { + [ObjectCreator.UseCtor] + public LeaveMapLogic(Widget widget, OrderManager orderManager, World world) + { + widget.Get("VERSION_LABEL").Text = Game.modData.Manifest.Mod.Version; + + var panelName = "LEAVE_RESTART_SIMPLE"; + + var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); + var showObjectives = iop != null && iop.PanelName != null && world.LocalPlayer != null; + + if (showObjectives) + panelName = "LEAVE_RESTART_FULL"; + + var dialog = widget.Get(panelName); + var fmvPlayer = Ui.Root.GetOrNull("FMVPLAYER"); + dialog.IsVisible = () => true; + widget.IsVisible = () => fmvPlayer == null || fmvPlayer != Ui.CurrentWindow(); + + var leaveButton = dialog.Get("LEAVE_BUTTON"); + leaveButton.OnClick = () => + { + leaveButton.Disabled = true; + var mpe = world.WorldActor.TraitOrDefault(); + + Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", + world.LocalPlayer == null ? null : world.LocalPlayer.Country.Race); + + var exitDelay = 1200; + if (mpe != null) + { + Game.RunAfterDelay(exitDelay, () => mpe.Fade(MenuPaletteEffect.EffectType.Black)); + exitDelay += 40 * mpe.Info.FadeLength; + } + + Game.RunAfterDelay(exitDelay, () => + { + Game.Disconnect(); + Ui.ResetAll(); + Game.LoadShellMap(); + }); + }; + + if (showObjectives) + { + var objectivesContainer = dialog.Get("OBJECTIVES"); + Game.LoadWidget(world, iop.PanelName, objectivesContainer, new WidgetArgs()); + } + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs b/OpenRA.Mods.RA/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs index 201007bd86..91e1f7c60a 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Logic @@ -26,6 +27,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic Game.LoadWidget(world, "PLAYER_WIDGETS", playerRoot, new WidgetArgs()); Game.LoadWidget(world, "CHAT_PANEL", ingameRoot, new WidgetArgs()); + + Action ShowLeaveRestartDialog = () => + { + ingameRoot.IsVisible = () => false; + Game.LoadWidget(world, "LEAVE_RESTART_WIDGET", Ui.Root, new WidgetArgs()); + }; + world.GameOver += ShowLeaveRestartDialog; } } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs index 2dd149f74d..eff7114022 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2014 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -9,19 +9,34 @@ #endregion using System; +using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.RA; +using OpenRA.Mods.RA.Widgets; +using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Logic { - class IngameMenuLogic + public class IngameMenuLogic { + Widget menu; + [ObjectCreator.UseCtor] - public IngameMenuLogic(Widget widget, World world, Action onExit, WorldRenderer worldRenderer, bool transient) + public IngameMenuLogic(Widget widget, World world, Action onExit, WorldRenderer worldRenderer, IngameInfoPanel activePanel) { var resumeDisabled = false; + menu = widget.Get("INGAME_MENU"); var mpe = world.WorldActor.TraitOrDefault(); + if (mpe != null) + mpe.Fade(mpe.Info.MenuEffect); + menu.Get("VERSION_LABEL").Text = Game.modData.Manifest.Mod.Version; + + var hideMenu = false; + menu.Get("MENU_BUTTONS").IsVisible = () => !hideMenu; + + // TODO: Create a mechanism to do things like this cleaner. Also needed for scripted missions Action onQuit = () => { Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", world.LocalPlayer == null ? null : world.LocalPlayer.Country.Race); @@ -33,7 +48,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic Game.RunAfterDelay(exitDelay, () => mpe.Fade(MenuPaletteEffect.EffectType.Black)); exitDelay += 40 * mpe.Info.FadeLength; } - Game.RunAfterDelay(exitDelay, () => { Game.Disconnect(); @@ -42,62 +56,69 @@ namespace OpenRA.Mods.RA.Widgets.Logic }); }; - Action onSurrender = () => + Action closeMenu = () => { - world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor, false)); + Ui.CloseWindow(); + Ui.Root.RemoveChild(menu); + if (mpe != null) + mpe.Fade(MenuPaletteEffect.EffectType.None); onExit(); }; - widget.Get("DISCONNECT").OnClick = () => + Action showMenu = () => hideMenu = false; + + menu.Get("ABORT_MISSION").OnClick = () => { - widget.Visible = false; - ConfirmationDialogs.PromptConfirmAction("Abort Mission", "Leave this game and return to the menu?", onQuit, () => widget.Visible = true); + hideMenu = true; + ConfirmationDialogs.PromptConfirmAction("Abort Mission", "Leave this game and return to the menu?", onQuit, showMenu); }; - widget.Get("SETTINGS").OnClick = () => + Action onSurrender = () => { - widget.Visible = false; - Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs() - { - { "onExit", () => widget.Visible = true }, - { "worldRenderer", worldRenderer }, - }); + world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor, false)); + closeMenu(); }; - - widget.Get("MUSIC").OnClick = () => + var surrenderButton = menu.Get("SURRENDER"); + surrenderButton.IsDisabled = () => (world.LocalPlayer == null || world.LocalPlayer.WinState != WinState.Undefined); + surrenderButton.OnClick = () => { - widget.Visible = false; - Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs + hideMenu = true; + ConfirmationDialogs.PromptConfirmAction("Surrender", "Are you sure you want to surrender?", onSurrender, showMenu); + }; + surrenderButton.IsDisabled = () => world.LocalPlayer == null || world.LocalPlayer.WinState != WinState.Undefined; + + menu.Get("MUSIC").OnClick = () => + { + hideMenu = true; + Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs() { - { "onExit", () => { widget.Visible = true; } }, + { "onExit", () => hideMenu = false }, { "world", world } }); }; - var resumeButton = widget.Get("RESUME"); - resumeButton.IsDisabled = () => resumeDisabled; - resumeButton.OnClick = () => + var settingsButton = widget.Get("SETTINGS"); + settingsButton.OnClick = () => { - if (transient) + hideMenu = true; + Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs() { - Ui.CloseWindow(); - Ui.Root.RemoveChild(widget); - } - - onExit(); + { "world", world }, + { "worldRenderer", worldRenderer }, + { "onExit", () => hideMenu = false }, + }); }; - widget.Get("SURRENDER").OnClick = () => + var resumeButton = menu.Get("RESUME"); + resumeButton.IsDisabled = () => resumeDisabled; + resumeButton.OnClick = closeMenu; + + // Game info panel + var gameInfoPanel = Game.LoadWidget(world, "GAME_INFO_PANEL", menu, new WidgetArgs() { - widget.Visible = false; - ConfirmationDialogs.PromptConfirmAction( - "Surrender", - "Are you sure you want to surrender?", - onSurrender, - () => widget.Visible = true, - "Surrender"); - }; - widget.Get("SURRENDER").IsVisible = () => world.LocalPlayer != null && world.LocalPlayer.WinState == WinState.Undefined; + { "activePanel", activePanel } + }); + gameInfoPanel.IsVisible = () => !hideMenu; } } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs index a24b302d21..4d30629241 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic WorldRenderer worldRenderer; [ObjectCreator.UseCtor] - public ObserverStatsLogic(World world, WorldRenderer worldRenderer, Widget widget, Action onExit, bool transient) + public ObserverStatsLogic(World world, WorldRenderer worldRenderer, Widget widget, Action onExit) { this.world = world; this.worldRenderer = worldRenderer; @@ -139,18 +139,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic var close = widget.GetOrNull("CLOSE"); if (close != null) - { close.OnClick = () => { - if (transient) - { - Ui.CloseWindow(); - Ui.Root.RemoveChild(widget); - } - + Ui.CloseWindow(); + Ui.Root.RemoveChild(widget); onExit(); }; - } } void ClearStats() diff --git a/OpenRA.Mods.RA/Widgets/Logic/OrderButtonsChromeLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/OrderButtonsChromeLogic.cs index 3bb5bda0ed..2b5a826f0a 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/OrderButtonsChromeLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/OrderButtonsChromeLogic.cs @@ -8,9 +8,11 @@ */ #endregion +using System; using System.Linq; using OpenRA.Mods.RA.Orders; using OpenRA.Widgets; +using OpenRA.Traits; namespace OpenRA.Mods.RA.Widgets.Logic { @@ -59,8 +61,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic var options = widget.GetOrNull("OPTIONS_BUTTON"); if (options != null) { + var blinking = false; + var lp = world.LocalPlayer; options.IsDisabled = () => disableSystemButtons; - options.OnClick = () => OpenMenuPanel(options); + options.OnClick = () => + { + blinking = false; + OpenMenuPanel(options, new WidgetArgs() + { + { "activePanel", IngameInfoPanel.AutoSelect } + }); + }; + options.IsHighlighted = () => blinking && Game.LocalTick % 50 < 25; + + if (lp != null) + { + Action StartBlinking = player => + { + if (player == world.LocalPlayer) + blinking = true; + }; + + var mo = lp.PlayerActor.TraitOrDefault(); + + if (mo != null) + mo.ObjectiveAdded += StartBlinking; + } } var diplomacy = widget.GetOrNull("DIPLOMACY_BUTTON"); @@ -76,7 +102,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic { debug.IsVisible = () => world.LobbyInfo.GlobalSettings.AllowCheats; debug.IsDisabled = () => disableSystemButtons; - debug.OnClick = () => OpenMenuPanel(debug); + debug.OnClick = () => OpenMenuPanel(debug, new WidgetArgs() + { + { "activePanel", IngameInfoPanel.Debug } + }); } var stats = widget.GetOrNull("OBSERVER_STATS_BUTTON"); @@ -87,7 +116,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic } } - void OpenMenuPanel(MenuButtonWidget button) + void OpenMenuPanel(MenuButtonWidget button, WidgetArgs widgetArgs = null) { disableSystemButtons = true; var cachedPause = world.PredictedPaused; @@ -98,21 +127,19 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (button.Pause && world.LobbyInfo.IsSinglePlayer) world.SetPauseState(true); - Game.LoadWidget(world, button.MenuContainer, Ui.Root, new WidgetArgs() + widgetArgs = widgetArgs ?? new WidgetArgs(); + widgetArgs.Add("onExit", () => { - { "transient", true }, - { "onExit", () => - { - if (button.HideIngameUI) - ingameRoot.IsVisible = () => true; + if (button.HideIngameUI) + ingameRoot.IsVisible = () => true; - if (button.Pause && world.LobbyInfo.IsSinglePlayer) - world.SetPauseState(cachedPause); + if (button.Pause && world.LobbyInfo.IsSinglePlayer) + world.SetPauseState(cachedPause); - disableSystemButtons = false; - } - } + disableSystemButtons = false; }); + + Game.LoadWidget(world, button.MenuContainer, Ui.Root, widgetArgs); } static void BindOrderButton(World world, ButtonWidget w, string icon) diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index 12d943e97b..c8b6a556e2 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -364,6 +364,22 @@ namespace OpenRA.Utility } } + if (engineVersion < 20140806) + { + // remove ConquestVictoryConditions when StrategicVictoryConditions is set + if (depth == 0 && node.Key == "Player" && node.Value.Nodes.Any(n => n.Key == "StrategicVictoryConditions")) + node.Value.Nodes.Add(new MiniYamlNode("-ConquestVictoryConditions", "")); + + // the objectives panel trait and its properties have been renamed + if (depth == 1 && node.Key == "ConquestObjectivesPanel") + { + node.Key = "ObjectivesPanel"; + node.Value.Nodes.RemoveAll(_ => true); + node.Value.Nodes.Add(new MiniYamlNode("PanelName", new MiniYaml("SKIRMISH_STATS"))); + } + + } + // Veterancy was changed to use the upgrades system if (engineVersion < 20140807) { diff --git a/mods/cnc/chrome/ingame-debug.yaml b/mods/cnc/chrome/ingame-debug.yaml index d7db534ff5..148e0ec559 100644 --- a/mods/cnc/chrome/ingame-debug.yaml +++ b/mods/cnc/chrome/ingame-debug.yaml @@ -3,122 +3,110 @@ Container@DEBUG_PANEL: Width: PARENT_RIGHT Height: PARENT_BOTTOM Children: - Label@TITLE: - Width: PARENT_RIGHT - Y: 0-25 - Font: BigBold - Contrast: true + Label@CHEATS_TITLE: + Y: 25 + Font: Bold + Text: Cheats Align: Center - Text: Debug Options - Background@bg: Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-black - Children: - Label@CHEATS_TITLE: - Y: 25 - Font: Bold - Text: Cheats - Align: Center - Width: PARENT_RIGHT - Checkbox@INSTANT_BUILD: - X: 45 - Y: 45 - Width: 200 - Height: 20 - Font: Regular - Text: Instant Build Speed - Checkbox@ENABLE_TECH: - X: 45 - Y: 75 - Width: 200 - Height: 20 - Font: Regular - Text: Build Everything - Checkbox@BUILD_ANYWHERE: - X: 45 - Y: 105 - Width: 200 - Height: 20 - Font: Regular - Text: Build Anywhere - Checkbox@UNLIMITED_POWER: - X: 290 - Y: 45 - Width: 200 - Height: 20 - Font: Regular - Text: Unlimited Power - Checkbox@INSTANT_CHARGE: - X: 290 - Y: 75 - Width: 200 - Height: 20 - Font: Regular - Text: Instant Charge Time - Checkbox@DISABLE_SHROUD: - X: 290 - Y: 105 - Height: 20 - Width: 200 - Font: Regular - Text: Disable Shroud & Fog - Button@GIVE_CASH: - X: 90 - Y: 145 - Width: 140 - Height: 35 - Text: Give $20,000 - Button@GROW_RESOURCES: - X: 271 - Y: 145 - Width: 140 - Height: 35 - Text: Grow Resources - Button@GIVE_EXPLORATION: - X: 90 - Y: 195 - Width: 140 - Height: 35 - Text: Clear Shroud - Button@RESET_EXPLORATION: - X: 271 - Y: 195 - Width: 140 - Height: 35 - Text: Reset Shroud - Label@VISUALIZATIONS_TITLE: - Y: 255 - Font: Bold - Text: Visualizations - Align: Center - Width: PARENT_RIGHT - Checkbox@SHOW_UNIT_PATHS: - X: 45 - Y: 285 - Width: 200 - Height: 20 - Font: Regular - Text: Show Unit Paths - Checkbox@SHOW_ASTAR: - X: 45 - Y: 315 - Height: 20 - Width: 200 - Font: Regular - Text: Show A* Cost - Checkbox@SHOW_COMBATOVERLAY: - X: 290 - Y: 285 - Height: 20 - Width: 200 - Font: Regular - Text: Show Combat Geometry - Checkbox@SHOW_GEOMETRY: - X: 290 - Y: 315 - Height: 20 - Width: 200 - Font: Regular - Text: Show Render Geometry + Checkbox@INSTANT_BUILD: + X: 45 + Y: 45 + Width: 200 + Height: 20 + Font: Regular + Text: Instant Build Speed + Checkbox@ENABLE_TECH: + X: 45 + Y: 75 + Width: 200 + Height: 20 + Font: Regular + Text: Build Everything + Checkbox@BUILD_ANYWHERE: + X: 45 + Y: 105 + Width: 200 + Height: 20 + Font: Regular + Text: Build Anywhere + Checkbox@UNLIMITED_POWER: + X: 290 + Y: 45 + Width: 200 + Height: 20 + Font: Regular + Text: Unlimited Power + Checkbox@INSTANT_CHARGE: + X: 290 + Y: 75 + Width: 200 + Height: 20 + Font: Regular + Text: Instant Charge Time + Checkbox@DISABLE_SHROUD: + X: 290 + Y: 105 + Height: 20 + Width: 200 + Font: Regular + Text: Disable Shroud & Fog + Button@GIVE_CASH: + X: 90 + Y: 145 + Width: 140 + Height: 35 + Text: Give $20,000 + Button@GROW_RESOURCES: + X: 271 + Y: 145 + Width: 140 + Height: 35 + Text: Grow Resources + Button@GIVE_EXPLORATION: + X: 90 + Y: 195 + Width: 140 + Height: 35 + Text: Clear Shroud + Button@RESET_EXPLORATION: + X: 271 + Y: 195 + Width: 140 + Height: 35 + Text: Reset Shroud + Label@VISUALIZATIONS_TITLE: + Y: 255 + Font: Bold + Text: Visualizations + Align: Center + Width: PARENT_RIGHT + Checkbox@SHOW_UNIT_PATHS: + X: 45 + Y: 285 + Width: 200 + Height: 20 + Font: Regular + Text: Show Unit Paths + Checkbox@SHOW_ASTAR: + X: 45 + Y: 315 + Height: 20 + Width: 200 + Font: Regular + Text: Show A* Cost + Checkbox@SHOW_COMBATOVERLAY: + X: 290 + Y: 285 + Height: 20 + Width: 200 + Font: Regular + Text: Show Combat Geometry + Checkbox@SHOW_GEOMETRY: + X: 290 + Y: 315 + Height: 20 + Width: 200 + Font: Regular + Text: Show Render Geometry diff --git a/mods/cnc/chrome/ingame-info.yaml b/mods/cnc/chrome/ingame-info.yaml new file mode 100644 index 0000000000..7b0a99f610 --- /dev/null +++ b/mods/cnc/chrome/ingame-info.yaml @@ -0,0 +1,55 @@ +Container@GAME_INFO_PANEL: + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 512 + Height: 375 + Logic: GameInfoLogic + Visible: False + Children: + Label@TITLE: + Width: PARENT_RIGHT + Y: 0 - 20 + Text: Game Information + Align: Center + Font: BigBold + Contrast: true + Label@TITLE_NO_TABS: + Width: PARENT_RIGHT + Y: 15 + Text: Game Information + Align: Center + Font: BigBold + Contrast: true + Container@TAB_CONTAINER: + Children: + Button@BUTTON1: + Y: 5 + Width: 140 + Height: 35 + Visible: False + Button@BUTTON2: + X: 150 + Y: 5 + Width: 140 + Height: 35 + Visible: False + Button@BUTTON3: + X: 300 + Y: 5 + Width: 140 + Height: 35 + Visible: False + Background@BACKGROUND: + Y: 39 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background: panel-black + Children: + Container@STATS_PANEL: + Container@MAP_PANEL: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Container@OBJECTIVES_PANEL: + Container@DEBUG_PANEL: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM diff --git a/mods/cnc/chrome/ingame-infobriefing.yaml b/mods/cnc/chrome/ingame-infobriefing.yaml new file mode 100644 index 0000000000..5151240779 --- /dev/null +++ b/mods/cnc/chrome/ingame-infobriefing.yaml @@ -0,0 +1,32 @@ +Container@MAP_PANEL: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoBriefingLogic + Children: + Background@PREVIEW_BG: + X: (PARENT_RIGHT - WIDTH) / 2 + Y: 15 + Width: 324 + Height: 160 + Background: panel-gray + Children: + MapPreview@MAP_PREVIEW: + Width: 320 + Height: 156 + X: 2 + Y: 2 + IgnoreMouseOver: True + IgnoreMouseInput: True + ShowSpawnPoints: False + ScrollPanel@MAP_DESCRIPTION_PANEL: + X: 15 + Y: 190 + Width: 482 + Height: 170 + Children: + Label@MAP_DESCRIPTION: + X: 5 + Y: 195 + Width: 452 + Height: 160 + diff --git a/mods/cnc/chrome/ingame-infoobjectives.yaml b/mods/cnc/chrome/ingame-infoobjectives.yaml new file mode 100644 index 0000000000..b61e92a4af --- /dev/null +++ b/mods/cnc/chrome/ingame-infoobjectives.yaml @@ -0,0 +1,40 @@ +Container@MISSION_OBJECTIVES: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoObjectivesLogic + Children: + Label@MISSION: + X: 15 + Y: 15 + Width: 80 + Height: 20 + Font: MediumBold + Text: Mission: + Label@MISSION_STATUS: + X: 95 + Y: 15 + Width: PARENT_RIGHT - 110 + Height: 20 + Font: MediumBold + ScrollPanel@OBJECTIVES_PANEL: + X: 15 + Y: 50 + Width: 482 + Height: 310 + ItemSpacing: 35 + Children: + Container@OBJECTIVE_TEMPLATE: + Children: + Label@OBJECTIVE_TYPE: + X: 10 + Y: 0 - 20 + Height: 20 + Width: 70 + Align: Center + Checkbox@OBJECTIVE_STATUS: + X: 90 + Y: 0 - 20 + Width: PARENT_RIGHT - 100 + Height: 20 + Disabled: True + TextColorDisabled: 255,255,255 diff --git a/mods/cnc/chrome/ingame-infostats.yaml b/mods/cnc/chrome/ingame-infostats.yaml new file mode 100644 index 0000000000..46dcfa0f0d --- /dev/null +++ b/mods/cnc/chrome/ingame-infostats.yaml @@ -0,0 +1,108 @@ +Container@SKIRMISH_STATS: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoStatsLogic + Children: + Label@STATS_OBJECTIVE: + X: 15 + Y: 10 + Width: 85 + Height: 25 + Font: MediumBold + Text: Mission: + Label@STATS_STATUS: + X: 100 + Y: 10 + Width: PARENT_RIGHT - 10 + Height: 25 + Font: MediumBold + Checkbox@STATS_CHECKBOX: + X: 15 + Y: 45 + Width: 482 + Height: 20 + Font: Bold + Text: Destroy all opposition! + Disabled: yes + TextColorDisabled: 255,255,255 + Container@STATS_HEADERS: + X: 17 + Y: 80 + Width: 393 + Children: + Label@NAME: + X: 10 + Width: 150 + Height: 25 + Text: Player + Font: Bold + Label@RACE: + X: 150 + Width: 80 + Height: 25 + Text: Faction + Font: Bold + Align: Center + Label@STANCE: + X: 240 + Width: 70 + Height: 25 + Text: Team + Font: Bold + Align: Center + Label@KILLS: + X: 310 + Width: 70 + Height: 25 + Text: Kills + Font: Bold + Align: Center + Label@DEATHS: + X: 380 + Width: 70 + Height: 25 + Text: Deaths + Font: Bold + Align: Center + ScrollPanel@PLAYER_LIST: + X: 15 + Y: 105 + Width: 482 + Height: 250 + ItemSpacing: 5 + Children: + Container@PLAYER_TEMPLATE: + Width: PARENT_RIGHT-27 + Height: 25 + X: 2 + Y: 0 + Children: + Label@NAME: + X: 10 + Width: 150 + Height: 25 + Image@FACTIONFLAG: + X: 159 + Y: 6 + Width: 32 + Height: 16 + Label@FACTION: + X: 195 + Width: 40 + Height: 25 + Label@TEAM: + X: 240 + Width: 70 + Height: 25 + Align: Center + Label@KILLS: + X: 310 + Width: 70 + Height: 25 + Align: Center + Label@DEATHS: + X: 380 + Width: 70 + Height: 25 + Align: Center + diff --git a/mods/cnc/chrome/ingame-leavemap.yaml b/mods/cnc/chrome/ingame-leavemap.yaml new file mode 100644 index 0000000000..1b150db223 --- /dev/null +++ b/mods/cnc/chrome/ingame-leavemap.yaml @@ -0,0 +1,98 @@ +Container@LEAVE_RESTART_WIDGET: + Logic: LeaveMapLogic + Children: + Image@EVA: + X: WINDOW_RIGHT-128-43 + Y: 43 + Width: 128 + Height: 64 + ImageCollection: logos + ImageName: eva + Label@VERSION_LABEL: + X: WINDOW_RIGHT-128-43 + Y: 115 + Width: 128 + Align: Center + Contrast: true + Background@BORDER: + Width: WINDOW_RIGHT + Height: WINDOW_BOTTOM + Background: shellmapborder + Container@LEAVE_RESTART_SIMPLE + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 370 + Height: 125 + Visible: False + Children: + Background@LEAVE_RESTART_SIMPLE_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM - 35 + Background: panel-black + Children: + Label@GAME_ENDED_LABEL: + X: 0 + Y: 0 - 25 + Width: PARENT_RIGHT + Font: BigBold + Align: Center + Text: The game has ended + Contrast: True + Label@BLURB: + X: 15 + Y: (PARENT_BOTTOM - HEIGHT) / 2 + Width: PARENT_RIGHT - 30 + Text: Press 'Leave' to return to the main menu. + Align: Center + Button@LEAVE_BUTTON: + X: 0 + Y: PARENT_BOTTOM - 1 + Width: 140 + Height: 35 + Font: Bold + Text: Leave + Button@RESTART_BUTTON: + X: 150 + Y: PARENT_BOTTOM - 1 + Width: 140 + Height: 35 + Font: Bold + Text: Restart + Visible: false + Container@LEAVE_RESTART_FULL: + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 512 + Height: 410 + Visible: False + Children: + Background@LEAVE_RESTART_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM - 35 + Background: panel-black + Children: + Label@GAME_ENDED_LABEL: + X: 0 + Y: 0 - 25 + Width: PARENT_RIGHT + Font: BigBold + Align: Center + Text: The game has ended + Contrast: True + Button@LEAVE_BUTTON: + X: 0 + Y: PARENT_BOTTOM - 1 + Width: 140 + Height: 35 + Font: Bold + Text: Leave + Button@RESTART_BUTTON: + X: 150 + Y: PARENT_BOTTOM - 1 + Width: 140 + Height: 35 + Font: Bold + Text: Restart + Visible: false + Container@OBJECTIVES: + diff --git a/mods/cnc/chrome/ingame-menu.yaml b/mods/cnc/chrome/ingame-menu.yaml index 606e1789a9..859a57978c 100644 --- a/mods/cnc/chrome/ingame-menu.yaml +++ b/mods/cnc/chrome/ingame-menu.yaml @@ -1,27 +1,7 @@ -Container@INGAME_MENU_PANEL: - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 512 - Height: 370 - Children: - Button@OBJECTIVES_BUTTON: - Y: PARENT_BOTTOM - 1 - Width: 140 - Height: 35 - Text: Objectives - Visible: false - Button@DEBUG_BUTTON: - X: 150 - Y: PARENT_BOTTOM - 1 - Width: 140 - Height: 35 - Text: Debug - Visible: false - Container@INGAME_MENU: Width: WINDOW_RIGHT Height: WINDOW_BOTTOM - Logic: CncIngameMenuLogic + Logic: IngameMenuLogic Children: Image@EVA: X: WINDOW_RIGHT-128-43 @@ -46,31 +26,31 @@ Container@INGAME_MENU: Width: 740 Height: 35 Children: - Button@QUIT_BUTTON: + Button@ABORT_MISSION: X: 0 Y: 0 Width: 140 Height: 35 Text: Abort Mission - Button@SURRENDER_BUTTON: + Button@SURRENDER: X: 150 Y: 0 Width: 140 Height: 35 Text: Surrender - Button@MUSIC_BUTTON: + Button@MUSIC: X: 300 Y: 0 Width: 140 Height: 35 Text: Music - Button@SETTINGS_BUTTON: + Button@SETTINGS: X: 450 Y: 0 Width: 140 Height: 35 Text: Settings - Button@RESUME_BUTTON: + Button@RESUME: Key: escape X: 600 Y: 0 diff --git a/mods/cnc/chrome/objectives.yaml b/mods/cnc/chrome/objectives.yaml deleted file mode 100644 index 2599c1e804..0000000000 --- a/mods/cnc/chrome/objectives.yaml +++ /dev/null @@ -1,120 +0,0 @@ -Container@CONQUEST_OBJECTIVES: - Logic: CncConquestObjectivesLogic - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Children: - Label@TITLE: - Width: PARENT_RIGHT - Y: 0-25 - Font: BigBold - Contrast: true - Align: Center - Background@bg: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-black - Children: - Label@PRIMARY: - X: 15 - Y: 10 - Width: 482 - Height: 25 - Font: MediumBold - Text: Primary Objectives: - Label@STATUS: - X: 190 - Y: 10 - Width: 482 - Height: 25 - Font: MediumBold - Text: Incomplete - Checkbox@1: - X: 25 - Y: 45 - Width: 482 - Height: 20 - Font: Bold - Text: Crush all opposition! - Disabled: yes - Container@LABEL_CONTAINER: - X: 17 - Y: 80 - Width: 393 - Children: - Label@NAME: - X: 10 - Width: 150 - Height: 25 - Text: Player - Align: Center - Font: Bold - Label@RACE: - X: 150 - Width: 80 - Height: 25 - Text: Faction - Font: Bold - Align: Center - Label@STANCE: - X: 240 - Width: 70 - Height: 25 - Text: Team - Font: Bold - Align: Center - Label@KILLS: - X: 310 - Width: 70 - Height: 25 - Text: Kills - Font: Bold - Align: Center - Label@DEATHS: - X: 380 - Width: 70 - Height: 25 - Text: Deaths - Font: Bold - Align: Center - ScrollPanel@PLAYER_LIST: - X: 15 - Y: 105 - Width: 482 - Height: 250 - ItemSpacing: 5 - Children: - Container@PLAYER_TEMPLATE: - Width: PARENT_RIGHT-27 - Height: 25 - X: 2 - Y: 0 - Children: - Label@NAME: - X: 10 - Width: 150 - Height: 25 - Image@FACTIONFLAG: - X: 159 - Y: 6 - Width: 32 - Height: 16 - Label@FACTION: - X: 195 - Width: 40 - Height: 25 - Label@TEAM: - X: 240 - Width: 70 - Height: 25 - Align: Center - Label@KILLS: - X: 310 - Width: 70 - Height: 25 - Align: Center - Label@DEATHS: - X: 380 - Width: 70 - Height: 25 - Align: Center - diff --git a/mods/cnc/maps/gdi01/gdi01.lua b/mods/cnc/maps/gdi01/gdi01.lua index 4cb5b1faa1..b54c5f8e98 100644 --- a/mods/cnc/maps/gdi01/gdi01.lua +++ b/mods/cnc/maps/gdi01/gdi01.lua @@ -2,58 +2,76 @@ InfantryReinforcements = { "e1", "e1", "e1" } VehicleReinforcements = { "jeep" } NodPatrol = { "e1", "e1" } -MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) - Media.PlayMovieFullscreen("consyard.vqa") -end - -MissionFailed = function() - Mission.MissionOver(nil, { player }, false) - Media.PlayMovieFullscreen("gameover.vqa") -end - SendNodPatrol = function() - local patrol = Reinforcements.Reinforce(enemy, NodPatrol, nod0.Location, nod1.Location, 0) - Utils.Do(patrol, function(soldier) - Actor.Move(soldier, nod2.Location) - Actor.Move(soldier, nod3.Location) - Actor.Hunt(soldier) + Utils.Do(NodPatrol, function(type) + local soldier = Actor.Create(type, true, { Location = nod0.Location, Owner = enemy }) + soldier.Move(nod1.Location) + soldier.AttackMove(nod2.Location) + soldier.Move(nod3.Location) + soldier.Hunt() end) end -SetGunboatPath = function() - Actor.AttackMove(Gunboat, gunboatLeft.Location) - Actor.AttackMove(Gunboat, gunboatRight.Location) +SetGunboatPath = function(gunboat) + gunboat.AttackMove(gunboatLeft.Location) + gunboat.AttackMove(gunboatRight.Location) end ReinforceFromSea = function(passengers) - local hovercraft, troops = Reinforcements.Insert(player, "oldlst", passengers, { lstStart.Location, lstEnd.Location }, { lstStart.Location }) - Media.PlaySpeechNotification("Reinforce") + local transport = Actor.Create("oldlst", true, { Location = lstStart.Location, Owner = player }) + + Utils.Do(passengers, function(actorType) + local passenger = Actor.Create(actorType, false, { Owner = player }) + transport.LoadPassenger(passenger) + end) + + transport.Move(lstEnd.Location) + transport.UnloadPassengers() + transport.Wait(50) + transport.Move(lstStart.Location) + transport.Destroy() + + Media.PlaySpeechNotification(player, "Reinforce") end WorldLoaded = function() - player = OpenRA.GetPlayer("GDI") - enemy = OpenRA.GetPlayer("Nod") - Media.PlayMovieFullscreen("gdi1.vqa", function() Media.PlayMovieFullscreen("landing.vqa") end) + player = Player.GetPlayer("GDI") + enemy = Player.GetPlayer("Nod") + + gdiObjective = player.AddPrimaryObjective("Destroy all Nod forces in the area!") + + Trigger.OnPlayerWon(player, function() + Media.PlaySpeechNotification(player, "Win") + Trigger.AfterDelay(25, function() + Media.PlayMovieFullscreen("consyard.vqa") + end) + end) + + Trigger.OnPlayerLost(player, function() + Media.PlaySpeechNotification(player, "Lose") + Trigger.AfterDelay(25, function() + Media.PlayMovieFullscreen("gameover.vqa") + end) + end) + + Trigger.OnIdle(Gunboat, function() SetGunboatPath(Gunboat) end) + SendNodPatrol() - OpenRA.RunAfterDelay(25 * 5, function() ReinforceFromSea(InfantryReinforcements) end) - OpenRA.RunAfterDelay(25 * 15, function() ReinforceFromSea(InfantryReinforcements) end) - OpenRA.RunAfterDelay(25 * 30, function() ReinforceFromSea(VehicleReinforcements) end) - OpenRA.RunAfterDelay(25 * 60, function() ReinforceFromSea(VehicleReinforcements) end) + Trigger.AfterDelay(25 * 5, function() ReinforceFromSea(InfantryReinforcements) end) + Trigger.AfterDelay(25 * 15, function() ReinforceFromSea(InfantryReinforcements) end) + Trigger.AfterDelay(25 * 30, function() ReinforceFromSea(VehicleReinforcements) end) + Trigger.AfterDelay(25 * 60, function() ReinforceFromSea(VehicleReinforcements) end) end Tick = function() - if Actor.IsIdle(Gunboat) then - SetGunboatPath() + if enemy.HasNoRequiredUnits() then + player.MarkCompletedObjective(gdiObjective) end - if Mission.RequiredUnitsAreDestroyed(player) then - MissionFailed() + if player.HasNoRequiredUnits() then + player.MarkFailedObjective(gdiObjective) end - if Mission.RequiredUnitsAreDestroyed(enemy) then - MissionAccomplished() - end -end \ No newline at end of file +end diff --git a/mods/cnc/maps/gdi01/map.yaml b/mods/cnc/maps/gdi01/map.yaml index 072923e57e..c06e937d74 100644 --- a/mods/cnc/maps/gdi01/map.yaml +++ b/mods/cnc/maps/gdi01/map.yaml @@ -457,10 +457,14 @@ Rules: PlayMusicOnMapLoad: Music: aoi Loop: false - LuaScriptInterface: - LuaScripts: gdi01.lua + LuaScript: + Scripts: gdi01.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true ^Infantry: MustBeDestroyed: PROC: diff --git a/mods/cnc/maps/gdi02/gdi02.lua b/mods/cnc/maps/gdi02/gdi02.lua index 978fcf0265..ea566859d3 100644 --- a/mods/cnc/maps/gdi02/gdi02.lua +++ b/mods/cnc/maps/gdi02/gdi02.lua @@ -5,12 +5,12 @@ VehicleReinforcements = { "jeep" } AttackerSquadSize = 3 MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("flag.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("gameover.vqa") end diff --git a/mods/cnc/maps/gdi02/map.yaml b/mods/cnc/maps/gdi02/map.yaml index 08a82ce766..402d22c050 100644 --- a/mods/cnc/maps/gdi02/map.yaml +++ b/mods/cnc/maps/gdi02/map.yaml @@ -736,8 +736,12 @@ Rules: -CrateSpawner: LuaScriptInterface: LuaScripts: gdi02.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true PROC: Buildable: Prerequisites: ~disabled diff --git a/mods/cnc/maps/gdi03/gdi03.lua b/mods/cnc/maps/gdi03/gdi03.lua index 8809c80b20..988d060522 100644 --- a/mods/cnc/maps/gdi03/gdi03.lua +++ b/mods/cnc/maps/gdi03/gdi03.lua @@ -1,10 +1,10 @@ MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("bombaway.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("gameover.vqa") end diff --git a/mods/cnc/maps/gdi03/map.yaml b/mods/cnc/maps/gdi03/map.yaml index 5deae0f5e8..1b5b6ecf1c 100644 --- a/mods/cnc/maps/gdi03/map.yaml +++ b/mods/cnc/maps/gdi03/map.yaml @@ -897,8 +897,12 @@ Rules: -CrateSpawner: LuaScriptInterface: LuaScripts: gdi03.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true ^Infantry: MustBeDestroyed: WEAP: diff --git a/mods/cnc/maps/gdi04a/gdi04a.lua b/mods/cnc/maps/gdi04a/gdi04a.lua index 4835100100..c911c0ecdf 100644 --- a/mods/cnc/maps/gdi04a/gdi04a.lua +++ b/mods/cnc/maps/gdi04a/gdi04a.lua @@ -127,11 +127,11 @@ WorldLoaded = function() end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("burdet1.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("gameover.vqa") end diff --git a/mods/cnc/maps/gdi04a/map.yaml b/mods/cnc/maps/gdi04a/map.yaml index c0f56925fb..f99bae6bc2 100644 --- a/mods/cnc/maps/gdi04a/map.yaml +++ b/mods/cnc/maps/gdi04a/map.yaml @@ -546,8 +546,12 @@ Rules: -CrateSpawner: LuaScriptInterface: LuaScripts: gdi04a.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true ^Infantry: MustBeDestroyed: ^Vehicle: diff --git a/mods/cnc/maps/gdi04b/gdi04b.lua b/mods/cnc/maps/gdi04b/gdi04b.lua index f0774926b7..ba071d47e7 100644 --- a/mods/cnc/maps/gdi04b/gdi04b.lua +++ b/mods/cnc/maps/gdi04b/gdi04b.lua @@ -162,11 +162,11 @@ WorldLoaded = function() end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("burdet1.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("gameover.vqa") end diff --git a/mods/cnc/maps/gdi04b/map.yaml b/mods/cnc/maps/gdi04b/map.yaml index 98e836adc3..03790c811b 100644 --- a/mods/cnc/maps/gdi04b/map.yaml +++ b/mods/cnc/maps/gdi04b/map.yaml @@ -625,8 +625,12 @@ Rules: -CrateSpawner: LuaScriptInterface: LuaScripts: gdi04b.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true ^Infantry: MustBeDestroyed: ^Vehicle: diff --git a/mods/cnc/maps/gdi04c/gdi04c.lua b/mods/cnc/maps/gdi04c/gdi04c.lua index e1d33804d0..df75bd136c 100644 --- a/mods/cnc/maps/gdi04c/gdi04c.lua +++ b/mods/cnc/maps/gdi04c/gdi04c.lua @@ -109,11 +109,11 @@ WorldLoaded = function() end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("burdet1.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("gameover.vqa") end diff --git a/mods/cnc/maps/gdi04c/map.yaml b/mods/cnc/maps/gdi04c/map.yaml index 35a8b22e92..91929a834d 100644 --- a/mods/cnc/maps/gdi04c/map.yaml +++ b/mods/cnc/maps/gdi04c/map.yaml @@ -895,8 +895,12 @@ Rules: -CrateSpawner: LuaScriptInterface: LuaScripts: gdi04c.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true ^Infantry: MustBeDestroyed: ^Vehicle: diff --git a/mods/cnc/maps/nod01/map.yaml b/mods/cnc/maps/nod01/map.yaml index fc6b415d6e..1419f6cb4a 100644 --- a/mods/cnc/maps/nod01/map.yaml +++ b/mods/cnc/maps/nod01/map.yaml @@ -299,12 +299,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: nod01.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES C10: Tooltip: Name: Nikoomba diff --git a/mods/cnc/maps/nod01/nod01.lua b/mods/cnc/maps/nod01/nod01.lua index 7628104eb4..6db3abfa2d 100644 --- a/mods/cnc/maps/nod01/nod01.lua +++ b/mods/cnc/maps/nod01/nod01.lua @@ -2,11 +2,11 @@ RifleInfantryReinforcements = { "e1", "e1", } RocketInfantryReinforcements = { "e3", "e3", "e3" } MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("nodlose.vqa") end diff --git a/mods/cnc/maps/nod03a/map.yaml b/mods/cnc/maps/nod03a/map.yaml index 34d7eb053a..b61ce9c898 100644 --- a/mods/cnc/maps/nod03a/map.yaml +++ b/mods/cnc/maps/nod03a/map.yaml @@ -565,12 +565,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: nod03a.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES NUK2: Buildable: Prerequisites: ~disabled diff --git a/mods/cnc/maps/nod03a/nod03a.lua b/mods/cnc/maps/nod03a/nod03a.lua index ab8fae4894..f1cf69e834 100644 --- a/mods/cnc/maps/nod03a/nod03a.lua +++ b/mods/cnc/maps/nod03a/nod03a.lua @@ -2,12 +2,12 @@ FirstAttackWave = { "e1", "e1", "e1", "e2", } SecondThirdAttackWave = { "e1", "e1", "e2", } MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("desflees.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("flag.vqa") end diff --git a/mods/cnc/maps/nod03b/map.yaml b/mods/cnc/maps/nod03b/map.yaml index 5ef9dc9f71..9f3b265393 100644 --- a/mods/cnc/maps/nod03b/map.yaml +++ b/mods/cnc/maps/nod03b/map.yaml @@ -634,12 +634,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: nod03b.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES NUK2: Buildable: Prerequisites: ~disabled diff --git a/mods/cnc/maps/nod03b/nod03b.lua b/mods/cnc/maps/nod03b/nod03b.lua index 8171a58770..88a6037a87 100644 --- a/mods/cnc/maps/nod03b/nod03b.lua +++ b/mods/cnc/maps/nod03b/nod03b.lua @@ -3,12 +3,12 @@ SecondAttackWave = { "e1", "e1", "e1", } ThirdAttackWave = { "e1", "e1", "e1", "e2", } MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("desflees.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("flag.vqa") end diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 13479e27d0..38afa45035 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -88,13 +88,17 @@ ChromeLayout: mods/cnc/chrome/replaybrowser.yaml mods/cnc/chrome/ingame.yaml mods/cnc/chrome/ingame-chat.yaml - mods/cnc/chrome/ingame-debug.yaml mods/cnc/chrome/ingame-menu.yaml + mods/cnc/chrome/ingame-debug.yaml + mods/cnc/chrome/ingame-info.yaml + mods/cnc/chrome/ingame-infobriefing.yaml + mods/cnc/chrome/ingame-infoobjectives.yaml + mods/cnc/chrome/ingame-infostats.yaml + mods/cnc/chrome/ingame-leavemap.yaml mods/cnc/chrome/music.yaml mods/cnc/chrome/settings.yaml mods/cnc/chrome/credits.yaml mods/cnc/chrome/dialogs.yaml - mods/cnc/chrome/objectives.yaml mods/cnc/chrome/tooltips.yaml mods/cnc/chrome/irc.yaml mods/cnc/chrome/assetbrowser.yaml diff --git a/mods/cnc/rules/player.yaml b/mods/cnc/rules/player.yaml index d1e0dd8ff8..f177d84ce9 100644 --- a/mods/cnc/rules/player.yaml +++ b/mods/cnc/rules/player.yaml @@ -2,6 +2,8 @@ Player: PlaceBuilding: TechTree: SupportPowerManager: + ScriptTriggers: + MissionObjectives: ConquestVictoryConditions: PowerManager: AllyRepair: diff --git a/mods/cnc/rules/world.yaml b/mods/cnc/rules/world.yaml index 2014d5aff4..fe0e1d98e3 100644 --- a/mods/cnc/rules/world.yaml +++ b/mods/cnc/rules/world.yaml @@ -8,6 +8,7 @@ World: LoadWidgetAtGameStart: Widget: INGAME_ROOT MenuPaletteEffect: + MenuEffect: Desaturated CloakPaletteEffect: ScreenShaker: NukePaletteEffect: @@ -185,7 +186,7 @@ World: PathFinder: ValidateOrder: DebugPauseState: - ConquestObjectivesPanel: - ObjectivesPanel: CONQUEST_OBJECTIVES + ObjectivesPanel: + PanelName: SKIRMISH_STATS RadarPings: diff --git a/mods/d2k/chrome.yaml b/mods/d2k/chrome.yaml index cf54d9356e..119686643f 100644 --- a/mods/d2k/chrome.yaml +++ b/mods/d2k/chrome.yaml @@ -521,7 +521,10 @@ checkbox: dialog.png corner-br: 767,127,1,1 checkbox-bits: buttons.png - checked: 0,140,16,16 + checked: 0,157,16,16 + checked-disabled: 0,173,16,16 + crossed: 16,157,16,16 + crossed-disabled: 16,173,16,16 checkbox-hover: dialog.png background: 641,129,126,126 diff --git a/mods/d2k/chrome/ingame-leavemap.yaml b/mods/d2k/chrome/ingame-leavemap.yaml new file mode 100644 index 0000000000..cd78d046f0 --- /dev/null +++ b/mods/d2k/chrome/ingame-leavemap.yaml @@ -0,0 +1,92 @@ +Container@LEAVE_RESTART_WIDGET: + Logic: LeaveMapLogic + Children: + Background@BORDER: + X: 0 - 15 + Y: 0 - 15 + Width: WINDOW_RIGHT + 30 + Height: WINDOW_BOTTOM + 30 + Background: mainmenu-border + Label@VERSION_LABEL: + X: WINDOW_RIGHT - 10 + Y: WINDOW_BOTTOM - 20 + Align: Right + Font: Regular + Contrast: True + Container@LEAVE_RESTART_SIMPLE + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 370 + Height: 175 + Visible: False + Children: + Background@LEAVE_RESTART_SIMPLE_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Children: + Label@GAME_ENDED_LABEL: + Y: 20 + Width: PARENT_RIGHT + Height: 25 + Font: Bold + Align: Center + Text: The game has ended + Label@BLURB: + X: 15 + Y: 50 + Width: PARENT_RIGHT - 30 + Height: 65 + Text: Press 'Leave' to return to the main menu. + Align: Center + Button@RESTART_BUTTON: + X: 20 + Y: PARENT_BOTTOM - 45 + Width: 140 + Height: 25 + Font: Bold + Text: Restart + Visible: false + Button@LEAVE_BUTTON: + X: (PARENT_RIGHT - WIDTH) / 2 + Y: PARENT_BOTTOM - 45 + Width: 140 + Height: 25 + Font: Bold + Text: Leave + Container@LEAVE_RESTART_FULL: + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 522 + Height: 470 + Visible: False + Children: + Background@LEAVE_RESTART_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Children: + Label@GAME_ENDED_LABEL: + X: 20 + Y: 20 + Width: PARENT_RIGHT - 40 + Height: 25 + Font: Bold + Align: Center + Text: The game has ended + Button@RESTART_BUTTON: + X: PARENT_RIGHT - 2 * (WIDTH + 20) + Y: PARENT_BOTTOM - 45 + Width: 120 + Height: 25 + Font: Bold + Text: Restart + Visible: false + Button@LEAVE_BUTTON: + X: PARENT_RIGHT - WIDTH - 20 + Y: PARENT_BOTTOM - 45 + Width: 120 + Height: 25 + Font: Bold + Text: Leave + Container@OBJECTIVES: + Y: 40 + diff --git a/mods/d2k/chrome/ingame-menu.yaml b/mods/d2k/chrome/ingame-menu.yaml new file mode 100644 index 0000000000..bcddf2682d --- /dev/null +++ b/mods/d2k/chrome/ingame-menu.yaml @@ -0,0 +1,61 @@ +Container@INGAME_MENU: + Width: WINDOW_RIGHT + Height: WINDOW_BOTTOM + Logic: IngameMenuLogic + Children: + Label@VERSION_LABEL: + X: WINDOW_RIGHT - 10 + Y: WINDOW_BOTTOM - 20 + Align: Right + Font: Regular + Contrast: True + Background@MENU_BUTTONS: + X: 100 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 200 + Height: 295 + Children: + Label@LABEL_TITLE: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 20 + Width: 200 + Height: 30 + Text: Options + Align: Center + Font: Bold + Button@RESUME: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 60 + Width: 140 + Height: 30 + Text: Resume + Font: Bold + Key: escape + Button@SETTINGS: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 100 + Width: 140 + Height: 30 + Text: Settings + Font: Bold + Button@MUSIC: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 140 + Width: 140 + Height: 30 + Text: Music + Font: Bold + Button@SURRENDER: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 180 + Width: 140 + Height: 30 + Text: Surrender + Font: Bold + Button@ABORT_MISSION: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 220 + Width: 140 + Height: 30 + Text: Abort Mission + Font: Bold diff --git a/mods/d2k/chrome/ingame-observer.yaml b/mods/d2k/chrome/ingame-observer.yaml index 996d72c9b4..3aa2336b2d 100644 --- a/mods/d2k/chrome/ingame-observer.yaml +++ b/mods/d2k/chrome/ingame-observer.yaml @@ -1,6 +1,10 @@ Container@OBSERVER_WIDGETS: Children: - Button@OBSERVER_STATS_BUTTON: + MenuButton@OBSERVER_STATS_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_OBSERVERSTATS_BG + HideIngameUI: False + Pause: False X: 162 Y: 0 Width: 160 diff --git a/mods/d2k/chrome/ingame-player.yaml b/mods/d2k/chrome/ingame-player.yaml index 38f2eb8fbf..e60ff102b8 100644 --- a/mods/d2k/chrome/ingame-player.yaml +++ b/mods/d2k/chrome/ingame-player.yaml @@ -3,7 +3,10 @@ Container@PLAYER_WIDGETS: LogicKeyListener@CONTROLGROUP_KEYHANDLER: Logic: ControlGroupLogic LogicTicker@SIDEBAR_TICKER: - Button@INGAME_DIPLOMACY_BUTTON: + MenuButton@DIPLOMACY_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_DIPLOMACY_BG + HideIngameUI: False X: 162 Y: 0 Width: 160 @@ -11,24 +14,16 @@ Container@PLAYER_WIDGETS: Text: Diplomacy (P) Font: Bold Key: p - Button@INGAME_DEBUG_BUTTON: + MenuButton@DEBUG_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_MENU X: 324 Y: 0 Width: 160 Height: 25 Text: Debug (Shift + Esc) - Visible: false Font: Bold Key: escape Shift - Button@OBJECTIVES_BUTTON: - X: 486 - Y: 0 - Width: 160 - Height: 25 - Text: Objectives (O) - Visible: false - Font: Bold - Key: o SlidingContainer@INGAME_RADAR_BIN: X: WINDOW_RIGHT-215 Y: 0 diff --git a/mods/d2k/chrome/ingame.yaml b/mods/d2k/chrome/ingame.yaml index 6fb6d8f353..ba99368f3b 100644 --- a/mods/d2k/chrome/ingame.yaml +++ b/mods/d2k/chrome/ingame.yaml @@ -46,7 +46,8 @@ Container@INGAME_ROOT: Y: 34 Order: Descending Container@PLAYER_ROOT: - Button@INGAME_OPTIONS_BUTTON: + MenuButton@OPTIONS_BUTTON: + Logic: OrderButtonsChromeLogic X: 0 Y: 0 Width: 160 diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index e27ad056d8..e4703fe110 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -61,11 +61,16 @@ ChromeLayout: mods/ra/chrome/ingame-chat.yaml mods/ra/chrome/ingame-diplomacy.yaml mods/ra/chrome/ingame-fmvplayer.yaml - mods/ra/chrome/ingame-menu.yaml + mods/d2k/chrome/ingame-menu.yaml + mods/ra/chrome/ingame-info.yaml + mods/ra/chrome/ingame-infobriefing.yaml + mods/ra/chrome/ingame-infoobjectives.yaml + mods/ra/chrome/ingame-infostats.yaml mods/d2k/chrome/ingame-observer.yaml mods/ra/chrome/ingame-observerstats.yaml mods/d2k/chrome/ingame-player.yaml mods/ra/chrome/ingame-debug.yaml + mods/d2k/chrome/ingame-leavemap.yaml mods/d2k/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/ra/chrome/credits.yaml @@ -152,6 +157,9 @@ Fonts: Title: Font:mods/d2k/Dune2k.ttf Size:32 + MediumBold: + Font:FreeSansBold.ttf + Size:18 BigBold: Font:FreeSansBold.ttf Size:24 diff --git a/mods/d2k/rules/player.yaml b/mods/d2k/rules/player.yaml index 1112e28208..e55955cda7 100644 --- a/mods/d2k/rules/player.yaml +++ b/mods/d2k/rules/player.yaml @@ -34,6 +34,8 @@ Player: BlockedAudio: NoRoom PlaceBuilding: SupportPowerManager: + ScriptTriggers: + MissionObjectives: ConquestVictoryConditions: PowerManager: AdviceInterval: 650 diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index 6df1ce8aec..d1dfee1296 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -189,4 +189,6 @@ World: ValidateOrder: DebugPauseState: RadarPings: + ObjectivesPanel: + PanelName: SKIRMISH_STATS diff --git a/mods/d2k/uibits/buttons.png b/mods/d2k/uibits/buttons.png index b2b4085580..93f928ee98 100644 Binary files a/mods/d2k/uibits/buttons.png and b/mods/d2k/uibits/buttons.png differ diff --git a/mods/ra/chrome.yaml b/mods/ra/chrome.yaml index 02cb7d045e..db547c0ab1 100644 --- a/mods/ra/chrome.yaml +++ b/mods/ra/chrome.yaml @@ -427,7 +427,10 @@ checkbox: dialog.png corner-br: 767,127,1,1 checkbox-bits: buttons.png - checked: 0,140,16,16 + checked: 0,157,16,16 + checked-disabled: 0,173,16,16 + crossed: 16,157,16,16 + crossed-disabled: 16,173,16,16 checkbox-hover: dialog.png background: 641,129,126,126 diff --git a/mods/ra/chrome/ingame-debug.yaml b/mods/ra/chrome/ingame-debug.yaml index b10dd915b9..b2e20db205 100644 --- a/mods/ra/chrome/ingame-debug.yaml +++ b/mods/ra/chrome/ingame-debug.yaml @@ -1,110 +1,117 @@ -Background@INGAME_DEBUG_BG: +Container@DEBUG_PANEL: Logic: DebugMenuLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 350 - Height: 475 + Y: 20 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM Children: - Label@LABEL_TITLE: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 20 - Width: 250 - Height: 25 + Label@LABLE_TITLE: + Y: 25 + Font: Bold Text: Debug Options Align: Center - Font: Bold - Checkbox@DISABLE_SHROUD: - X: 30 - Y: 50 - Height: 20 - Width: PARENT_RIGHT - 30 - Text: Disable Shroud & Fog - Button@GIVE_EXPLORATION: - X: 30 - Y: 80 - Width: 120 - Height: 25 - Text: Give Exploration - Button@RESET_EXPLORATION: - X: 200 - Y: 80 - Width: 120 - Height: 25 - Text: Reset Exploration - Checkbox@SHOW_UNIT_PATHS: - X: 30 - Y: 110 - Width: PARENT_RIGHT - 30 - Height: 20 - Text: Show Unit Paths - Button@GIVE_CASH: - X: 30 - Y: 140 - Width: 135 - Height: 20 - Text: Give $20000 Cash - Height: 25 - Button@GROW_RESOURCES: - X: 185 - Y: 140 - Width: 135 - Height: 20 - Text: Grow Resources - Height: 25 + Width: PARENT_RIGHT Checkbox@INSTANT_BUILD: - X: 30 - Y: 170 - Width: PARENT_RIGHT - 30 + X: 45 + Y: 45 + Width: 200 Height: 20 + Font: Regular Text: Instant Build Speed - Checkbox@INSTANT_CHARGE: - X: 30 - Y: 200 - Width: PARENT_RIGHT - 30 - Height: 20 - Text: Support Powers Charge Instantly Checkbox@ENABLE_TECH: - X: 30 - Y: 230 - Width: PARENT_RIGHT - 30 + X: 45 + Y: 75 + Width: 200 Height: 20 + Font: Regular Text: Build Everything - Checkbox@UNLIMITED_POWER: - X: 30 - Y: 260 - Width: PARENT_RIGHT - 30 - Height: 20 - Text: Unlimited Power Checkbox@BUILD_ANYWHERE: - X: 30 - Y: 290 - Width: PARENT_RIGHT - 30 + X: 45 + Y: 105 + Width: 200 Height: 20 + Font: Regular Text: Build Anywhere - Checkbox@SHOW_ASTAR: - X: 30 - Y: 320 - Width: PARENT_RIGHT - 30 + Checkbox@UNLIMITED_POWER: + X: 290 + Y: 45 + Width: 200 Height: 20 + Font: Regular + Text: Unlimited Power + Checkbox@INSTANT_CHARGE: + X: 290 + Y: 75 + Width: 200 + Height: 20 + Font: Regular + Text: Instant Charge Time + Checkbox@DISABLE_SHROUD: + X: 290 + Y: 105 + Height: 20 + Width: 200 + Font: Regular + Text: Disable Shroud & Fog + Button@GIVE_CASH: + X: 90 + Y: 150 + Width: 140 + Height: 30 + Font: Bold + Text: Give $20,000 + Button@GROW_RESOURCES: + X: 271 + Y: 150 + Width: 140 + Height: 30 + Font: Bold + Text: Grow Resources + Button@GIVE_EXPLORATION: + X: 90 + Y: 200 + Width: 140 + Height: 30 + Font: Bold + Text: Clear Shroud + Button@RESET_EXPLORATION: + X: 271 + Y: 200 + Width: 140 + Height: 30 + Font: Bold + Text: Reset Shroud + Label@VISUALIZATIONS_TITLE: + Y: 255 + Font: Bold + Text: Visualizations + Align: Center + Width: PARENT_RIGHT + Checkbox@SHOW_UNIT_PATHS: + X: 45 + Y: 285 + Width: 200 + Height: 20 + Font: Regular + Text: Show Unit Paths + Checkbox@SHOW_ASTAR: + X: 45 + Y: 315 + Height: 20 + Width: 200 + Font: Regular Text: Show A* Cost Checkbox@SHOW_COMBATOVERLAY: - X: 30 - Y: 350 + X: 290 + Y: 285 Height: 20 Width: 200 + Font: Regular Text: Show Combat Geometry Checkbox@SHOW_GEOMETRY: - X: 30 - Y: 380 + X: 290 + Y: 315 Height: 20 Width: 200 + Font: Regular Text: Show Render Geometry - Button@CLOSE: - X: 30 - Y: 420 - Width: PARENT_RIGHT - 60 - Height: 25 - Text: Close - Key: escape - Font: Bold diff --git a/mods/ra/chrome/ingame-info.yaml b/mods/ra/chrome/ingame-info.yaml new file mode 100644 index 0000000000..6aad3f056d --- /dev/null +++ b/mods/ra/chrome/ingame-info.yaml @@ -0,0 +1,64 @@ +Container@GAME_INFO_PANEL: + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 522 + Height: 455 + Logic: GameInfoLogic + Visible: False + Children: + Background@BACKGROUND: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background@BACKGROUND_NO_TABS: + Y: 25 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM - 25 + Label@TITLE: + Y: 20 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Font: Bold + Label@TITLE_NO_TABS: + Y: 45 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Font: Bold + Container@TAB_CONTAINER: + X: (PARENT_RIGHT - WIDTH) / 2 + Width: 360 + Height: 25 + Children: + Button@BUTTON1: + Y: 50 + Width: 120 + Height: 25 + Font: Bold + Visible: False + Button@BUTTON2: + X: 120 + Y: 50 + Width: 120 + Height: 25 + Font: Bold + Visible: False + Button@BUTTON3: + X: 240 + Y: 50 + Width: 120 + Height: 25 + Font: Bold + Visible: False + Container@STATS_PANEL: + Y: 65 + Container@MAP_PANEL: + Y: 65 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Container@OBJECTIVES_PANEL: + Y: 65 + Container@DEBUG_PANEL: + Y: 65 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM diff --git a/mods/ra/chrome/ingame-infobriefing.yaml b/mods/ra/chrome/ingame-infobriefing.yaml new file mode 100644 index 0000000000..de0813f7fe --- /dev/null +++ b/mods/ra/chrome/ingame-infobriefing.yaml @@ -0,0 +1,32 @@ +Container@MAP_PANEL: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoBriefingLogic + Children: + Background@PREVIEW_BG: + X: (PARENT_RIGHT - WIDTH) / 2 + Y: 20 + Width: 324 + Height: 160 + Background: panel-gray + Children: + MapPreview@MAP_PREVIEW: + Width: 320 + Height: 156 + X: 2 + Y: 2 + IgnoreMouseOver: True + IgnoreMouseInput: True + ShowSpawnPoints: False + ScrollPanel@MAP_DESCRIPTION_PANEL: + X: 20 + Y: 195 + Width: 482 + Height: 175 + Children: + Label@MAP_DESCRIPTION: + X: 5 + Y: 180 + Width: 452 + Height: 145 + diff --git a/mods/ra/chrome/ingame-infoobjectives.yaml b/mods/ra/chrome/ingame-infoobjectives.yaml new file mode 100644 index 0000000000..1dde1deee0 --- /dev/null +++ b/mods/ra/chrome/ingame-infoobjectives.yaml @@ -0,0 +1,40 @@ +Container@MISSION_OBJECTIVES: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoObjectivesLogic + Children: + Label@MISSION: + X: 20 + Y: 20 + Width: 80 + Height: 25 + Font: MediumBold + Text: Mission: + Label@MISSION_STATUS: + X: 100 + Y: 20 + Width: PARENT_RIGHT - 120 + Height: 25 + Font: MediumBold + ScrollPanel@OBJECTIVES_PANEL: + X: 20 + Y: 60 + Width: 482 + Height: 310 + ItemSpacing: 35 + Children: + Container@OBJECTIVE_TEMPLATE: + Children: + Label@OBJECTIVE_TYPE: + X: 10 + Y: 0 - 20 + Height: 20 + Width: 70 + Align: Center + Checkbox@OBJECTIVE_STATUS: + X: 90 + Y: 0 - 20 + Width: PARENT_RIGHT - 100 + Height: 20 + Disabled: True + TextColorDisabled: 255,255,255 diff --git a/mods/ra/chrome/ingame-infostats.yaml b/mods/ra/chrome/ingame-infostats.yaml new file mode 100644 index 0000000000..4c8d45ddcd --- /dev/null +++ b/mods/ra/chrome/ingame-infostats.yaml @@ -0,0 +1,108 @@ +Container@SKIRMISH_STATS: + Height: PARENT_BOTTOM + Width: PARENT_RIGHT + Logic: GameInfoStatsLogic + Children: + Label@MISSION: + X: 20 + Y: 20 + Width: 482 + Height: 25 + Font: MediumBold + Text: Mission: + Label@STATS_STATUS: + X: 100 + Y: 20 + Width: PARENT_RIGHT - 10 + Height: 25 + Font: MediumBold + Checkbox@STATS_CHECKBOX: + X: 20 + Y: 55 + Width: 482 + Height: 20 + Font: Bold + Text: Destroy all opposition! + Disabled: yes + TextColorDisabled: 255,255,255 + Container@STATS_HEADERS: + X: 22 + Y: 80 + Width: 393 + Children: + Label@NAME: + X: 10 + Width: 150 + Height: 25 + Text: Player + Font: Bold + Label@RACE: + X: 150 + Width: 80 + Height: 25 + Text: Faction + Font: Bold + Align: Center + Label@STANCE: + X: 240 + Width: 70 + Height: 25 + Text: Team + Font: Bold + Align: Center + Label@KILLS: + X: 310 + Width: 70 + Height: 25 + Text: Kills + Font: Bold + Align: Center + Label@DEATHS: + X: 380 + Width: 70 + Height: 25 + Text: Deaths + Font: Bold + Align: Center + ScrollPanel@PLAYER_LIST: + X: 20 + Y: 105 + Width: 482 + Height: 265 + ItemSpacing: 5 + Children: + Container@PLAYER_TEMPLATE: + Width: PARENT_RIGHT-27 + Height: 25 + X: 2 + Y: 0 + Children: + Label@NAME: + X: 10 + Width: 150 + Height: 25 + Image@FACTIONFLAG: + X: 159 + Y: 6 + Width: 32 + Height: 16 + Label@FACTION: + X: 195 + Width: 40 + Height: 25 + Label@TEAM: + X: 240 + Width: 70 + Height: 25 + Align: Center + Label@KILLS: + X: 310 + Width: 70 + Height: 25 + Align: Center + Label@DEATHS: + X: 380 + Width: 70 + Height: 25 + Align: Center + diff --git a/mods/ra/chrome/ingame-leavemap.yaml b/mods/ra/chrome/ingame-leavemap.yaml new file mode 100644 index 0000000000..1bebfd9716 --- /dev/null +++ b/mods/ra/chrome/ingame-leavemap.yaml @@ -0,0 +1,99 @@ +Container@LEAVE_RESTART_WIDGET: + Logic: LeaveMapLogic + Children: + Background@BORDER: + X: 0 - 15 + Y: 0 - 15 + Width: WINDOW_RIGHT + 30 + Height: WINDOW_BOTTOM + 30 + Background: mainmenu-border + Image@LOGO: + X: WINDOW_RIGHT - 296 + Y: 30 + ImageCollection: logos + ImageName: logo + Label@VERSION_LABEL: + X: WINDOW_RIGHT - 296 + Y: 296 - 20 + Width: 296 - 20 + Height: 25 + Align: Center + Font: Regular + Contrast: True + Container@LEAVE_RESTART_SIMPLE + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 370 + Height: 175 + Visible: False + Children: + Background@LEAVE_RESTART_SIMPLE_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Children: + Label@GAME_ENDED_LABEL: + Y: 20 + Width: PARENT_RIGHT + Height: 25 + Font: Bold + Align: Center + Text: The game has ended + Label@BLURB: + X: 15 + Y: 50 + Width: PARENT_RIGHT - 30 + Height: 65 + Text: Press 'Leave' to return to the main menu. + Align: Center + Button@RESTART_BUTTON: + X: 20 + Y: PARENT_BOTTOM - 45 + Width: 140 + Height: 25 + Font: Bold + Text: Restart + Visible: false + Button@LEAVE_BUTTON: + X: (PARENT_RIGHT - WIDTH) / 2 + Y: PARENT_BOTTOM - 45 + Width: 140 + Height: 25 + Font: Bold + Text: Leave + Container@LEAVE_RESTART_FULL: + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 522 + Height: 470 + Visible: False + Children: + Background@LEAVE_RESTART_BG: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Children: + Label@GAME_ENDED_LABEL: + X: 20 + Y: 20 + Width: PARENT_RIGHT - 40 + Height: 25 + Font: Bold + Align: Center + Text: The game has ended + Button@RESTART_BUTTON: + X: PARENT_RIGHT - 2 * (WIDTH + 20) + Y: PARENT_BOTTOM - 45 + Width: 120 + Height: 25 + Font: Bold + Text: Restart + Visible: false + Button@LEAVE_BUTTON: + X: PARENT_RIGHT - WIDTH - 20 + Y: PARENT_BOTTOM - 45 + Width: 120 + Height: 25 + Font: Bold + Text: Leave + Container@OBJECTIVES: + Y: 40 + diff --git a/mods/ra/chrome/ingame-menu.yaml b/mods/ra/chrome/ingame-menu.yaml index 73ad81ea76..f3483b91e7 100644 --- a/mods/ra/chrome/ingame-menu.yaml +++ b/mods/ra/chrome/ingame-menu.yaml @@ -1,52 +1,74 @@ -Background@INGAME_OPTIONS_BG: - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 300 - Height: 295 +Container@INGAME_MENU: + Width: WINDOW_RIGHT + Height: WINDOW_BOTTOM Logic: IngameMenuLogic Children: - Label@LABEL_TITLE: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 20 - Width: 250 + Background@BORDER: + X: 0 - 15 + Y: 0 - 15 + Width: WINDOW_RIGHT + 30 + Height: WINDOW_BOTTOM + 30 + Background: mainmenu-border + Image@LOGO: + X: WINDOW_RIGHT - 296 + Y: 30 + ImageCollection: logos + ImageName: logo + Label@VERSION_LABEL: + X: WINDOW_RIGHT - 296 + Y: 296 - 20 + Width: 296 - 20 Height: 25 - Text: Options Align: Center - Font: Bold - Button@RESUME: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 60 - Width: 160 - Height: 25 - Text: Resume - Font: Bold - Key: escape - Button@SETTINGS: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 100 - Width: 160 - Height: 25 - Text: Settings - Font: Bold - Button@MUSIC: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 140 - Width: 160 - Height: 25 - Text: Music - Font: Bold - Button@SURRENDER: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 180 - Width: 160 - Height: 25 - Text: Surrender - Font: Bold - Button@DISCONNECT: - X: (PARENT_RIGHT - WIDTH)/2 - Y: 220 - Width: 160 - Height: 25 - Text: Abort Mission - Font: Bold - + Font: Regular + Contrast: True + Background@MENU_BUTTONS: + X: 100 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 200 + Height: 295 + Children: + Label@LABEL_TITLE: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 20 + Width: 200 + Height: 30 + Text: Options + Align: Center + Font: Bold + Button@RESUME: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 60 + Width: 140 + Height: 30 + Text: Resume + Font: Bold + Key: escape + Button@SETTINGS: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 100 + Width: 140 + Height: 30 + Text: Settings + Font: Bold + Button@MUSIC: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 140 + Width: 140 + Height: 30 + Text: Music + Font: Bold + Button@SURRENDER: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 180 + Width: 140 + Height: 30 + Text: Surrender + Font: Bold + Button@ABORT_MISSION: + X: (PARENT_RIGHT - WIDTH)/2 + Y: 220 + Width: 140 + Height: 30 + Text: Abort Mission + Font: Bold diff --git a/mods/ra/chrome/ingame-objectives.yaml b/mods/ra/chrome/ingame-objectives.yaml deleted file mode 100644 index 87b6bc02fa..0000000000 --- a/mods/ra/chrome/ingame-objectives.yaml +++ /dev/null @@ -1,98 +0,0 @@ -Background@MISSION_OBJECTIVES: - Logic: MissionObjectivesLogic - X: 25 - Y: 50 - Width: 512 - Height: 530 - Visible: false - 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: 20 - Children: - Container@PRIMARY_OBJECTIVE_TEMPLATE: - X: 15 - Y: 0 - Width: PARENT_RIGHT - 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: 20 - Children: - Container@SECONDARY_OBJECTIVE_TEMPLATE: - X: 15 - Y: 0 - Width: PARENT_RIGHT - 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 - diff --git a/mods/ra/chrome/ingame-observer.yaml b/mods/ra/chrome/ingame-observer.yaml index 06c37dead3..e751dac3f1 100644 --- a/mods/ra/chrome/ingame-observer.yaml +++ b/mods/ra/chrome/ingame-observer.yaml @@ -21,8 +21,8 @@ Container@OBSERVER_WIDGETS: Font: Bold Contrast: true MenuButton@OPTIONS_BUTTON: - MenuContainer: INGAME_OPTIONS_BG - HideIngameUI: false + MenuContainer: INGAME_MENU + HideIngameUI: true Pause: false X: 0 Y: 0 diff --git a/mods/ra/chrome/ingame-player.yaml b/mods/ra/chrome/ingame-player.yaml index fb72542e65..e75d3e083e 100644 --- a/mods/ra/chrome/ingame-player.yaml +++ b/mods/ra/chrome/ingame-player.yaml @@ -3,15 +3,6 @@ Container@PLAYER_WIDGETS: LogicKeyListener@CONTROLGROUP_KEYHANDLER: Logic: ControlGroupLogic LogicTicker@SIDEBAR_TICKER: - Button@OBJECTIVES_BUTTON: - X: 486 - Y: 0 - Width: 160 - Height: 25 - Text: Objectives (O) - Visible: false - Font: Bold - Key: o Container@SUPPORT_POWERS: Logic: SupportPowerBinLogic X: 10 @@ -106,9 +97,6 @@ Container@PLAYER_WIDGETS: ImageCollection: order-icons MenuButton@DEBUG_BUTTON: Logic: AddRaceSuffixLogic - MenuContainer: INGAME_DEBUG_BG - HideIngameUI: false - Pause: false Key: escape Shift X: 128 Width: 28 @@ -144,8 +132,6 @@ Container@PLAYER_WIDGETS: ImageName: diplomacy MenuButton@OPTIONS_BUTTON: Logic: AddRaceSuffixLogic - MenuContainer: INGAME_OPTIONS_BG - HideIngameUI: false Key: escape X: 192 Width: 28 diff --git a/mods/ra/maps/allies-01-classic/allies01.lua b/mods/ra/maps/allies-01-classic/allies01.lua index df16280cdc..d9fbed7ae5 100644 --- a/mods/ra/maps/allies-01-classic/allies01.lua +++ b/mods/ra/maps/allies-01-classic/allies01.lua @@ -105,12 +105,12 @@ CreateEinstein = function() end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) --Media.PlayMovieFullscreen("snowbomb.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("bmap.vqa") end diff --git a/mods/ra/maps/allies-01-classic/map.yaml b/mods/ra/maps/allies-01-classic/map.yaml index 3e9eafda8f..427eb01ffc 100644 --- a/mods/ra/maps/allies-01-classic/map.yaml +++ b/mods/ra/maps/allies-01-classic/map.yaml @@ -574,12 +574,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: allies01.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES TRAN.Extraction: Inherits: TRAN RenderUnit: diff --git a/mods/ra/maps/allies-02-classic/allies02.lua b/mods/ra/maps/allies-02-classic/allies02.lua index 18834f4241..616478a37c 100644 --- a/mods/ra/maps/allies-02-classic/allies02.lua +++ b/mods/ra/maps/allies-02-classic/allies02.lua @@ -23,12 +23,12 @@ RunInitialActivities = function() end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) Media.PlayMovieFullscreen("montpass.vqa") end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) Media.PlayMovieFullscreen("frozen.vqa") end diff --git a/mods/ra/maps/allies-02-classic/map.yaml b/mods/ra/maps/allies-02-classic/map.yaml index c075d75304..ab1c51bbf1 100644 --- a/mods/ra/maps/allies-02-classic/map.yaml +++ b/mods/ra/maps/allies-02-classic/map.yaml @@ -869,12 +869,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: allies02.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES ^Infantry: MustBeDestroyed: ^Tank: diff --git a/mods/ra/maps/intervention/map.yaml b/mods/ra/maps/intervention/map.yaml index 00669d8f17..1a8b95c1c1 100644 --- a/mods/ra/maps/intervention/map.yaml +++ b/mods/ra/maps/intervention/map.yaml @@ -2214,12 +2214,16 @@ Smudges: Rules: Player: -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true World: -CrateSpawner: -SpawnMPUnits: -MPStartLocations: LuaScriptInterface: LuaScripts: mission.lua + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES CAMERA: RevealsShroud: Range: 18c0 diff --git a/mods/ra/maps/intervention/mission.lua b/mods/ra/maps/intervention/mission.lua index ab3f9156f9..36aef85741 100644 --- a/mods/ra/maps/intervention/mission.lua +++ b/mods/ra/maps/intervention/mission.lua @@ -264,9 +264,9 @@ WorldLoaded = function() end MissionFailed = function() - Mission.MissionOver(nil, { player }, false) + Mission.MissionOver(nil, { player }, true) end MissionAccomplished = function() - Mission.MissionOver({ player }, nil, false) + Mission.MissionOver({ player }, nil, true) end diff --git a/mods/ra/maps/koth-athena/map.yaml b/mods/ra/maps/koth-athena/map.yaml index 7dd203f32a..d8a89a439b 100644 --- a/mods/ra/maps/koth-athena/map.yaml +++ b/mods/ra/maps/koth-athena/map.yaml @@ -2113,11 +2113,15 @@ Rules: -Selectable: -TargetableBuilding: Player: + -ConquestVictoryConditions: StrategicVictoryConditions: TicksToHold: 4500 ResetOnHoldLost: true RatioRequired: 1 CriticalRatioRequired: 1 + World: + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Sequences: diff --git a/mods/ra/maps/koth-crossroads/map.yaml b/mods/ra/maps/koth-crossroads/map.yaml index b5e2a96984..71e684ce8e 100644 --- a/mods/ra/maps/koth-crossroads/map.yaml +++ b/mods/ra/maps/koth-crossroads/map.yaml @@ -264,11 +264,15 @@ Rules: -Selectable: -TargetableBuilding: Player: + -ConquestVictoryConditions: StrategicVictoryConditions: TicksToHold: 3000 ResetOnHoldLost: true RatioRequired: 1 CriticalRatioRequired: 1 + World: + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES Sequences: diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 9043bd1e6e..1bb66eab72 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -74,8 +74,12 @@ ChromeLayout: mods/ra/chrome/ingame-chat.yaml mods/ra/chrome/ingame-diplomacy.yaml mods/ra/chrome/ingame-fmvplayer.yaml + mods/ra/chrome/ingame-info.yaml + mods/ra/chrome/ingame-infobriefing.yaml + mods/ra/chrome/ingame-infoobjectives.yaml + mods/ra/chrome/ingame-infostats.yaml + mods/ra/chrome/ingame-leavemap.yaml mods/ra/chrome/ingame-menu.yaml - mods/ra/chrome/ingame-objectives.yaml mods/ra/chrome/ingame-observer.yaml mods/ra/chrome/ingame-observerstats.yaml mods/ra/chrome/ingame-player.yaml @@ -169,6 +173,9 @@ Fonts: Title: Font:mods/ra/ZoodRangmah.ttf Size:48 + MediumBold: + Font:FreeSansBold.ttf + Size:18 BigBold: Font:FreeSansBold.ttf Size:24 diff --git a/mods/ra/rules/player.yaml b/mods/ra/rules/player.yaml index 2ed6bd6b24..fdf86884bc 100644 --- a/mods/ra/rules/player.yaml +++ b/mods/ra/rules/player.yaml @@ -42,6 +42,8 @@ Player: RequireOwner: false PlaceBuilding: SupportPowerManager: + ScriptTriggers: + MissionObjectives: ConquestVictoryConditions: PowerManager: AllyRepair: diff --git a/mods/ra/rules/world.yaml b/mods/ra/rules/world.yaml index 4f34728d95..49cd27c7fd 100644 --- a/mods/ra/rules/world.yaml +++ b/mods/ra/rules/world.yaml @@ -174,4 +174,6 @@ World: DebugPauseState: RadarPings: StartGameNotification: + ObjectivesPanel: + PanelName: SKIRMISH_STATS diff --git a/mods/ra/uibits/buttons.png b/mods/ra/uibits/buttons.png index 9e1491a049..16b9674eb6 100644 Binary files a/mods/ra/uibits/buttons.png and b/mods/ra/uibits/buttons.png differ diff --git a/mods/ts/chrome.yaml b/mods/ts/chrome.yaml index e5e2a87c07..0293e7dfb1 100644 --- a/mods/ts/chrome.yaml +++ b/mods/ts/chrome.yaml @@ -465,7 +465,10 @@ checkbox: dialog.png corner-br: 767,127,1,1 checkbox-bits: buttons.png - checked: 0,140,16,16 + checked: 0,157,16,16 + checked-disabled: 0,173,16,16 + crossed: 16,157,16,16 + crossed-disabled: 16,173,16,16 checkbox-hover: dialog.png background: 641,129,126,126 diff --git a/mods/ts/chrome/ingame-player.yaml b/mods/ts/chrome/ingame-player.yaml index 79c93d15f4..3804db6a7e 100644 --- a/mods/ts/chrome/ingame-player.yaml +++ b/mods/ts/chrome/ingame-player.yaml @@ -3,7 +3,10 @@ Container@PLAYER_WIDGETS: LogicKeyListener@CONTROLGROUP_KEYHANDLER: Logic: ControlGroupLogic LogicTicker@SIDEBAR_TICKER: - Button@INGAME_DIPLOMACY_BUTTON: + MenuButton@DIPLOMACY_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_DIPLOMACY_BG + HideIngameUI: False X: 162 Y: 0 Width: 160 @@ -11,7 +14,9 @@ Container@PLAYER_WIDGETS: Text: Diplomacy (P) Font: Bold Key: p - Button@INGAME_DEBUG_BUTTON: + MenuButton@DEBUG_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_MENU X: 324 Y: 0 Width: 160 @@ -20,15 +25,6 @@ Container@PLAYER_WIDGETS: Visible: false Font: Bold Key: escape Shift - Button@OBJECTIVES_BUTTON: - X: 486 - Y: 0 - Width: 160 - Height: 25 - Text: Objectives (O) - Visible: false - Font: Bold - Key: o SlidingContainer@INGAME_RADAR_BIN: X: WINDOW_RIGHT-215 Y: 0 diff --git a/mods/ts/chrome/ingame.yaml b/mods/ts/chrome/ingame.yaml index bc6ed0b61f..c470852efe 100644 --- a/mods/ts/chrome/ingame.yaml +++ b/mods/ts/chrome/ingame.yaml @@ -46,7 +46,9 @@ Container@INGAME_ROOT: Y: 34 Order: Descending Container@PLAYER_ROOT: - Button@INGAME_OPTIONS_BUTTON: + MenuButton@OPTIONS_BUTTON: + Logic: OrderButtonsChromeLogic + MenuContainer: INGAME_MENU X: 0 Y: 0 Width: 160 diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index bd7ce9714d..e889a0e0ae 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -104,11 +104,15 @@ ChromeLayout: mods/ra/chrome/ingame-diplomacy.yaml mods/ra/chrome/ingame-fmvplayer.yaml mods/ra/chrome/ingame-menu.yaml - mods/ra/chrome/ingame-objectives.yaml + mods/ra/chrome/ingame-info.yaml + mods/ra/chrome/ingame-infobriefing.yaml + mods/ra/chrome/ingame-infoobjectives.yaml + mods/ra/chrome/ingame-infostats.yaml mods/ra/chrome/ingame-observer.yaml mods/ra/chrome/ingame-observerstats.yaml mods/ts/chrome/ingame-player.yaml mods/ra/chrome/ingame-debug.yaml + mods/ra/chrome/ingame-leavemap.yaml mods/ra/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/ra/chrome/credits.yaml diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml index f44970cc41..80a376ccd8 100644 --- a/mods/ts/rules/player.yaml +++ b/mods/ts/rules/player.yaml @@ -26,6 +26,8 @@ Player: LowPowerSlowdown: 3 PlaceBuilding: SupportPowerManager: + ScriptTriggers: + MissionObjectives: ConquestVictoryConditions: PowerManager: AllyRepair: diff --git a/mods/ts/uibits/buttons.png b/mods/ts/uibits/buttons.png index 97cfe0e824..9d48099fb0 100644 Binary files a/mods/ts/uibits/buttons.png and b/mods/ts/uibits/buttons.png differ