diff --git a/Source/Client/Comp/Map/MultiplayerMapComp.cs b/Source/Client/Comp/Map/MultiplayerMapComp.cs index 534cdf64..e9e77de1 100644 --- a/Source/Client/Comp/Map/MultiplayerMapComp.cs +++ b/Source/Client/Comp/Map/MultiplayerMapComp.cs @@ -35,12 +35,12 @@ public MultiplayerMapComp(Map map) sessionManager = new(map); } - public CaravanFormingSession CreateCaravanFormingSession(bool reform, Action onClosed, bool mapAboutToBeRemoved, IntVec3? meetingSpot = null) + public CaravanFormingSession CreateCaravanFormingSession(Faction faction, bool reform, Action onClosed, bool mapAboutToBeRemoved, IntVec3? meetingSpot = null) { var caravanForming = sessionManager.GetFirstOfType(); if (caravanForming == null) { - caravanForming = new CaravanFormingSession(map, reform, onClosed, mapAboutToBeRemoved, meetingSpot); + caravanForming = new CaravanFormingSession(faction, map, reform, onClosed, mapAboutToBeRemoved, meetingSpot); if (!sessionManager.AddSession(caravanForming)) { // Shouldn't happen if the session doesn't exist already, show an error just in case @@ -51,12 +51,12 @@ public CaravanFormingSession CreateCaravanFormingSession(bool reform, Action onC return caravanForming; } - public TransporterLoading CreateTransporterLoadingSession(List transporters) + public TransporterLoading CreateTransporterLoadingSession(Faction faction, List transporters) { var transporterLoading = sessionManager.GetFirstOfType(); if (transporterLoading == null) { - transporterLoading = new TransporterLoading(map, transporters); + transporterLoading = new TransporterLoading(faction, map, transporters); if (!sessionManager.AddSession(transporterLoading)) { // Shouldn't happen if the session doesn't exist already, show an error just in case diff --git a/Source/Client/Persistent/CaravanFormingPatches.cs b/Source/Client/Persistent/CaravanFormingPatches.cs index 9dab7444..bdd9e7b2 100644 --- a/Source/Client/Persistent/CaravanFormingPatches.cs +++ b/Source/Client/Persistent/CaravanFormingPatches.cs @@ -7,6 +7,7 @@ using UnityEngine; using Verse; using static Verse.Widgets; +using System.Reflection; namespace Multiplayer.Client.Persistent { @@ -168,25 +169,27 @@ static void Prefix(Dialog_FormCaravan __instance, Map map, bool reform, Action o if (__instance.GetType() != typeof(Dialog_FormCaravan)) return; + Faction faction = Faction.OfPlayer; + // Handles showing the dialog from TimedForcedExit.CompTick -> TimedForcedExit.ForceReform // (note TimedForcedExit is obsolete) if (Multiplayer.ExecutingCmds || Multiplayer.Ticking) { var comp = map.MpComp(); if (comp.sessionManager.GetFirstOfType() == null) - comp.CreateCaravanFormingSession(reform, onClosed, mapAboutToBeRemoved, designatedMeetingPoint); + comp.CreateCaravanFormingSession(faction, reform, onClosed, mapAboutToBeRemoved, designatedMeetingPoint); } else // Handles opening from the interface: forming gizmos, reforming gizmos and caravan hitching spots { - StartFormingCaravan(map, reform, designatedMeetingPoint); + StartFormingCaravan(faction, map, reform, designatedMeetingPoint); } } [SyncMethod] - internal static void StartFormingCaravan(Map map, bool reform = false, IntVec3? designatedMeetingPoint = null, int? routePlannerWaypoint = null) + internal static void StartFormingCaravan(Faction faction, Map map, bool reform = false, IntVec3? designatedMeetingPoint = null, int? routePlannerWaypoint = null) { var comp = map.MpComp(); - var session = comp.CreateCaravanFormingSession(reform, null, false, designatedMeetingPoint); + var session = comp.CreateCaravanFormingSession(faction, reform, null, false, designatedMeetingPoint); if (TickPatch.currentExecutingCmdIssuedBySelf) { @@ -224,7 +227,7 @@ static bool Prefix(Map origin, int tile) return true; // Override behavior in multiplayer - DialogFormCaravanCtorPatch.StartFormingCaravan(origin, routePlannerWaypoint: tile); + DialogFormCaravanCtorPatch.StartFormingCaravan(Faction.OfPlayer, origin, routePlannerWaypoint: tile); return false; } @@ -241,4 +244,101 @@ static bool Prefix(TimedForcedExit __instance) return true; } } + + [HarmonyPatch()] + static class DisableCaravanFormCheckboxForOtherFactions + { + static MethodInfo TargetMethod() { + return typeof(Widgets).GetMethod("Checkbox", [ + typeof(Vector2), typeof(bool).MakeByRefType(), typeof(float), typeof(bool), typeof(bool), typeof(Texture2D), typeof(Texture2D) + ]); + } + + static bool Prefix(Vector2 topLeft, bool checkOn, bool disabled) + { + if (CaravanFormingProxy.drawing == null || CaravanFormingProxy.drawing.Session?.faction == Multiplayer.RealPlayerFaction) + return true; + + if (disabled) + return true; + + Widgets.Checkbox(topLeft, ref checkOn, disabled: true); + return false; + } + } + + [HarmonyPatch()] + static class DisableCaravanFormSuppliesCheckboxForOtherFactions + { + static MethodInfo TargetMethod() { + return typeof(Widgets).GetMethod("CheckboxLabeled", [ + typeof(Rect), typeof(string), typeof(bool).MakeByRefType(), typeof(bool), typeof(Texture2D), typeof(Texture2D), typeof(bool), typeof(bool) + ]); + } + + static bool Prefix(Rect rect, string label, bool checkOn, bool disabled) + { + if (CaravanFormingProxy.drawing == null || CaravanFormingProxy.drawing.Session?.faction == Multiplayer.RealPlayerFaction) + return true; + + if (disabled || label != "AutomaticallySelectTravelSupplies".Translate()) + return true; + + Widgets.CheckboxLabeled(rect, label, ref checkOn, disabled: true, null, null, placeCheckboxNearText: true); + return false; + } + } + + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonText), typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool), typeof(TextAnchor))] + static class DisableCaravanFormControlButtonsForOtherFactions + { + static bool Prefix(Rect rect, string label, ref bool __result) + { + if (CaravanFormingProxy.drawing == null || CaravanFormingProxy.drawing.Session?.faction == Multiplayer.RealPlayerFaction) + return true; + + if (label != "ResetButton".Translate() && label != "CancelButton".Translate() && label != "ChangeRouteButton".Translate() && label != "Send".Translate()) + return true; + + __result = false; + return false; + } + } + + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonText))] + [HarmonyPatch(new[] { typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool), typeof(TextAnchor) })] + static class DisableCaravanFormCountButtonsForOtherFactions + { + static bool Prefix(Rect rect, string label, ref bool __result) + { + if (CaravanFormingProxy.drawing == null || CaravanFormingProxy.drawing.Session?.faction == Multiplayer.RealPlayerFaction) + return true; + + if (label != "0" && label != "M<" && label != "<<" && label != "<" && label != ">" && label != ">>" && label != ">M") + return true; + + GUI.color = Widgets.InactiveColor; + Widgets.TextArea(rect, label, true); + GUI.color = Color.white; + __result = false; + return false; + } + } + + [HarmonyPatch()] + static class DisableCaravanFormCountTextBoxForOtherFactions + { + static MethodInfo TargetMethod() { + return typeof(Widgets).GetMethod("TextFieldNumeric", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(typeof(int)); + } + static bool Prefix(Rect rect, int val) + { + if (CaravanFormingProxy.drawing == null || CaravanFormingProxy.drawing.Session?.faction == Multiplayer.RealPlayerFaction) + return true; + + GUI.color = Color.white; + Widgets.TextArea(rect, val.ToString(), true); + return false; + } + } } diff --git a/Source/Client/Persistent/CaravanFormingSession.cs b/Source/Client/Persistent/CaravanFormingSession.cs index fd1fc32a..a0a4b69e 100644 --- a/Source/Client/Persistent/CaravanFormingSession.cs +++ b/Source/Client/Persistent/CaravanFormingSession.cs @@ -11,6 +11,8 @@ public class CaravanFormingSession : ExposableSession, ISessionWithTransferables { public Map map; + public Faction faction; + public bool reform; public Action onClosed; public bool mapAboutToBeRemoved; @@ -24,12 +26,13 @@ public class CaravanFormingSession : ExposableSession, ISessionWithTransferables public override Map Map => map; - public CaravanFormingSession(Map map) : base(map) + public CaravanFormingSession(Faction faction, Map map) : base(map) { this.map = map; + this.faction = faction; } - public CaravanFormingSession(Map map, bool reform, Action onClosed, bool mapAboutToBeRemoved, IntVec3? meetingSpot = null) : this(map) + public CaravanFormingSession(Faction faction, Map map, bool reform, Action onClosed, bool mapAboutToBeRemoved, IntVec3? meetingSpot = null) : this(faction, map) { this.reform = reform; this.onClosed = onClosed; diff --git a/Source/Client/Persistent/Trading.cs b/Source/Client/Persistent/Trading.cs index 1092848c..775a3e7a 100644 --- a/Source/Client/Persistent/Trading.cs +++ b/Source/Client/Persistent/Trading.cs @@ -22,6 +22,8 @@ public class MpTradeSession : ExposableSession, ISessionWithTransferables, ISess public MpTradeDeal deal; public bool giftsOnly; + public Faction NegotiatorFaction => playerNegotiator?.Faction; + public string Label { get diff --git a/Source/Client/Persistent/TradingUI.cs b/Source/Client/Persistent/TradingUI.cs index b0150dfb..822bd367 100644 --- a/Source/Client/Persistent/TradingUI.cs +++ b/Source/Client/Persistent/TradingUI.cs @@ -48,7 +48,7 @@ public override void DoWindowContents(Rect inRect) if (selectedTab == -1 && trading.Count > 0) selectedTab = 0; - if (selectedTab == -1) + if (selectedTab == -1 || tabs.Count == 0) { Close(); return; @@ -56,7 +56,7 @@ public override void DoWindowContents(Rect inRect) int rows = Mathf.CeilToInt(tabs.Count / 3f); inRect.yMin += rows * TabDrawer.TabHeight + 3; - TabDrawer.DrawTabs(inRect, tabs, rows); + TabDrawer.DrawTabs(inRect, tabs); inRect.yMin += 10f; @@ -67,8 +67,10 @@ public override void DoWindowContents(Rect inRect) selectedSession = session.SessionId; } + Faction factionContext = session.NegotiatorFaction; try { + factionContext = FactionContext.Push(factionContext); MpTradeSession.SetTradeSession(session); drawingTrade = this; @@ -124,6 +126,9 @@ public override void DoWindowContents(Rect inRect) { drawingTrade = null; MpTradeSession.SetTradeSession(null); + if (factionContext != null) { + FactionContext.Pop(); + } } } @@ -246,6 +251,77 @@ public static List AllTradeables() } } + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonText), typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool), typeof(TextAnchor))] + static class DisableTradeControlButtonsForOtherFactions + { + static bool Prefix(Rect rect, string label, ref bool __result) + { + if (TradingWindow.drawingTrade == null || MpTradeSession.current.NegotiatorFaction == Multiplayer.RealPlayerFaction) + return true; + + if (label != "ResetButton".Translate() && label != "CancelButton".Translate() && label != "OfferGifts".Translate() && label != "AcceptButton".Translate()) + return true; + + __result = false; + return false; + } + } + + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonImageWithBG))] + static class DisableTradeModeButtonForOtherFactions + { + private static readonly Texture2D GiftModeIcon = ContentFinder.Get("UI/Buttons/GiftMode"); + private static readonly Texture2D TradeModeIcon = ContentFinder.Get("UI/Buttons/TradeMode"); + + static bool Prefix(Rect butRect, Texture2D image, ref bool __result) + { + if (TradingWindow.drawingTrade == null || MpTradeSession.current.NegotiatorFaction == Multiplayer.RealPlayerFaction) + return true; + + if (image != GiftModeIcon && image != TradeModeIcon) + return true; + + __result = false; + return false; + } + } + + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonText), typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool), typeof(TextAnchor))] + static class DisableTradeCountButtonsForOtherFactions + { + static bool Prefix(Rect rect, string label, ref bool __result) + { + if (TradingWindow.drawingTrade == null || MpTradeSession.current.NegotiatorFaction == Multiplayer.RealPlayerFaction) + return true; + + if (label != "0" && label != "M<" && label != "<<" && label != "<" && label != ">" && label != ">>" && label != ">M") + return true; + + GUI.color = Widgets.InactiveColor; + Widgets.TextArea(rect, label, true); + GUI.color = Color.white; + __result = false; + return false; + } + } + + [HarmonyPatch()] + static class DisableTradeCountTextBoxForOtherFactions + { + static MethodInfo TargetMethod() { + return typeof(Widgets).GetMethod("TextFieldNumeric", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(typeof(int)); + } + static bool Prefix(Rect rect, int val) + { + if (TradingWindow.drawingTrade == null || MpTradeSession.current.NegotiatorFaction == Multiplayer.RealPlayerFaction) + return true; + + GUI.color = Color.white; + Widgets.TextArea(rect, val.ToString(), true); + return false; + } + } + [HarmonyPatch(typeof(Widgets), nameof(Widgets.ButtonTextWorker))] static class MakeCancelTradeButtonRed { diff --git a/Source/Client/Persistent/TransporterLoadingPatches.cs b/Source/Client/Persistent/TransporterLoadingPatches.cs index cc9401b9..1b165711 100644 --- a/Source/Client/Persistent/TransporterLoadingPatches.cs +++ b/Source/Client/Persistent/TransporterLoadingPatches.cs @@ -133,10 +133,85 @@ static void Prefix(Dialog_LoadTransporters __instance, Map map, List transporters; public List pods; public List transferables; public bool uiDirty; - public TransporterLoading(Map map) : base(map) + public TransporterLoading(Faction faction, Map map) : base(map) { this.map = map; + this.faction = faction; } - public TransporterLoading(Map map, List transporters) : this(map) + public TransporterLoading(Faction faction, Map map, List transporters) : this(faction, map) { this.transporters = transporters; pods = transporters.Select(t => t.parent).ToList();