diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationGamemode.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationGamemode.cs index ad0a0a902..c7034ba57 100644 --- a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationGamemode.cs +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationGamemode.cs @@ -189,12 +189,12 @@ public override void StopRound() { if (arg.StartsWith("win")) { - Log.Info("Winner in arguments found: " + arg); long factionId; long.TryParse(arg.Remove(0, 3), out factionId); _winningFaction = MyAPIGateway.Session.Factions.TryGetFactionById(factionId); setWinnerFromArgs = true; + Log.Info($"Winner in arguments found: {factionId} ({_winningFaction?.Name})"); break; } } diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationHud.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationHud.cs index 91f3fcbe0..ecbbeccfa 100644 --- a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationHud.cs +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/Elimination/EliminationHud.cs @@ -59,7 +59,8 @@ internal class elmHud_Window : HudElementBase private bool _matchEnded; private readonly MatchTimer _timer; - private readonly LabelBox _timerLabel; + internal readonly LabelBox _timerLabel; + internal LabelBox _winnerLabel; public EliminationHud_TeamBanner[] Banners; public elmHud_Window(HudParentBase parent, EliminationGamemode gamemode) : base(parent) @@ -121,6 +122,7 @@ public void Update() public void MatchEnded(IMyFaction winner) { + Log.Info("EliminationHud.cs:125 MatchEnded (" + winner?.Name + ")"); _matchEnded = true; var winnerPoints = 0; foreach (var banner in Banners) @@ -136,7 +138,7 @@ public void MatchEnded(IMyFaction winner) if (_timerLabel == null) return; - var winnerLabel = new LabelBox(_timerLabel) + _winnerLabel = new LabelBox(_timerLabel) { Text = winner != null ? $"A WINNER IS {winner.Name}. {winnerPoints} tickets remaining." @@ -147,7 +149,7 @@ public void MatchEnded(IMyFaction winner) Color = HudConstants.HudBackgroundColor }; - winnerLabel.TextBoard.SetFormatting(GlyphFormat.White.WithColor(Color.Red).WithSize(3) + _winnerLabel.TextBoard.SetFormatting(GlyphFormat.White.WithColor(Color.Red).WithSize(3) .WithAlignment(TextAlignment.Center)); } } diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHGamemode.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHGamemode.cs new file mode 100644 index 000000000..151ea2ae9 --- /dev/null +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHGamemode.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using Sandbox.ModAPI; +using SC.SUGMA.GameModes.Elimination; +using SC.SUGMA.GameState; +using SC.SUGMA.Utilities; +using VRage.Game.ModAPI; +using VRageMath; + +namespace SC.SUGMA.GameModes.KOTH +{ + internal partial class KOTHGamemode : EliminationGamemode + { + public KOTHSphereZone ControlPoint; + + private Vector3D _controlPointPosition = new Vector3D(0, 0, 0); + private float _controlPointRadius = 2500f; + + private int ActivationTime = 300; + public int ActivationTimeCounter = 0; + + private int WinTime = 120; + + public override string ReadableName { get; internal set; } = "King Of The Hill"; + + public override string Description { get; internal set; } = + "Fight to Control the Capture Point. Either hold it uncontested, or eliminate the enemy team to win."; + + public KOTHGamemode() + { + ArgumentParser += new ArgumentParser( + new ArgumentParser.ArgumentDefinition( + text => ActivationTime = int.Parse(text), + "at", "activation-time", + $"Delay before Center Zone is Capturable, in Seconds" + ), + new ArgumentParser.ArgumentDefinition( + text => WinTime = int.Parse(text), + "wt", "win-time", + "How long a team has to hold the zone uncontested to win, in Seconds" + ) + ); + } + + public override void StartRound(string[] arguments = null) + { + base.StartRound(arguments); + + if (TrackedFactions.Count <= 1) + return; + + ActivationTimeCounter = ActivationTime; + ControlPoint = null; + + if (!MyAPIGateway.Utilities.IsDedicated) + SUGMA_SessionComponent.I.RegisterComponent("KOTHHud", new KOTHHud(this)); + } + + public override void StopRound() + { + _winningFaction = ControlPoint?._zoneOwner; + base.StopRound(); + + SUGMA_SessionComponent.I.GetComponent("KOTHHud")?.MatchEnded(_winningFaction); + SUGMA_SessionComponent.I.UnregisterComponent("KOTHHud"); + + ControlPoint = null; + SUGMA_SessionComponent.I.UnregisterComponent("KOTHZone"); + } + + internal override void DisplayWinMessage() + { + if (_winningFaction == null) + { + MyAPIGateway.Utilities.ShowNotification("YOU ARE ALL LOSERS.", 10000, "Red"); + return; + } + + MyAPIGateway.Utilities.ShowNotification($"A WINNER IS [{_winningFaction?.Name}]!", 10000); + } + + public override void UpdateActive() + { + if (ActivationTimeCounter > 0) + { + if (_matchTimer.Ticks % 60 == 0) + { + ActivationTimeCounter--; + + if (ActivationTimeCounter <= 0) + { + ControlPoint = new KOTHSphereZone(_controlPointPosition, _controlPointRadius, WinTime); + SUGMA_SessionComponent.I.RegisterComponent("KOTHZone", ControlPoint); + } + } + } + + if (ControlPoint == null) + return; + + if (ControlPoint.IsCaptured) + { + StopRound(); + } + } + } +} \ No newline at end of file diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHHud.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHHud.cs new file mode 100644 index 000000000..2a899b44c --- /dev/null +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameModes/KingOfTheHill/KOTHHud.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using RichHudFramework; +using RichHudFramework.Client; +using RichHudFramework.UI; +using RichHudFramework.UI.Client; +using RichHudFramework.UI.Rendering; +using SC.SUGMA.GameModes.Elimination; +using SC.SUGMA.GameState; +using SC.SUGMA.Utilities; +using VRage.Game.ModAPI; +using VRage.Utils; +using VRageMath; + +namespace SC.SUGMA.GameModes.KOTH +{ + internal class KOTHHud : ComponentBase + { + private readonly KOTHGamemode _gamemode; + private KOTHHud_Window _window; + + public KOTHHud(KOTHGamemode gamemode) + { + _gamemode = gamemode; + } + + public override void Init(string id) + { + base.Init(id); + + if (!RichHudClient.Registered) + throw new Exception("RichHudAPI was not initialized in time!"); + + _window = new KOTHHud_Window(HudMain.HighDpiRoot, _gamemode); + } + + public override void Close() + { + HudMain.HighDpiRoot.RemoveChild(_window); + } + + public override void UpdateTick() + { + if (SUGMA_SessionComponent.I.CurrentGamemode != null) + _window.Update(); + } + + public void MatchEnded(IMyFaction winner) + { + _window.MatchEnded(winner); + } + } + + internal class KOTHHud_Window : WindowBase + { + private static readonly Material _circleMaterial = + new Material(MyStringId.GetOrCompute("SugmaCircle"), new Vector2(32, 32)); + + private readonly KOTHGamemode _gamemode; + private readonly elmHud_Window _windowBase; + + private TexturedBox _captureIndicator; + + private Label _captureLabel; + + public KOTHHud_Window(HudParentBase parent, KOTHGamemode gamemode) : base(parent) + { + _gamemode = gamemode; + _windowBase = SUGMA_SessionComponent.I.GetComponent("elmHud").Window; + + _captureIndicator = new TexturedBox(_windowBase) + { + Material = _circleMaterial, + ParentAlignment = ParentAlignments.Bottom | ParentAlignments.Center, + Size = Vector2.One * 32, + Offset = new Vector2(0, -10), + ZOffset = sbyte.MaxValue + }; + + _captureLabel = new Label(_captureIndicator) + { + ParentAlignment = ParentAlignments.Center, + Offset = new Vector2(0, -35), + Text = "Initializing KOTH..." + }; + + foreach (var banner in _windowBase.Banners) + { + banner.Visible = false; + } + } + + public void Update() + { + if (_gamemode.ControlPoint == null) + { + int timeLeft = Math.Max(0, _gamemode.ActivationTimeCounter); + if (timeLeft > 0) + { + _captureIndicator.Color = Color.White; + _captureLabel.Text = $"Zone Locked: {timeLeft}s"; + } + else + { + _captureIndicator.Color = Color.White; + _captureLabel.Text = "Waiting for zone creation..."; + } + return; + } + + var zone = _gamemode.ControlPoint; + + bool isActivelyCapturing = zone.ActiveCapturingFaction != null && zone.CaptureTimeCurrent > 0f; + Color capturingColor = isActivelyCapturing + ? zone.ActiveCapturingFaction.CustomColor.ColorMaskToRgb() + : Color.White; + + _captureIndicator.Color = capturingColor.SetAlphaPct(0.5f); + + float current = zone.CaptureTimeCurrent; + float total = zone.CaptureTime; + + if (!isActivelyCapturing && current > 0f) + { + _captureIndicator.Color = Color.White.SetAlphaPct(0.5f); + } + + _captureLabel.Text = $"Capturing: {current:0.0}s / {total:0.0}s"; + } + + public void MatchEnded(IMyFaction winner) + { + Log.Info("KOTHHud.cs:133 MatchEnded (" + winner?.Name + ")"); + _captureIndicator.Visible = false; + _captureLabel.Visible = false; + + _windowBase._winnerLabel.Visible = false; + _windowBase._winnerLabel = new LabelBox(_windowBase._timerLabel) + { + Text = winner != null + ? $"A WINNER IS {winner.Name}" + : "YOU ARE ALL LOSERS", + ParentAlignment = ParentAlignments.Bottom, + Height = EliminationHud_TeamBanner.BaseHeight, + TextPadding = new Vector2(2.5f, 0), + Color = HudConstants.HudBackgroundColor + }; + _windowBase._winnerLabel.Visible = true; + + _windowBase._winnerLabel.TextBoard.SetFormatting(GlyphFormat.White.WithColor(Color.Red).WithSize(3) + .WithAlignment(TextAlignment.Center)); + } + } +} \ No newline at end of file diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameState/KOTHSphereZone.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameState/KOTHSphereZone.cs new file mode 100644 index 000000000..fe7e3fb0b --- /dev/null +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/GameState/KOTHSphereZone.cs @@ -0,0 +1,112 @@ +using RichHudFramework; +using Sandbox.Game; +using Sandbox.Game.Entities; +using SC.SUGMA.Utilities; +using VRage.Game.ModAPI; +using VRageMath; +using System; +using System.Linq; +using System.Collections.Generic; + +namespace SC.SUGMA.GameState +{ + public class KOTHSphereZone : SphereZone + { + public IMyFaction _zoneOwner; + private Color _baseColor = Color.White.SetAlphaPct(0.25f); + + public bool IsCaptured = false; + public float CaptureTime; + public float CaptureTimeCurrent; + public MySoundPair CaptureSound = new MySoundPair("SUGMA_CaptureSound_TF2"); + + public IMyFaction ActiveCapturingFaction; + + public KOTHSphereZone(Vector3D center, double radius, float captureTime, IMyFaction initialOwner = null) + : base(center, radius) + { + _zoneOwner = initialOwner; + CaptureTime = captureTime; + + SphereDrawColor = (_zoneOwner?.CustomColor.ColorMaskToRgb() ?? Color.White).SetAlphaPct(0.25f); + _baseColor = SphereDrawColor; + } + + public override void UpdateTick() + { + GridFilter = SUGMA_SessionComponent.I.ShareTrackApi.GetTrackedGrids(); + base.UpdateTick(); + + var distinctFactions = new HashSet(); + foreach (var grid in ContainedGrids) + { + var faction = grid.GetFaction(); + if (faction != null) + distinctFactions.Add(faction); + } + + if (distinctFactions.Count == 0) + { + CaptureTimeCurrent = MathHelper.Max(0f, CaptureTimeCurrent - (1f / 120f)); + if (CaptureTimeCurrent <= 0f) + ActiveCapturingFaction = null; + } + else if (distinctFactions.Count > 1) + { + CaptureTimeCurrent = MathHelper.Max(0f, CaptureTimeCurrent - (1f / 120f)); + if (CaptureTimeCurrent <= 0f) + ActiveCapturingFaction = null; + } + else + { + var occupant = distinctFactions.First(); + + if (occupant == _zoneOwner) + { + CaptureTimeCurrent = 0f; + ActiveCapturingFaction = null; + } + else + { + if (ActiveCapturingFaction == null) + { + ActiveCapturingFaction = occupant; + } + else if (ActiveCapturingFaction != occupant) + { + CaptureTimeCurrent = MathHelper.Max(0f, CaptureTimeCurrent - (1f / 60f)); + + if (CaptureTimeCurrent <= 0f) + { + ActiveCapturingFaction = occupant; + CaptureTimeCurrent = 0f; + } + } + + if (ActiveCapturingFaction == occupant) + { + CaptureTimeCurrent += (1f / 60f); + + if (CaptureTimeCurrent >= CaptureTime) + { + _zoneOwner = ActiveCapturingFaction; + CaptureTimeCurrent = 0f; + ActiveCapturingFaction = null; + OnCapture(); + } + } + } + } + + float lerpAmount = (CaptureTime <= 0f ? 0f : CaptureTimeCurrent / CaptureTime); + Color capturingColor = ActiveCapturingFaction?.CustomColor.ColorMaskToRgb() ?? Color.White; + SphereDrawColor = Color.Lerp(_baseColor, capturingColor, lerpAmount).SetAlphaPct(0.25f); + } + + public virtual void OnCapture() + { + IsCaptured = true; + SUtils.PlaySound(CaptureSound); + } + } +} diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/SUGMA_SessionComponent.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/SUGMA_SessionComponent.cs index bc51ba722..b237979cb 100644 --- a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/SUGMA_SessionComponent.cs +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/SUGMA_SessionComponent.cs @@ -10,6 +10,7 @@ using SC.SUGMA.GameModes.Domination; using SC.SUGMA.GameModes.Elimination; using SC.SUGMA.GameModes.TeamDeathmatch; +using SC.SUGMA.GameModes.KOTH; using SC.SUGMA.GameState; using SC.SUGMA.HeartNetworking; using SC.SUGMA.HeartNetworking.Custom; @@ -33,6 +34,7 @@ internal class SUGMA_SessionComponent : MySessionComponentBase ["elm"] = new EliminationGamemode(), ["dom"] = new DominationGamemode(), ["tdm"] = new TeamDeathmatchGamemode(), + ["koth"] = new KOTHGamemode(), }; /// diff --git a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/Utilities/SUtils.cs b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/Utilities/SUtils.cs index 3285df400..aec9bd4a1 100644 --- a/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/Utilities/SUtils.cs +++ b/Gamemode Mods/StarCore SUGMA Gamemodes/Data/Scripts/SUGMA/Utilities/SUtils.cs @@ -49,7 +49,7 @@ public static void SetWorldPermissionsForMatch(bool matchActive) MySessionComponentSafeZones.AllowedActions = CastProhibit(MySessionComponentSafeZones.AllowedActions, matchActive ? MatchPermsInt : FullPermsInt); - if (matchActive && MyAPIGateway.Session.IsServer) + if (matchActive && (MyAPIGateway.Session?.IsServer ?? false)) ClearImageLcds(); } @@ -110,31 +110,42 @@ public static void ClearBoard(bool resetFactions) if (!MyAPIGateway.Session.IsServer) return; - var playerIds = new List(); + var playerIds = new List(); // All players that aren't spectators. foreach (var faction in PlayerTracker.I.GetPlayerFactions()) playerIds.AddRange(faction.Members.Values.Select(player => player.PlayerId)); - var greenSpawn = GetFactionSpawns().FirstOrDefault(b => b.Key.Tag == "NEU").Value; - foreach (var player in PlayerTracker.I.AllPlayers.Where(p => playerIds.Contains(p.Key))) + var factionSpawns = GetFactionSpawns(); + if (factionSpawns.Any(b => b.Key.Tag == "NEU")) { - if (greenSpawn != null) - player.Value.Character?.SetWorldMatrix(greenSpawn.WorldMatrix); - else + var spawnPos = GetFactionSpawns().First(b => b.Key.Tag == "NEU").Value.WorldMatrix.Translation; + spawnPos -= spawnPos.Normalized() * 100; + + foreach (var player in PlayerTracker.I.AllPlayers) + { + (player.Value.Controller.ControlledEntity as IMyCockpit)?.RemovePilot(); + player.Value.Character?.Teleport(MatrixD.CreateWorld(spawnPos + RandVector(-50, 50) * Vector3D.Right)); + } + } + else + { + foreach (var player in PlayerTracker.I.AllPlayers.Where(p => playerIds.Contains(p.Key))) player.Value.Character?.Kill(); } - + SUGMA_SessionComponent.I.StopGamemode(true); + List bufferGroupGrids = new List(); MyAPIGateway.Entities.GetEntities(null, g => { IMyCubeGrid grid = g as IMyCubeGrid; if (grid == null) return false; - // If this ever becomes an issue with deleting existing subgrids, change it to a GridGroup check. - if (!grid.IsStatic) + grid.GetGridGroup(GridLinkTypeEnum.Physical).GetGrids(bufferGroupGrids); // Ignore the spawn stations, blockers, and any grids attached to them. + if (!bufferGroupGrids.Any(attachedGrid => attachedGrid.IsStatic)) grid.Close(); + bufferGroupGrids.Clear(); return false; }); diff --git a/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs b/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs index 9ea961c32..3bcf84387 100644 --- a/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs +++ b/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs @@ -762,6 +762,9 @@ internal class PointAdditions : MySessionComponentBase ["Caster_Reactor"] = 125, ["Heat_Heatsink"] = 10, ["Heat_FlatRadiator"] = 10, + ["ActiveRadiator"] = 250, + ["RadiatorPanel"] = 5, + ["ExtendableRadiatorBase"] = 5, #endregion }; diff --git a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/GridStats.cs b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/GridStats.cs index f0dc41672..205cde8be 100644 --- a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/GridStats.cs +++ b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/GridStats.cs @@ -13,6 +13,11 @@ namespace StarCore.ShareTrack.ShipTracking { internal class GridStats // TODO convert this to be event-driven. OnBlockPlace, etc. Keep a queue. { + private readonly string[] _ignoredIntegrityBlocks = new[] + { + "SC_SRB" + }; + private readonly HashSet _fatBlocks = new HashSet(); private readonly HashSet _slimBlocks; @@ -38,7 +43,7 @@ public GridStats(IMyCubeGrid grid) foreach (var block in _slimBlocks) { - if (block?.FatBlock != null) + if (block?.FatBlock != null && !_ignoredIntegrityBlocks.Contains(block.BlockDefinition.Id.SubtypeName)) { _fatBlocks.Add(block.FatBlock); GridIntegrity += block.Integrity; @@ -72,11 +77,11 @@ public void UpdateAfterSim() { float tempGridInteg = 0; - foreach (var block in _slimBlocks) + foreach (var block in _fatBlocks) { - if (block.FatBlock != null) // Remove To Count All Blocks + if (block != null && !_ignoredIntegrityBlocks.Contains(block.BlockDefinition.SubtypeName)) // Remove To Count All Blocks { - tempGridInteg += block.Integrity; + tempGridInteg += block.SlimBlock.Integrity; } } diff --git a/Utility Mods/MoA Fusion Systems/Data/ActiveRadiatorParticle.sbc b/Utility Mods/MoA Fusion Systems/Data/ActiveRadiatorParticle.sbc index 7f6031369..c908eab58 100644 --- a/Utility Mods/MoA Fusion Systems/Data/ActiveRadiatorParticle.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/ActiveRadiatorParticle.sbc @@ -315,7 +315,7 @@ true - 0 + 1 0 diff --git a/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc b/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc index b9195b695..47d25cb99 100644 --- a/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc @@ -7,7 +7,7 @@ Fusion Systems - FusionSystems + Fusion Systems Caster_Accelerator_0 Caster_Accelerator_90 diff --git a/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc b/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc index 491910d46..d915be8dc 100644 --- a/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc @@ -35,6 +35,7 @@ + X \ No newline at end of file diff --git a/Utility Mods/MoA Fusion Systems/Data/ctf_score_background.sbc b/Utility Mods/MoA Fusion Systems/Data/HudTextures.sbc similarity index 71% rename from Utility Mods/MoA Fusion Systems/Data/ctf_score_background.sbc rename to Utility Mods/MoA Fusion Systems/Data/HudTextures.sbc index 0e6538197..dadd3556e 100644 --- a/Utility Mods/MoA Fusion Systems/Data/ctf_score_background.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/HudTextures.sbc @@ -25,5 +25,17 @@ 0.1 Textures\fusionBarBackground.dds + + + TransparentMaterialDefinition + HudBackground + + false + 1 + false + false + 0.1 + Textures\HudBackground.dds + diff --git a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/FusionWindow.cs b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/FusionWindow.cs new file mode 100644 index 000000000..9d9df4b8f --- /dev/null +++ b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/FusionWindow.cs @@ -0,0 +1,260 @@ +using Epstein_Fusion_DS.Communication; +using Epstein_Fusion_DS.FusionParts; +using Epstein_Fusion_DS.HeatParts; +using RichHudFramework.UI; +using RichHudFramework.UI.Rendering; +using RichHudFramework.UI.Rendering.Client; +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VRage.Game.Entity; +using VRage.Game.ModAPI; +using VRageMath; + +namespace Epstein_Fusion_DS.HudHelpers +{ + internal class FusionWindow : CamSpaceNode + { + private readonly TexturedBox _backgroundBox, _foregroundBox, _heatBox, _storBox; + private readonly Label _heatLabel, _storageLabel, _infoLabelLeft; + + private readonly GlyphFormat _stdTextFormat = new GlyphFormat(color: HudConstants.HudTextColor, alignment: TextAlignment.Center, font: FontManager.GetFont("Monospace")); + private readonly GlyphFormat _stdTextFormatInfo = new GlyphFormat(color: HudConstants.HudTextColor, textSize: 0.6f, alignment: TextAlignment.Left, font: FontManager.GetFont("Monospace")); + + public FusionWindow(HudParentBase parent) : base(parent) + { + RotationAxis = new Vector3(0, 1, 0); + RotationAngle = 0.25f; + TransformOffset = new Vector3D(-0.0675, -0.04, -0.05); + + _backgroundBox = new TexturedBox(this) + { + Material = new Material("WhiteSquare", HudConstants.HudSize), + Size = HudConstants.HudSize, + Color = HudConstants.HudBackgroundColor, + IsMasking = true, + ZOffset = sbyte.MinValue, + Padding = Vector2.Zero, + }; + _foregroundBox = new TexturedBox(this) + { + Material = new Material("HudBackground", new Vector2(400, 136)), + Size = HudConstants.HudSize, + ZOffset = sbyte.MaxValue, + }; + + _heatLabel = new Label(this) + { + Text = "00% HEAT", + Offset = new Vector2(0, 0), + Format = _stdTextFormat, + ZOffset = sbyte.MaxValue, + }; + _storageLabel = new Label(this) + { + Text = "00% STOR", + Offset = new Vector2(0, -_backgroundBox.Size.Y/3), + Format = _stdTextFormat, + ZOffset = sbyte.MaxValue, + }; + + _infoLabelLeft = new Label(this) + { + Text = "100% INTEGRITY - ALL SYSTEMS NOMINAL", + Offset = new Vector2(0, _backgroundBox.Size.Y/3), + Format = _stdTextFormat, + ZOffset = sbyte.MaxValue, + }; + + _heatBox = new TexturedBox(_backgroundBox) + { + Material = new Material("WhiteSquare", new Vector2(384, 38) * HudConstants.HudSizeRatio), + Size = new Vector2(384, 38) * HudConstants.HudSizeRatio, + ParentAlignment = ParentAlignments.Left | ParentAlignments.Top | ParentAlignments.Inner, + Offset = new Vector2(8, -49) * HudConstants.HudSizeRatio, + ZOffset = 0, + Color = Color.Red, + }; + + _storBox = new TexturedBox(_backgroundBox) + { + Material = new Material("WhiteSquare", new Vector2(384, 38) * HudConstants.HudSizeRatio), + Size = new Vector2(384, 38) * HudConstants.HudSizeRatio, + ParentAlignment = ParentAlignments.Left | ParentAlignments.Top | ParentAlignments.Inner, + Offset = new Vector2(8, -95) * HudConstants.HudSizeRatio, + ZOffset = 0, + Color = Color.Orange, + }; + } + + + private static ModularDefinitionApi ModularApi => Epstein_Fusion_DS.ModularDefinition.ModularApi; + private int _ticks = 0; + private bool _shouldHide; + private MyEntity3DSoundEmitter _soundEmitter = null; + private readonly MySoundPair _alertSound = new MySoundPair("ArcSoundBlockAlert2"); + + public void Update() + { + _ticks++; + var playerCockpit = MyAPIGateway.Session?.Player?.Controller?.ControlledEntity?.Entity as IMyShipController; + + // Pulling the current HudState is SLOOOOWWWW, so we only pull it when tab is just pressed. + //if (MyAPIGateway.Input.IsNewKeyPressed(MyKeys.Tab)) + // _shouldHide = MyAPIGateway.Session?.Config?.HudState != 1; + + // Hide HUD element if the player isn't in a cockpit + if (playerCockpit == null || _shouldHide) + { + if (Visible) Visible = false; + + if (_soundEmitter != null) + { + _soundEmitter.StopSound(true); + _soundEmitter = null; + } + return; + } + + var playerGrid = playerCockpit.CubeGrid; + + float totalFusionCapacity = 0; + float totalFusionGeneration = 0; + float totalFusionStored = 0; + float reactorIntegrity = 0; + int reactorCount = 0; + + foreach (var system in SFusionManager.I.FusionSystems) + { + if (playerGrid != ModularApi.GetAssemblyGrid(system.Key)) + continue; + + totalFusionCapacity += system.Value.MaxPowerStored; + totalFusionGeneration += system.Value.PowerGeneration; + totalFusionStored += system.Value.PowerStored; + foreach (var reactor in system.Value.Reactors) + { + reactorIntegrity += reactor.Block.SlimBlock.Integrity/reactor.Block.SlimBlock.MaxIntegrity; + reactorCount++; + } + foreach (var thruster in system.Value.Thrusters) + { + reactorIntegrity += thruster.Block.SlimBlock.Integrity/thruster.Block.SlimBlock.MaxIntegrity; + reactorCount++; + } + } + reactorIntegrity /= reactorCount; + + // Hide HUD element if the grid has no fusion systems (capacity is always >0 for a fusion system) + if (totalFusionCapacity == 0) + { + if (Visible) Visible = false; + return; + } + + // Show otherwise + if (!Visible) Visible = true; + + var heatPct = HeatManager.I.GetGridHeatLevel(playerGrid); + + _heatBox.Width = 384 * HudConstants.HudSizeRatio.X * heatPct; + _heatBox.Color = new Color(heatPct, 1-heatPct, 0, 0.75f); + + _storBox.Width = 384 * HudConstants.HudSizeRatio.X * (totalFusionStored / totalFusionCapacity); + + _infoLabelLeft.Text = new RichText + { + {(reactorIntegrity*100).ToString("N0") + "%", _stdTextFormatInfo.WithColor(reactorIntegrity > 0.6 ? Color.White : Color.Red)}, + {" INTEGRITY - ", _stdTextFormatInfo}, + {GetNoticeText(heatPct, reactorIntegrity), GetNoticeFormat(heatPct, reactorIntegrity)}, + }; + + _heatLabel.Text = $"{heatPct*100:N0}% HEAT"; + _storageLabel.Text = $"{(totalFusionStored / totalFusionCapacity) * 100:N0}% STOR"; + + if (heatPct > 0.8f) + { + if (_soundEmitter == null) + { + _soundEmitter = new MyEntity3DSoundEmitter((MyEntity) playerCockpit.Entity) + { + CanPlayLoopSounds = true + }; + _soundEmitter.PlaySound(_alertSound); + } + } + else + { + if (_soundEmitter != null) + { + _soundEmitter.StopSound(true); + _soundEmitter = null; + } + } + } + + private int _errRemainingTicks = 0; + private float _lastIntegrityPct = 1; + private string _lastErrText = ""; + private string GetNoticeText(float heatPct, float integrityPct) + { + if (integrityPct < _lastIntegrityPct && _errRemainingTicks == 0) + _errRemainingTicks = Utils.Random.Next(60, 120); + //_lastIntegrityPct = integrityPct; + + string baseText = "ALL SYSTEMS NOMINAL"; + char[] errArray = new[] + { + '?', + '░', + '▒', + '▓', + '█', + '*', + '%', + '@', + }; + + if (integrityPct < 0.1) + baseText = " I DON'T WANT TO DIE. "; + else if (integrityPct < 0.5) + baseText = " -! REACTOR FAILURE !- "; + else if (integrityPct < 0.6) + baseText = "-! SHUTDOWN IMMINENT !-"; + else if (heatPct > 0.8) + baseText = " ! THERMAL DAMAGE ! "; + + if (_errRemainingTicks > 0 || integrityPct < 0.6) + { + if (_errRemainingTicks % 4 == 0) + { + var chars = baseText.ToCharArray(); + for (int i = Utils.Random.Next(0, baseText.Length/4); i < baseText.Length; i += Utils.Random.Next(1, baseText.Length/2)) + chars[i] = errArray[Utils.Random.Next(0, errArray.Length - 1)]; + baseText = new string(chars); + _lastErrText = baseText; + } + else + { + baseText = _lastErrText; + } + _errRemainingTicks--; + } + + return baseText; + } + + private GlyphFormat GetNoticeFormat(float heatPct, float integrityPct) + { + if (integrityPct < 0.6 || heatPct > 0.8) + return _stdTextFormatInfo.WithColor(Color.Red); + else if (_errRemainingTicks > 0) + return _stdTextFormatInfo.WithColor(Color.Yellow); + return _stdTextFormatInfo; + } + } +} diff --git a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/HudConstants.cs b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/HudConstants.cs new file mode 100644 index 000000000..cab42a67e --- /dev/null +++ b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HudHelpers/HudConstants.cs @@ -0,0 +1,20 @@ +using RichHudFramework.UI.Rendering; +using VRageMath; + +namespace Epstein_Fusion_DS.HudHelpers +{ + /// + /// HUD constants class for Fusion Systems + /// + public static class HudConstants + { + public static readonly Color HudBackgroundColor = new Color(255, 255, 255, 40); + public static readonly Color HudTextColor = Color.White; + public static Vector2 HudSize = new Vector2(300, 102); + public static Vector2 HudSizeRatio = HudSize / new Vector2(400, 136); + + //public static Material BackgroundMaterial = new Material("HudBackground", new Vector2(435, 102)); + + //public static Vector2 HudAngle = new Vector2( + } +} diff --git a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/S_FusionPlayerHud.cs b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/S_FusionPlayerHud.cs index e21fca76b..76f6d0a24 100644 --- a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/S_FusionPlayerHud.cs +++ b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/S_FusionPlayerHud.cs @@ -21,7 +21,7 @@ public class SFusionPlayerHud : MySessionComponentBase public static SFusionPlayerHud I; private int _ticks; - private ConsumptionBar _consumptionBar; + private FusionWindow _fusionHud; private static ModularDefinitionApi ModularApi => Epstein_Fusion_DS.ModularDefinition.ModularApi; private static SFusionManager FusionManager => SFusionManager.I; private static HeatManager HeatManager => HeatManager.I; @@ -53,15 +53,17 @@ public override void UpdateAfterSimulation() _ticks++; try { - if (_consumptionBar == null && RichHudClient.Registered) - _consumptionBar = new ConsumptionBar(HudMain.HighDpiRoot) + if (_fusionHud == null && RichHudClient.Registered) + { + _fusionHud = new FusionWindow(HudMain.HighDpiRoot) { Visible = true - }; + }; + } HeatManager.UpdateTick(); FusionManager.UpdateTick(); - _consumptionBar?.Update(); + _fusionHud?.Update(); if (ModularApi.IsDebug()) { diff --git a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/Utils.cs b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/Utils.cs index 50d5541e1..466ec002b 100644 --- a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/Utils.cs +++ b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/Utils.cs @@ -1,9 +1,12 @@ -using VRageMath; +using System; +using VRageMath; namespace Epstein_Fusion_DS { public static class Utils { + public static Random Random = new Random(); + // TODO make this less inefficient. public static Matrix RotateMatrixAroundPoint(Matrix matrix, Vector3D point, Vector3D axis, double angleRadians) { diff --git a/Utility Mods/MoA Fusion Systems/Textures/HudBackground.dds b/Utility Mods/MoA Fusion Systems/Textures/HudBackground.dds new file mode 100644 index 000000000..1e517cff8 Binary files /dev/null and b/Utility Mods/MoA Fusion Systems/Textures/HudBackground.dds differ diff --git a/Utility Mods/MoA Fusion Systems/Textures/HudBackground.pdn b/Utility Mods/MoA Fusion Systems/Textures/HudBackground.pdn new file mode 100644 index 000000000..5765d762b Binary files /dev/null and b/Utility Mods/MoA Fusion Systems/Textures/HudBackground.pdn differ diff --git a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs index 7b821d10f..4822e35e5 100644 --- a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs +++ b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs @@ -34,6 +34,7 @@ public class Generator_Settings public float MinPowerDraw = 50.00f; public int MaxSiegeTime = 60; + public int MinSiegeTime = 15; public int SiegePowerDraw = 900; public float SiegeModeResistence = 0.9f; @@ -56,6 +57,7 @@ void LoadConfig(MyIni iniParser) MinPowerDraw = iniParser.Get(IniSection, nameof(MinPowerDraw)).ToSingle(MinPowerDraw); MaxSiegeTime = iniParser.Get(IniSection, nameof(MaxSiegeTime)).ToInt32(MaxSiegeTime); + MinSiegeTime = iniParser.Get(IniSection, nameof(MinSiegeTime)).ToInt32(MinSiegeTime); SiegePowerDraw = iniParser.Get(IniSection, nameof(SiegePowerDraw)).ToInt32(SiegePowerDraw); SiegeModeResistence = iniParser.Get(IniSection, nameof(SiegeModeResistence)).ToSingle(SiegeModeResistence); diff --git a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs index ab5b00db3..cb8c55567 100644 --- a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs +++ b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs @@ -471,7 +471,7 @@ private void EndSiegeMode() SiegeBlockEnabler(Block.CubeGrid.GetFatBlocks(), true); - SiegeCooldownTime.Value = (SiegeElapsedTime.Value > 5) ? (SiegeElapsedTime.Value * 2) : 5; + SiegeCooldownTime.Value = (SiegeElapsedTime.Value > Config.MinSiegeTime) ? (SiegeElapsedTime.Value * 2) : Config.MinSiegeTime; SiegeElapsedTime.Value = 0; SiegeCooldownActive.Value = true; } diff --git a/Utility Mods/SC_Season_4_Adjustments/Data/AiRange_EntityComponents.sbc b/Utility Mods/SC_Season_4_Adjustments/Data/AiRange_EntityComponents.sbc new file mode 100644 index 000000000..b32182fb9 --- /dev/null +++ b/Utility Mods/SC_Season_4_Adjustments/Data/AiRange_EntityComponents.sbc @@ -0,0 +1,111 @@ + + + + + + + BasicMissionFollowHome + BasicMissionBlock + + 2 + 0 + 19990 + 0 + 1 + 20000 + 1000 + + + + EventDistanceToLockedTarget + EventControllerBlockComponent + + 22 + 25000 + 25000 + + + + + OffensiveCombatCircleOrbit + OffensiveCombatBlock + + 0 + 100 + 20000 + 2 + + + + OffensiveCombatHitAndRun + OffensiveCombatBlock + + 5000 + 10000 + 2 + 90 + 2 + + + + OffensiveCombatIntercept + OffensiveCombatBlock + + 3 + + + + OffensiveCombatStayAtRange + OffensiveCombatBlock + + 2 + 1 + + + + + SearchEnemyComponent + DefaultEnemySearch + + 20000 + + + diff --git a/Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl b/Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl.disabled similarity index 99% rename from Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl rename to Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl.disabled index 444c291d7..0f65db8c4 100644 --- a/Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl +++ b/Weapon Mods/40k-Weapons-Mod/Data/Animation/NEC_Whip_Crystal.bsl.disabled @@ -30,4 +30,4 @@ action Block() { API.stoploop("rotateCrystal") API.stoploop("bounceCrystal") } -} \ No newline at end of file +} diff --git a/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info b/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info deleted file mode 100644 index 671be8d7d..000000000 --- a/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info +++ /dev/null @@ -1 +0,0 @@ -Animation NEC_Whip_Crystal \ No newline at end of file diff --git a/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info.disabled b/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info.disabled new file mode 100644 index 000000000..5dc7658b9 --- /dev/null +++ b/Weapon Mods/40k-Weapons-Mod/Data/Animation/main.info.disabled @@ -0,0 +1 @@ +Animation NEC_Whip_Crystal diff --git a/Weapon Mods/Starcore_Serpent_Arms_Heavy_Metal/Data/Scripts/CoreParts/Charon.cs b/Weapon Mods/Starcore_Serpent_Arms_Heavy_Metal/Data/Scripts/CoreParts/Charon.cs index 7a5721d15..3a9db9986 100644 --- a/Weapon Mods/Starcore_Serpent_Arms_Heavy_Metal/Data/Scripts/CoreParts/Charon.cs +++ b/Weapon Mods/Starcore_Serpent_Arms_Heavy_Metal/Data/Scripts/CoreParts/Charon.cs @@ -94,8 +94,8 @@ partial class Parts { { RotateRate = 0.013f, // Max traversal speed of azimuth subpart in radians per tick (0.1 is approximately 360 degrees per second). ElevateRate = 0.0075f, // Max traversal speed of elevation subpart in radians per tick. - MinAzimuth = -180, - MaxAzimuth = 180, + MinAzimuth = -45, + MaxAzimuth = 45, MinElevation = -13, MaxElevation = 45, HomeAzimuth = 0, // Default resting rotation angle