diff --git a/Source/RimWar/Harmony/HarmonyPatches.cs b/Source/RimWar/Harmony/HarmonyPatches.cs index de4f490..09c20f3 100644 --- a/Source/RimWar/Harmony/HarmonyPatches.cs +++ b/Source/RimWar/Harmony/HarmonyPatches.cs @@ -26,15 +26,59 @@ namespace RimWar.Harmony // static HarmonyPatches() // { + [StaticConstructorOnStartup] public class RimWarMod : Mod { + private readonly string ModId = "rimworld.torann.rimwar"; public static int RimpointsPerGift = 90; private static readonly Type patchType = typeof(RimWarMod); + private HarmonyLib.Harmony harmonyInstance; + + private void PatchHarmonyMethod(Type rimworldMethodType, + string rimworldMethodName, + Type[] prms = null, + HarmonyMethod prefixMethod = null, + HarmonyMethod postfixMethod = null, + HarmonyMethod transpilerMethod = null) + { + MethodInfo targetMethod = AccessTools.Method(rimworldMethodType, rimworldMethodName, prms, null); + Patches info = HarmonyLib.Harmony.GetPatchInfo(targetMethod); + if (info != null) { + if (prefixMethod != null) { + foreach (Patch patch in info.Prefixes) + { + if (patch.owner != ModId) + Log.Warning(string.Format("[RimWar] Possible mod conflict detected: Mod {0} also patches {1}.", + patch.owner, targetMethod.Name)); + } + } + if (postfixMethod != null) { + foreach (Patch patch in info.Postfixes) + { + if (patch.owner != ModId) + Log.Warning(string.Format("[RimWar] Possible mod conflict detected: Mod {0} also patches {1}.", + patch.owner, targetMethod.Name)); + } + } + if (transpilerMethod != null) { + foreach (Patch patch in info.Transpilers) + { + if (patch.owner != ModId) + Log.Warning(string.Format("[RimWar] Possible mod conflict detected: Mod {0} also patches {1}.", + patch.owner, targetMethod.Name)); + } + } + } + + harmonyInstance.Patch(targetMethod, prefix: prefixMethod, + postfix: postfixMethod, transpiler: transpilerMethod); + } + public RimWarMod(ModContentPack content) : base(content) { - HarmonyLib.Harmony harmonyInstance = new HarmonyLib.Harmony("rimworld.torann.rimwar"); + harmonyInstance = new HarmonyLib.Harmony(ModId); //Postfix //1.3 // //harmonyInstance.Patch(AccessTools.Method(typeof(TransportPodsArrivalAction_Shuttle), "Arrived", new Type[] @@ -42,50 +86,108 @@ public RimWarMod(ModContentPack content) : base(content) // typeof(List), // typeof(int) // }, null), null, new HarmonyMethod(patchType, "ShuttleArrived_SettlementHasAttackers_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(TransportersArrivalAction_AttackSettlement), "Arrived", new Type[] - { - typeof(List), - typeof(PlanetTile) - }, null), null, new HarmonyMethod(patchType, "PodsArrived_SettlementHasAttackers_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(RimWorld.Planet.SettlementUtility), "AttackNow", new Type[] - { - typeof(Caravan), - typeof(RimWorld.Planet.Settlement) - }, null), null, new HarmonyMethod(patchType, "AttackNow_SettlementReinforcement_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(Settlement), "GetInspectString", new Type[] - { - }, null), null, new HarmonyMethod(patchType, "Settlement_InspectString_WithPoints_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(Caravan_PathFollower), "StartPath", new Type[] - { - typeof(PlanetTile), - typeof(CaravanArrivalAction), - typeof(bool), - typeof(bool) - }, null), null, new HarmonyMethod(patchType, "Pather_StartPath_WarObjects", null), null); + + PatchHarmonyMethod(typeof(TransportersArrivalAction_AttackSettlement), + "Arrived", + new Type[]{ typeof(List), + typeof(PlanetTile) }, + postfixMethod: new HarmonyMethod(patchType, nameof(PodsArrived_SettlementHasAttackers_Postfix))); + PatchHarmonyMethod(typeof(RimWorld.Planet.SettlementUtility), + "AttackNow", + new Type[]{ typeof(Caravan), + typeof(RimWorld.Planet.Settlement) }, + postfixMethod: new HarmonyMethod(patchType, nameof(AttackNow_SettlementReinforcement_Postfix))); + PatchHarmonyMethod(typeof(Settlement), + "GetInspectString", + postfixMethod: new HarmonyMethod(patchType, nameof(Settlement_InspectString_WithPoints_Postfix))); + PatchHarmonyMethod(typeof(Caravan_PathFollower), "StartPath", + new Type[]{ typeof(PlanetTile), + typeof(CaravanArrivalAction), + typeof(bool), + typeof(bool) }, + postfixMethod: new HarmonyMethod(patchType, nameof(Pather_StartPath_WarObjects_Postfix))); + PatchHarmonyMethod(typeof(WorldSelectionDrawer), "DrawSelectionOverlays", + postfixMethod: new HarmonyMethod(patchType, nameof(WorldCapitolOverlay))); + PatchHarmonyMethod(typeof(CaravanEnterMapUtility), "Enter", + new Type[]{ typeof(Caravan), typeof(Map), + typeof(Func), + typeof(CaravanDropInventoryMode), + typeof(bool) }, + postfixMethod: new HarmonyMethod(patchType, nameof(AttackInjuredSettlement_Postfix))); + PatchHarmonyMethod(typeof(Settlement), "GetShuttleFloatMenuOptions", + new Type[]{ typeof(IEnumerable), + typeof(Action) }, + postfixMethod: new HarmonyMethod(patchType, nameof(Settlement_ShuttleReinforce_Postfix))); + PatchHarmonyMethod(typeof(ThingSetMaker), "Generate", + new Type[]{ typeof(ThingSetMakerParams) }, + postfixMethod: new HarmonyMethod(patchType, nameof(ThingSetMaker_TraderCheck_Postfix))); + PatchHarmonyMethod(typeof(FactionGiftUtility), "GiveGift", + new Type[]{ typeof(List), + typeof(Settlement) }, + prefixMethod: new HarmonyMethod(patchType, nameof(GivePodGiftAsRimWarPoints_Prefix))); + PatchHarmonyMethod(typeof(FactionGiftUtility), "GiveGift", + new Type[]{ typeof(List), + typeof(Faction), + typeof(GlobalTargetInfo) }, + prefixMethod: new HarmonyMethod(patchType, nameof(GiveGiftAsRimWarPoints_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker), "TryExecute", + new Type[]{ typeof(IncidentParms) }, + prefixMethod: new HarmonyMethod(patchType, nameof(IncidentWorker_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker_CaravanDemand), "ActionGive", + new Type[]{ typeof(Caravan), + typeof(List), + typeof(List) }, + prefixMethod: new HarmonyMethod(patchType, nameof(Caravan_Give_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker_NeutralGroup), "TryResolveParms", + new Type[]{ typeof(IncidentParms) }, + prefixMethod: new HarmonyMethod(patchType, nameof(TryResolveParms_Points_Prefix))); + PatchHarmonyMethod(typeof(CaravanExitMapUtility), "ExitMapAndCreateCaravan", + new Type[]{ typeof(IEnumerable), + typeof(Faction), + typeof(PlanetTile), + typeof(PlanetTile), + typeof(PlanetTile), + typeof(bool) }, + prefixMethod: new HarmonyMethod(patchType, nameof(ExitMapPostBattle_Prefix))); + PatchHarmonyMethod(typeof(IncidentQueue), "Add", + new Type[]{ typeof(IncidentDef), + typeof(int), + typeof(IncidentParms), + typeof(int) }, + prefixMethod: new HarmonyMethod(patchType, nameof(IncidentQueueAdd_Replacement_Prefix))); + PatchHarmonyMethod(typeof(FactionDialogMaker), "CallForAid", + new Type[]{ typeof(Map), typeof(Faction) }, + prefixMethod: new HarmonyMethod(patchType, nameof(CallForAid_Replacement_Patch))); + PatchHarmonyMethod(typeof(SymbolStack), "Push", + new Type[]{ typeof(string), + typeof(ResolveParams), + typeof(string) }, + prefixMethod: new HarmonyMethod(patchType, nameof(GenStep_Map_Params_Prefix))); + PatchHarmonyMethod(typeof(GenStep_Settlement), "ScatterAt", + new Type[]{ typeof(IntVec3), + typeof(Map), + typeof(GenStepParams), + typeof(int) }, + prefixMethod: new HarmonyMethod(patchType, nameof(GenStep_Map_ID_Prefix))); + + PatchHarmonyMethod(typeof(WorldPathPool), "GetEmptyWorldPath", + prefixMethod: new HarmonyMethod(patchType, nameof(WorldPathPool_Prefix_Patch))); + PatchHarmonyMethod(typeof(IncidentWorker_Ambush_EnemyFaction), "CanFireNowSub", + prefixMethod: new HarmonyMethod(patchType, nameof(CanFireNow_Ambush_EnemyFaction_RemovalPatch_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker_CaravanDemand), "CanFireNowSub", + prefixMethod: new HarmonyMethod(patchType, nameof(CanFireNow_CaravanDemand_RemovalPatch_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker_CaravanMeeting), "CanFireNowSub", + prefixMethod: new HarmonyMethod(patchType, nameof(CanFireNow_CaravanMeeting_RemovalPatch_Prefix))); + PatchHarmonyMethod(typeof(IncidentWorker_PawnsArrive), "CanFireNowSub", + prefixMethod: new HarmonyMethod(patchType, nameof(CanFireNow_PawnsArrive_RemovalPatch_Prefix))); + + harmonyInstance.PatchAll(); + //harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_CaravanMeeting), "RemoveAllPawnsAndPassToWorld", new Type[] // { // typeof(Caravan) // }, null), null, new HarmonyMethod(patchType, "Caravan_MoveOn_Prefix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(WorldSelectionDrawer), "DrawSelectionOverlays", new Type[] - { - }, null), null, new HarmonyMethod(patchType, "WorldCapitolOverlay", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(CaravanEnterMapUtility), "Enter", new Type[] - { - typeof(Caravan), - typeof(Map), - typeof(Func), - typeof(CaravanDropInventoryMode), - typeof(bool) - }, null), null, new HarmonyMethod(patchType, "AttackInjuredSettlement_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(Settlement), "GetShuttleFloatMenuOptions", new Type[] - { - typeof(IEnumerable), - typeof(Action) - }, null), null, new HarmonyMethod(patchType, "Settlement_ShuttleReinforce_Postfix", null), null); - harmonyInstance.Patch(AccessTools.Method(typeof(ThingSetMaker), "Generate", new Type[] - { - typeof(ThingSetMakerParams) - }, null), null, new HarmonyMethod(patchType, "ThingSetMaker_TraderCheck_Postfix", null), null); + //harmonyInstance.Patch(AccessTools.Method(typeof(PlaySettings), "DoPlaySettingsGlobalControls", new Type[] // { // typeof(WidgetRow), @@ -100,40 +202,6 @@ public RimWarMod(ModContentPack content) : base(content) //Prefix - harmonyInstance.Patch(AccessTools.Method(typeof(FactionGiftUtility), "GiveGift", new Type[] - { - typeof(List), - typeof(Settlement) - }, null), new HarmonyMethod(patchType, "GivePodGiftAsRimWarPoints_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(FactionGiftUtility), "GiveGift", new Type[] - { - typeof(List), - typeof(Faction), - typeof(GlobalTargetInfo) - }, null), new HarmonyMethod(patchType, "GiveGiftAsRimWarPoints_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker), "TryExecute", new Type[] - { - typeof(IncidentParms) - }, null), new HarmonyMethod(patchType, "IncidentWorker_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_CaravanDemand), "ActionGive", new Type[] - { - typeof(Caravan), - typeof(List), - typeof(List) - }, null), new HarmonyMethod(patchType, "Caravan_Give_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_NeutralGroup), "TryResolveParms", new Type[] - { - typeof(IncidentParms) - }, null), new HarmonyMethod(patchType, "TryResolveParms_Points_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(CaravanExitMapUtility), "ExitMapAndCreateCaravan", new Type[] - { - typeof(IEnumerable), - typeof(Faction), - typeof(PlanetTile), - typeof(PlanetTile), - typeof(PlanetTile), - typeof(bool) - }, null), new HarmonyMethod(patchType, "ExitMapPostBattle_Prefix", null), null, null); //Unused //harmonyInstance.Patch(AccessTools.Method(typeof(Faction), "TryAffectGoodwillWith", new Type[] // { @@ -144,45 +212,6 @@ public RimWarMod(ModContentPack content) : base(content) // typeof(HistoryEventDef), // typeof(GlobalTargetInfo?) // }, null), new HarmonyMethod(patchType, "TryAffectGoodwillWith_Reduction_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentQueue), "Add", new Type[] - { - typeof(IncidentDef), - typeof(int), - typeof(IncidentParms), - typeof(int) - }, null), new HarmonyMethod(patchType, "IncidentQueueAdd_Replacement_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(FactionDialogMaker), "CallForAid", new Type[] - { - typeof(Map), - typeof(Faction) - }, null), new HarmonyMethod(patchType, "CallForAid_Replacement_Patch", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(SymbolStack), "Push", new Type[] - { - typeof(string), - typeof(ResolveParams), - typeof(string) - }, null), new HarmonyMethod(patchType, "GenStep_Map_Params_Prefix", null), null, null); - harmonyInstance.Patch(AccessTools.Method(typeof(GenStep_Settlement), "ScatterAt", new Type[] - { - typeof(IntVec3), - typeof(Map), - typeof(GenStepParams), - typeof(int) - }, null), new HarmonyMethod(patchType, "GenStep_Map_ID_Prefix", null), null, null); - - harmonyInstance.Patch(AccessTools.Method(typeof(WorldPathPool), "GetEmptyWorldPath"), - prefix: new HarmonyMethod(patchType, nameof(WorldPathPool_Prefix_Patch))); - - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_Ambush_EnemyFaction), "CanFireNowSub"), - prefix: new HarmonyMethod(patchType, nameof(CanFireNow_Ambush_EnemyFaction_RemovalPatch_Prefix))); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_CaravanDemand), "CanFireNowSub"), - prefix: new HarmonyMethod(patchType, nameof(CanFireNow_CaravanDemand_RemovalPatch_Prefix))); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_CaravanMeeting), "CanFireNowSub"), - prefix: new HarmonyMethod(patchType, nameof(CanFireNow_CaravanMeeting_RemovalPatch_Prefix))); - harmonyInstance.Patch(AccessTools.Method(typeof(IncidentWorker_PawnsArrive), "CanFireNowSub"), - prefix: new HarmonyMethod(patchType, nameof(CanFireNow_PawnsArrive_RemovalPatch_Prefix))); - - harmonyInstance.PatchAll(); } //public static void WorldSettings_RimWarControls(PlaySettings __instance, ref WidgetRow row, bool worldView) @@ -641,7 +670,7 @@ private static void Postfix(FactionManager __instance, Faction faction) } } - public static void Pather_StartPath_WarObjects(Caravan_PathFollower __instance, Caravan ___caravan, PlanetTile destTile, CaravanArrivalAction arrivalAction, ref bool __result, bool repathImmediately = false, bool resetPauseStatus = true) + public static void Pather_StartPath_WarObjects_Postfix(Caravan_PathFollower __instance, Caravan ___caravan, PlanetTile destTile, CaravanArrivalAction arrivalAction, ref bool __result, bool repathImmediately = false, bool resetPauseStatus = true) { if (__result == true) { diff --git a/Source/RimWar/Options/Settings.cs b/Source/RimWar/Options/Settings.cs index cc111bf..d17e634 100644 --- a/Source/RimWar/Options/Settings.cs +++ b/Source/RimWar/Options/Settings.cs @@ -30,7 +30,7 @@ public class Settings : Verse.ModSettings public float objectMovementMultiplier = 1f; //performance controls - public bool threadingEnabled = true; + public bool threadingEnabled = false; public int averageEventFrequency = 150; public int settlementEventDelay = 50000; public int settlementScanDelay = 60000; @@ -85,7 +85,7 @@ public override void ExposeData() Scribe_Values.Look(ref this.heatFrequency, "heatFrequency", 2500f, false); Scribe_Values.Look(ref this.settlementGrowthRate, "settlementGrowthRate", 1f, false); Scribe_Values.Look(ref this.noPermanentEnemies, "noPermanentEnemies", false, true); - Scribe_Values.Look(ref this.threadingEnabled, "threadingEnabled", true, true); + Scribe_Values.Look(ref this.threadingEnabled, "threadingEnabled", false, true); Scribe_Values.Look(ref this.vassalNotification, "vassalNotification", false, false); Scribe_Values.Look(ref this.alliedNotification, "alliedNotification", false, false); Scribe_Values.Look(ref this.allowDropPodRaids, "allowDropPodRaids", true, true); diff --git a/Source/RimWar/Planet/WorldComponent_PowerTracker.cs b/Source/RimWar/Planet/WorldComponent_PowerTracker.cs index b211e01..f1048da 100644 --- a/Source/RimWar/Planet/WorldComponent_PowerTracker.cs +++ b/Source/RimWar/Planet/WorldComponent_PowerTracker.cs @@ -483,9 +483,9 @@ private static int CountOnPlanetFactions() return count; } - public void CheckForNewFactions() + private void CheckForNewFactions() { - if(WorldComponent_PowerTracker.CountOnPlanetFactions() > this.RimWarData.Count) + if (WorldComponent_PowerTracker.CountOnPlanetFactions() > this.RimWarData.Count) { Utility.RimWar_DebugToolsPlanet.ResetFactions(false, true); } @@ -727,8 +727,52 @@ public void UpdatePlayerAggression() this.minimumHeatForPlayerAction = Mathf.Clamp(this.minimumHeatForPlayerAction - Rand.RangeInclusive(1, 2), 0, 10000); } + private void CheckFactionDefeated() + { + /* This shouldn't be needed as Rimworld should mark faction as + * defeated by itself, but this does not seem to be a case. + * Usually faction can be only defeated by player destroying last + * settlement, but this will happen without player intervention. + * As such, mark faction as defeated ourselves if not already. + */ + List factionList = Find.World.factionManager.AllFactionsVisible.ToList(); + + for (int i = 0; i < factionList.Count; i++) + { + /* TODO Actually check both layers, but traders can be killed only by player currently. + * TODO This will also defeat "Refugee faction" but I find it neat, + * them coming to player defeated. Sadly RimWorld itself does not + * have pretty check for these factions. + * But need to fix this. + */ + if (factionList[i].IsPlayer || factionList[i] == Faction.OfTradersGuild || factionList[i].temporary) + continue; + + if (!Find.WorldObjects.AnyFactionSettlementOnRootSurface(factionList[i])) + { + // Check for active parties + List wosList = WorldUtility.GetRimWarDataForFaction(factionList[i]).FactionUnits; + if (wosList != null && wosList.Count > 0) + continue; + + if (factionList[i].defeated) + continue; + + factionList[i].defeated = true; + + Find.LetterStack.ReceiveLetter( + // TODO add translation + "Faction destroyed", + string.Format("All settlements of {0} have been destroyed.", factionList[i].Name), + LetterDefOf.PositiveEvent + ); + } + } + } + public void UpdateFactions() { + CheckFactionDefeated(); IncrementSettlementGrowth(); ReconstituteSettlements(); UpdateFactionSettlements(this.RimWarData.RandomElement()); diff --git a/Source/RimWar/Planet/WorldUtility.cs b/Source/RimWar/Planet/WorldUtility.cs index 3d434ba..306bae2 100644 --- a/Source/RimWar/Planet/WorldUtility.cs +++ b/Source/RimWar/Planet/WorldUtility.cs @@ -21,7 +21,7 @@ public class WorldUtility private static WorldComponent_PowerTracker wcpt = null; // Do not scan literally everything, put some arbitrary limit - private const int maxObjectsPerScan = 5; + private const int maxObjectsPerScan = 20; public static WorldComponent_PowerTracker Get_WCPT() { @@ -1381,6 +1381,13 @@ public static List GetWorldObjectsInRange(PlanetTile from, float ra { List tmpObjects = null; //List tmpObjects = Find.WorldObjects.AllWorldObjects; + + if (from.Layer == Find.WorldGrid.Orbit) + { + Log.WarningOnce("Attempting to GetWorldObjectsInRange while in space", 664799); + return null; + } + if (WorldObjectsHolder == null) CopyData(); lock (locker) diff --git a/Source/RimWar/Utility/Alert_NearbyRimWarObject.cs b/Source/RimWar/Utility/Alert_NearbyRimWarObject.cs index 8ee91ee..737e400 100644 --- a/Source/RimWar/Utility/Alert_NearbyRimWarObject.cs +++ b/Source/RimWar/Utility/Alert_NearbyRimWarObject.cs @@ -8,12 +8,15 @@ using Verse; using RimWar.Planet; using UnityEngine; +using Verse.Noise; namespace RimWar.Utility { public class Alert_NearbyRimWarObject : Alert { private List woGTIList = new List(); + private int updateRate = 0; + private static readonly int refreshRate = 60; private List WOGTIList { get @@ -28,26 +31,38 @@ public List WONearbyResult { get { - woNearbyResult.Clear(); - woGTIList.Clear(); - RimWar.Options.SettingsRef settingsRef = new Options.SettingsRef(); - if (settingsRef.alertRange > 0) - { - foreach (WorldObject wo in WorldUtility.GetWorldObjectsInRange(Find.AnyPlayerHomeMap.Tile, settingsRef.alertRange)) + if (updateRate >= refreshRate) { + updateRate = 0; + + woNearbyResult.Clear(); + woGTIList.Clear(); + RimWar.Options.SettingsRef settingsRef = new Options.SettingsRef(); + if (settingsRef.alertRange > 0) { - if (wo != null && wo.Faction != Faction.OfPlayer) + Map playerMap = Find.AnyPlayerHomeMap; + if (playerMap.Tile.Layer == Find.WorldGrid.Orbit) + { + return null; + } + + foreach (WorldObject wo in WorldUtility.GetWorldObjectsInRange(playerMap.Tile, settingsRef.alertRange)) { - List tmpList = WorldUtility.GetRimWarObjectsAt(wo.Tile); - if (tmpList != null && tmpList.Count > 0) + if (wo != null && wo.Faction != Faction.OfPlayer) { - foreach (WarObject warObj in tmpList) + List tmpList = WorldUtility.GetRimWarObjectsAt(wo.Tile); + if (tmpList != null && tmpList.Count > 0) { - woNearbyResult.Add(warObj); + foreach (WarObject warObj in tmpList) + { + woNearbyResult.Add(warObj); + } + woGTIList.Add(wo); } - woGTIList.Add(wo); } } - } + } + } else { + updateRate++; } List orderedList = woNearbyResult.OrderBy(name => name.Name).ToList();