diff --git a/Defs/ThingDefs_Buildings/Buildings_Storage.xml b/Defs/ThingDefs_Buildings/Buildings_Storage.xml index 8a862eaf..145f8a34 100644 --- a/Defs/ThingDefs_Buildings/Buildings_Storage.xml +++ b/Defs/ThingDefs_Buildings/Buildings_Storage.xml @@ -361,6 +361,121 @@ + + + + ProjectRimFactory.Storage.Building_ColdStoragePowered + PRF_ColdStorageUnit_I + + A matter-energy conversion based storage unit which can hold up to 10k stacks, consuming 10 W of power per stack of items. In the event of a power outage, items already inside will be safe, but the Cold Storage Unit will not be able to store more. Don't break it.\n\nItems stored in this Device are not spawned and therefore won't be automatically accessible by your pawns. Use I/O Ports to interact with it. + PRF_IoGroup + 0.9 + +
  • Furniture
  • +
    + Building + Impassable + true + 1.0 + true + false + false + true + MinifiedThing + Heavy + 0.5 + Item + +
  • ITab_Storage
  • +
  • ProjectRimFactory.Storage.UI.ITab_Items
  • +
    + + Graphic_Single + Storage/ColdStorageUnit + (3,3) + + + + + (0.1,0,2.8,2.8) + + Damage/Corner + Damage/Corner + Damage/Corner + + + + + + 50 + 450 + 5000 + 10880 + 0.05 + 0.5 + + + true + true + + Normal + + +
  • Manufactured
  • +
  • ResourcesRaw
  • +
  • Items
  • +
  • BuildingsArt
  • +
  • Weapons
  • +
  • Apparel
  • +
  • BodyParts
  • +
    + +
  • AllowRotten
  • +
    +
    +
    +
    + (3,3) + 150 + + 300 + 50 + 20 + 100 + 90 + 20 + 1 + 1 + + Normal + +
  • PRF_StorageIO_II
  • +
    + +
  • + 6 + (115,198,206,0) +
  • +
  • + CompPowerTrader + true + 0 +
  • +
  • +
  • + + 10 + +
  • +
  • + 10000 + true + true + false + true +
  • + +
    diff --git a/Languages/English/Keyed/AllKeyed_Settings.xml b/Languages/English/Keyed/AllKeyed_Settings.xml index b319444a..948a4794 100644 --- a/Languages/English/Keyed/AllKeyed_Settings.xml +++ b/Languages/English/Keyed/AllKeyed_Settings.xml @@ -7,6 +7,8 @@ Patches Toggels the Advanced IO CanReach Patch\nWhen checked the Patch is active and allowes Pawns to reach DSU contents using Advanced IO Ports even if the Path to the DSU is blocked\nPatch is not active by default as it may cause spikes and is only usefull in some cases.\n(ProjectRimFactory.Common.HarmonyPatches.Patch_Reachability_CanReach:Prefix) Advanced IO CanReach + Toggels the Cold Storage WealthWatcher Patch\nWhen checked the Patch is active and items in Coldstorage contribute to Colony Wealth.\nFor most Players we reccomend this to be on.\nPeformence load on this is ~1ms per 1k Things stored. This runs every 5k Ticks\n(ProjectRimFactory.Common.HarmonyPatches.Patch_WealthWatcher_CalculateWealthItems:Postfix) + Cold Storage WealthWatcher Forbid items on Placment Toggle this to forbid items on placement diff --git a/Source/ProjectRimFactory/AutoMachineTool/Building_BeltConveyor.cs b/Source/ProjectRimFactory/AutoMachineTool/Building_BeltConveyor.cs index 82f8f9f8..8b5f0ab5 100644 --- a/Source/ProjectRimFactory/AutoMachineTool/Building_BeltConveyor.cs +++ b/Source/ProjectRimFactory/AutoMachineTool/Building_BeltConveyor.cs @@ -262,13 +262,11 @@ public override void SpawnSetup(Map map, bool respawningAfterLoad) { } // already set, but just in case: this.products = thingOwnerInt.InnerListForReading; - map.GetComponent().RegisterIHideItemPos(this.Position, this); } public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) { var targets = AllNearbyLinkables().ToList(); - this.Map.GetComponent().DeRegisterIHideItemPos(this.Position,this); base.DeSpawn(mode); targets.ForEach(x => x.Unlink(this)); diff --git a/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs b/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs index f588eb87..715b79f1 100644 --- a/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs +++ b/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs @@ -6,35 +6,136 @@ using Verse; using HarmonyLib; using Verse.AI; +using ProjectRimFactory.Storage; +using System.Reflection; namespace ProjectRimFactory.Common { public static class ConditionalPatchHelper { + public class TogglePatch + { + private bool Patched = false; + + private readonly MethodInfo base_m; + private readonly HarmonyMethod trans_hm = null; + private readonly HarmonyMethod pre_hm = null; + private readonly HarmonyMethod post_hm = null; + private readonly MethodInfo trans_m = null; + private readonly MethodInfo pre_m = null; + private readonly MethodInfo post_m = null; + + public TogglePatch(MethodInfo base_method, MethodInfo prefix = null, MethodInfo postfix = null, MethodInfo Transpiler = null) + { + base_m = base_method; + if (Transpiler != null) trans_hm = new HarmonyMethod(Transpiler); + if (prefix != null) pre_hm = new HarmonyMethod(prefix); + if (postfix != null) post_hm = new HarmonyMethod(postfix); + trans_m = Transpiler; + pre_m = prefix; + post_m = postfix; + } + + public void PatchHandler(bool patch) + { + if (patch && !Patched) + { + harmony_instance.Patch(base_m,pre_hm,post_hm,trans_hm); + Patched = true; + } + else if (Patched && !patch) + { + if (trans_m != null) harmony_instance.Unpatch(base_m, trans_m); + if (pre_m != null) harmony_instance.Unpatch(base_m, pre_m); + if (post_m != null) harmony_instance.Unpatch(base_m, post_m); + Patched = false; + } + } + + } + //conditional private static Harmony harmony_instance = null; - private static bool Patch_Reachability_CanReach = false; + public static TogglePatch Patch_Reachability_CanReach = new TogglePatch( + AccessTools.Method(typeof(Verse.Reachability), "CanReach", new Type[] { typeof(IntVec3), typeof(LocalTargetInfo), typeof(PathEndMode), typeof(TraverseParms) }), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Reachability_CanReach), "Prefix") + ); + + public static TogglePatch Patch_WealthWatcher_CalculateWealthItems = new TogglePatch( + AccessTools.Method(typeof(RimWorld.WealthWatcher), "CalculateWealthItems"), + null, + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_WealthWatcher_CalculateWealthItems), "Postfix") + ); + + //Storage Patches + public static TogglePatch Patch_MinifiedThing_Print = new TogglePatch( + AccessTools.Method(typeof(RimWorld.MinifiedThing), "Print", new Type[] { typeof(SectionLayer)}), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_MinifiedThing_Print), "Prefix") + ); + public static TogglePatch Patch_Thing_Print = new TogglePatch( + AccessTools.Method(typeof(Verse.Thing), "Print", new Type[] { typeof(SectionLayer) }), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Thing_Print), "Prefix") + ); + public static TogglePatch Patch_ThingWithComps_Draw = new TogglePatch( + AccessTools.Method(typeof(Verse.ThingWithComps), "Draw"), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_ThingWithComps_Draw), "Prefix") + ); + public static TogglePatch Patch_ThingWithComps_DrawGUIOverlay = new TogglePatch( + AccessTools.Method(typeof(Verse.ThingWithComps), "DrawGUIOverlay"), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_ThingWithComps_DrawGUIOverlay), "Prefix") + ); + public static TogglePatch Patch_Thing_DrawGUIOverlay = new TogglePatch( + AccessTools.Method(typeof(Verse.Thing), "DrawGUIOverlay"), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Thing_DrawGUIOverlay), "Prefix") + ); + public static TogglePatch Patch_FloatMenuMakerMap_ChoicesAtFor = new TogglePatch( + AccessTools.Method(typeof(RimWorld.FloatMenuMakerMap), "ChoicesAtFor", new Type[] { typeof(UnityEngine.Vector3), typeof(Pawn), typeof(bool) }), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_FloatMenuMakerMap_ChoicesAtFor), "Prefix") + ); + public static TogglePatch Patch_Building_Storage_Accepts = new TogglePatch( + AccessTools.Method(typeof(RimWorld.Building_Storage), "Accepts", new Type[] { typeof(Verse.Thing)}), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Building_Storage_Accepts), "Prefix") + ); + public static TogglePatch Patch_ForbidUtility_IsForbidden = new TogglePatch( + AccessTools.Method(typeof(RimWorld.ForbidUtility), "IsForbidden", new Type[] { typeof(Thing), typeof(Pawn) }), + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_ForbidUtility_IsForbidden), "Prefix") + ); + + + + public static void InitHarmony(Harmony harmony) { harmony_instance = harmony; } - public static void Update_Patch_Reachability_CanReach() + static List building_MassStorages = new List(); + + private static void updatePatchStorage() { - var patch = AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Reachability_CanReach), "Prefix"); - var base_m = AccessTools.Method(typeof(Verse.Reachability), "CanReach", new Type[] { typeof(IntVec3), typeof(LocalTargetInfo), typeof(PathEndMode), typeof(TraverseParms) }); - if (ProjectRimFactory_ModSettings.PRF_Patch_Reachability_CanReach) - { - harmony_instance.Patch(base_m, new HarmonyMethod(patch) ); - Patch_Reachability_CanReach = true; - } - else if(Patch_Reachability_CanReach) - { - harmony_instance.Unpatch(base_m, patch); - Patch_Reachability_CanReach = false; - } + bool state = building_MassStorages.Count > 0; + + Patch_MinifiedThing_Print.PatchHandler(state); + Patch_Thing_Print.PatchHandler(state); + Patch_ThingWithComps_Draw.PatchHandler(state); + Patch_ThingWithComps_DrawGUIOverlay.PatchHandler(state); + Patch_Thing_DrawGUIOverlay.PatchHandler(state); + Patch_FloatMenuMakerMap_ChoicesAtFor.PatchHandler(state); + Patch_Building_Storage_Accepts.PatchHandler(state); + Patch_ForbidUtility_IsForbidden.PatchHandler(state); + } + + public static void Register(Building_MassStorageUnit building) + { + building_MassStorages.Add(building); + updatePatchStorage(); + } + public static void Deregister(Building_MassStorageUnit building) + { + building_MassStorages.Remove(building); + updatePatchStorage(); } } diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/AdvancedIO_PatchHelper.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/AdvancedIO_PatchHelper.cs index 193fb7e4..e1667fde 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/AdvancedIO_PatchHelper.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/AdvancedIO_PatchHelper.cs @@ -112,7 +112,7 @@ public static bool CanMoveItem(Building_AdvancedStorageUnitIOPort port, Thing th /// public static bool CanMoveItem(Building_AdvancedStorageUnitIOPort port, IntVec3 thingPos) { - return port.boundStorageUnit?.AllSlotCells()?.Contains(thingPos) ?? false; + return port.boundStorageUnit?.HoldsPos(thingPos) ?? false; } diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/PatchStorage.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/PatchStorage.cs index 83a37da8..cb4d7071 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/PatchStorage.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/PatchStorage.cs @@ -12,7 +12,6 @@ namespace ProjectRimFactory.Common.HarmonyPatches { - [HarmonyPatch(typeof(ForbidUtility), "IsForbidden", new Type[] { typeof(Thing), typeof(Pawn) })] class Patch_ForbidUtility_IsForbidden { static bool Prefix(Thing t, Pawn pawn, out bool __result) @@ -33,7 +32,6 @@ static bool Prefix(Thing t, Pawn pawn, out bool __result) } } - [HarmonyPatch(typeof(Building_Storage), "Accepts")] class Patch_Building_Storage_Accepts { static bool Prefix(Building_Storage __instance, Thing t, out bool __result) @@ -50,7 +48,6 @@ static bool Prefix(Building_Storage __instance, Thing t, out bool __result) } } - [HarmonyPatch(typeof(FloatMenuMakerMap), "ChoicesAtFor")] class Patch_FloatMenuMakerMap_ChoicesAtFor { static bool Prefix(Vector3 clickPos, Pawn pawn, out List __result) @@ -65,7 +62,6 @@ static bool Prefix(Vector3 clickPos, Pawn pawn, out List __resu } } - [HarmonyPatch(typeof(Thing), "DrawGUIOverlay")] class Patch_Thing_DrawGUIOverlay { static bool Prefix(Thing __instance) @@ -81,7 +77,6 @@ static bool Prefix(Thing __instance) } } - [HarmonyPatch(typeof(ThingWithComps), "DrawGUIOverlay")] class Patch_ThingWithComps_DrawGUIOverlay { static bool Prefix(Thing __instance) @@ -97,7 +92,6 @@ static bool Prefix(Thing __instance) } } - [HarmonyPatch(typeof(ThingWithComps), "Draw")] class Patch_ThingWithComps_Draw { static bool Prefix(Thing __instance) @@ -113,7 +107,6 @@ static bool Prefix(Thing __instance) } } - [HarmonyPatch(typeof(Thing), "Print")] class Patch_Thing_Print { static bool Prefix(Thing __instance, SectionLayer layer) @@ -129,7 +122,6 @@ static bool Prefix(Thing __instance, SectionLayer layer) } } - [HarmonyPatch(typeof(MinifiedThing), "Print")] class Patch_MinifiedThing_Print { static bool Prefix(Thing __instance, SectionLayer layer) diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_DSU_OrbitalTrade.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_DSU_OrbitalTrade.cs index d12eb071..b92c429f 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_DSU_OrbitalTrade.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_DSU_OrbitalTrade.cs @@ -20,7 +20,7 @@ static void Postfix(Map map, ref IEnumerable __result) { HashSet yieldedThings = new HashSet(); yieldedThings.AddRange(__result); - foreach (Building_MassStorageUnitPowered dsu in Building_MassStorageUnitPowered.AllPowered(map)) + foreach (ILinkableStorageParent dsu in TradePatchHelper.AllPowered(map)) { yieldedThings.AddRange(dsu.StoredItems); } @@ -89,7 +89,7 @@ static IEnumerable Transpiler(IEnumerable inst yield return new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(PassingShip), "Map")); //Call --> Building_MassStorageUnitPowered.AnyPowerd with the above as an argument yield return new CodeInstruction(OpCodes.Call, HarmonyLib.AccessTools - .Method(typeof(Building_MassStorageUnitPowered) ,nameof(Building_MassStorageUnitPowered.AnyPowerd), new[] { typeof(Map)} )); + .Method(typeof(TradePatchHelper) ,nameof(TradePatchHelper.AnyPowerd), new[] { typeof(Map)} )); yield return new CodeInstruction(OpCodes.Brtrue_S, instruction.operand); continue; @@ -103,6 +103,31 @@ static IEnumerable Transpiler(IEnumerable inst } } + public static class TradePatchHelper + { + public static bool AnyPowerd(Map map) + { + return AllPowered(map,true).Any(); + } + + public static IEnumerable AllPowered(Map map, bool any = false) + { + foreach (ILinkableStorageParent item in map.listerBuildings.AllBuildingsColonistOfClass()) + { + if (item.Powered) + { + yield return item; + if (any) break; + } + } + var cs = PatchStorageUtil.GetPRFMapComponent(map).ColdStorageBuildings.Select(b => b as ILinkableStorageParent); + foreach (var item in cs) + { + yield return item; + } + } + } + diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Pawn_TraderTracker_ColonyThingsWillingToBuy.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Pawn_TraderTracker_ColonyThingsWillingToBuy.cs new file mode 100644 index 00000000..77e42d08 --- /dev/null +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Pawn_TraderTracker_ColonyThingsWillingToBuy.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using ProjectRimFactory.Storage; +using RimWorld; +using Verse; + +namespace ProjectRimFactory.Common.HarmonyPatches +{ + [HarmonyPatch(typeof(Pawn_TraderTracker), "ColonyThingsWillingToBuy")] + class Patch_Pawn_TraderTracker_ColonyThingsWillingToBuy + { + static void Postfix(Pawn playerNegotiator, ref IEnumerable __result) + { + var map = playerNegotiator.Map; + if (map is null) return; + + HashSet yieldedThings = new HashSet(); + yieldedThings.AddRange(__result); + foreach (ILinkableStorageParent dsu in TradePatchHelper.AllPowered(map)) + { + //Only for Cold Storage + if (dsu.AdvancedIOAllowed) continue; + + yieldedThings.AddRange(dsu.StoredItems); + } + __result = yieldedThings; + + } + + } +} diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs index daa6c8df..06cb9563 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs @@ -23,7 +23,7 @@ public static bool Prefix(IntVec3 start, LocalTargetInfo dest, PathEndMode peMod if (mapcomp.ShouldHideItemsAtPos(ThingPos)) { //Is in a DSU - var pathToIO = mapcomp.GetadvancedIOLocations.Where(p => p.Value.boundStorageUnit?.Position == ThingPos && __instance.CanReach(start, p.Key, PathEndMode.Touch, traverseParams)).Any(); + var pathToIO = mapcomp.GetadvancedIOLocations.Where(p => p.Value.boundStorageUnit?.GetPosition == ThingPos && __instance.CanReach(start, p.Key, PathEndMode.Touch, traverseParams)).Any(); if (pathToIO) { __result = true; diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_TradeDeal_InSellablePosition.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_TradeDeal_InSellablePosition.cs new file mode 100644 index 00000000..4647c60e --- /dev/null +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_TradeDeal_InSellablePosition.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using HarmonyLib; +using Verse; +using ProjectRimFactory.Storage; +using System.Reflection.Emit; +using System.Reflection; + +namespace ProjectRimFactory.Common.HarmonyPatches +{ + + [HarmonyPatch(typeof(TradeDeal), "InSellablePosition")] + class Patch_TradeDeal_InSellablePosition + { + public static bool Prefix(Thing t, out string reason, ref bool __result) + { + if (!t.Spawned) + { + var buildings = PatchStorageUtil.GetPRFMapComponent(t.MapHeld).ColdStorageBuildings; + foreach(var building in buildings) + { + if (building.StoredItems.Contains(t)) + { + reason = null; + __result = true; + return false; + } + } + } + + reason = null; + return true; + } + + + } +} diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_WealthWatcher_CalculateWealthItems.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_WealthWatcher_CalculateWealthItems.cs new file mode 100644 index 00000000..f653c70e --- /dev/null +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_WealthWatcher_CalculateWealthItems.cs @@ -0,0 +1,29 @@ +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectRimFactory.Common.HarmonyPatches +{ + /// + /// Patch to ensure Items in Cold Storage Contribute to Wealth + /// 1k Items ~ 1ms (every 5k Ticks) + /// + class Patch_WealthWatcher_CalculateWealthItems + { + + public static void Postfix(Verse.Map ___map, ref float __result) + { + var buildings = PatchStorageUtil.GetPRFMapComponent(___map).ColdStorageBuildings; + var cnt = buildings.Count; + for(int i = 0; i < cnt; i++) + { + var building = buildings[i]; + __result += building.GetItemWealth(); + } + + } + } +} diff --git a/Source/ProjectRimFactory/Common/PRFMapComponent.cs b/Source/ProjectRimFactory/Common/PRFMapComponent.cs index 02cbcecc..0e7f33ba 100644 --- a/Source/ProjectRimFactory/Common/PRFMapComponent.cs +++ b/Source/ProjectRimFactory/Common/PRFMapComponent.cs @@ -15,6 +15,8 @@ public class PRFMapComponent : MapComponent // iHideRightMenus: see HarmonyPatches/PatchStorage.cs public HashSet iHideRightMenus = new HashSet(); + public List ColdStorageBuildings = new List(); + private Dictionary> hideItemLocations = new Dictionary>(); private Dictionary> ForbidPawnOutputItemLocations = new Dictionary>(); @@ -23,6 +25,24 @@ public class PRFMapComponent : MapComponent public Dictionary GetadvancedIOLocations => advancedIOLocations; + public void RegisterColdStorageBuilding(ProjectRimFactory.Storage.Building_ColdStorage port) + { + if (!ColdStorageBuildings.Contains(port)) + { + ColdStorageBuildings.Add(port); + } + } + public void DeRegisterColdStorageBuilding(ProjectRimFactory.Storage.Building_ColdStorage port) + { + if (ColdStorageBuildings.Contains(port)) + { + ColdStorageBuildings.Remove(port); + } + + } + + + public void RegisteradvancedIOLocations(IntVec3 pos, ProjectRimFactory.Storage.Building_AdvancedStorageUnitIOPort port) { if (!advancedIOLocations.ContainsKey(pos)) diff --git a/Source/ProjectRimFactory/Common/ProjectRimFactory_ModComponent.cs b/Source/ProjectRimFactory/Common/ProjectRimFactory_ModComponent.cs index 90273863..ff1959da 100644 --- a/Source/ProjectRimFactory/Common/ProjectRimFactory_ModComponent.cs +++ b/Source/ProjectRimFactory/Common/ProjectRimFactory_ModComponent.cs @@ -26,7 +26,8 @@ public ProjectRimFactory_ModComponent(ModContentPack content) : base(content) availableSpecialSculptures = SpecialSculpture.LoadAvailableSpecialSculptures(content); LoadModSupport(); ConditionalPatchHelper.InitHarmony(this.HarmonyInstance); - ConditionalPatchHelper.Update_Patch_Reachability_CanReach(); + ConditionalPatchHelper.Patch_Reachability_CanReach.PatchHandler(ProjectRimFactory_ModSettings.PRF_Patch_Reachability_CanReach); + ConditionalPatchHelper.Patch_WealthWatcher_CalculateWealthItems.PatchHandler(ProjectRimFactory_ModSettings.PRF_Patch_WealthWatcher_CalculateWealthItems); } catch (Exception ex) diff --git a/Source/ProjectRimFactory/Common/ProjectRimFactory_ModSettings.cs b/Source/ProjectRimFactory/Common/ProjectRimFactory_ModSettings.cs index ac30a40c..d1f762e9 100644 --- a/Source/ProjectRimFactory/Common/ProjectRimFactory_ModSettings.cs +++ b/Source/ProjectRimFactory/Common/ProjectRimFactory_ModSettings.cs @@ -73,12 +73,18 @@ private static void CSharpSettings(Listing_Standard list) { } TooltipHandler.TipRegion(rect, "PRF_Settings_C_Patches_Reachability_CanReach_ToolTip".Translate()); Widgets.CheckboxLabeled(rect, "PRF_Settings_C_Patches_Reachability_CanReach".Translate(), ref PRF_Patch_Reachability_CanReach); - list.Gap(); - if (PRF_Patch_Reachability_CanReach != PRF_Patch_Reachability_CanReach_last) + list.Gap(); + ConditionalPatchHelper.Patch_Reachability_CanReach.PatchHandler(ProjectRimFactory_ModSettings.PRF_Patch_Reachability_CanReach); + + rect = list.GetRect(20); + if (Mouse.IsOver(rect)) { - ConditionalPatchHelper.Update_Patch_Reachability_CanReach(); - } - PRF_Patch_Reachability_CanReach_last = PRF_Patch_Reachability_CanReach; + Widgets.DrawHighlight(rect); + } + TooltipHandler.TipRegion(rect, "PRF_Settings_C_Patches_WealthWatcher_CalculateWealthItems_ToolTip".Translate()); + Widgets.CheckboxLabeled(rect, "PRF_Settings_C_Patches_WealthWatcher_CalculateWealthItems".Translate(), ref PRF_Patch_WealthWatcher_CalculateWealthItems); + list.Gap(); + ConditionalPatchHelper.Patch_WealthWatcher_CalculateWealthItems.PatchHandler(ProjectRimFactory_ModSettings.PRF_Patch_WealthWatcher_CalculateWealthItems); } @@ -104,7 +110,7 @@ private static ContainerRow ParseSettingRows(ModContentPack content) public static bool PRF_LiteMode = false; private static bool PRF_LiteMode_last = false; public static bool PRF_Patch_Reachability_CanReach = false; - private static bool PRF_Patch_Reachability_CanReach_last = false; + public static bool PRF_Patch_WealthWatcher_CalculateWealthItems = true; public override void ExposeData() { @@ -113,8 +119,8 @@ public override void ExposeData() Scribe_Values.Look(ref Debug.activeFlags, "debugFlags", 0); Scribe_Values.Look(ref PRF_LiteMode, "PRF_LiteMode", false); Scribe_Values.Look(ref PRF_Patch_Reachability_CanReach, "PRF_Patch_Reachability_CanReach", false); + Scribe_Values.Look(ref PRF_Patch_WealthWatcher_CalculateWealthItems, "PRF_Patch_WealthWatcher_CalculateWealthItems", true); PRF_LiteMode_last = PRF_LiteMode; - PRF_Patch_Reachability_CanReach_last = PRF_Patch_Reachability_CanReach; } public void DoWindowContents(Rect inRect) diff --git a/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs b/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs index 75a26162..18598872 100644 --- a/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs +++ b/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs @@ -64,6 +64,8 @@ private Thing GetstoredItem() public bool CanGetNewItem => GetstoredItem() == null && (powerComp?.PowerOn ?? false); + public override bool IsAdvancedPort => true; + private void updateQueue() { if (CanGetNewItem && placementQueue.Count > 0) diff --git a/Source/ProjectRimFactory/Storage/Building_ColdStorage.cs b/Source/ProjectRimFactory/Storage/Building_ColdStorage.cs new file mode 100644 index 00000000..94283647 --- /dev/null +++ b/Source/ProjectRimFactory/Storage/Building_ColdStorage.cs @@ -0,0 +1,342 @@ +using System.Collections.Generic; +using System.Text; +using System.Linq; +using ProjectRimFactory.Common; +using ProjectRimFactory.Common.HarmonyPatches; +using ProjectRimFactory.Storage.Editables; +using ProjectRimFactory.Storage.UI; +using RimWorld; +using UnityEngine; +using Verse; + +namespace ProjectRimFactory.Storage +{ + [StaticConstructorOnStartup] + public abstract class Building_ColdStorage : Building, IRenameBuilding, IHaulDestination, IStoreSettingsParent, ILinkableStorageParent, IThingHolder + { + private static readonly Texture2D RenameTex = ContentFinder.Get("UI/Buttons/Rename"); + + protected ThingOwner thingOwner; + + private List items => thingOwner.InnerListForReading; + + private List ports = new List(); + + public string UniqueName { get => uniqueName; set => uniqueName = value; } + private string uniqueName; + public Building Building => this; + + public StorageSettings settings; + + //Initialized at spawn + public DefModExtension_Crate ModExtension_Crate = null; + + public abstract bool CanStoreMoreItems { get; } + // The maximum number of item stacks at this.Position: + // One item on each cell and the rest multi-stacked on Position? + public int MaxNumberItemsInternal => (ModExtension_Crate?.limit ?? int.MaxValue) + - def.Size.Area + 1; + public List StoredItems => items; + public int StoredItemsCount => items.Count; + public override string LabelNoCount => uniqueName ?? base.LabelNoCount; + public override string LabelCap => uniqueName ?? base.LabelCap; + public virtual bool CanReceiveIO => true; + public virtual bool Powered => true; + + public bool ForbidPawnAccess => ModExtension_Crate?.forbidPawnAccess ?? false; + + public virtual bool ForbidPawnInput => ForbidPawnAccess; + + public virtual bool ForbidPawnOutput => ForbidPawnAccess; + + public virtual bool HideItems => ModExtension_Crate?.hideItems ?? false; + + public virtual bool HideRightClickMenus => + ModExtension_Crate?.hideRightClickMenus ?? false; + + IntVec3 IHaulDestination.Position => this.Position; + + Map IHaulDestination.Map => this.Map; + + bool IStoreSettingsParent.StorageTabVisible => true; + + public bool AdvancedIOAllowed => false; + + public IntVec3 GetPosition => this.Position; + + public StorageSettings GetSettings => settings; + + public LocalTargetInfo GetTargetInfo => this; + + public bool CanUseIOPort => true; + + public void DeregisterPort(Building_StorageUnitIOBase port) + { + ports.Remove(port); + } + + public void RegisterPort(Building_StorageUnitIOBase port) + { + ports.Add(port); + } + + public override IEnumerable GetGizmos() + { + foreach (var g in base.GetGizmos()) + yield return g; + yield return new Command_Action + { + icon = RenameTex, + action = () => Find.WindowStack.Add(new Dialog_RenameMassStorageUnit(this)), + hotKey = KeyBindingDefOf.Misc1, + defaultLabel = "PRFRenameMassStorageUnitLabel".Translate(), + defaultDesc = "PRFRenameMassStorageUnitDesc".Translate() + }; + } + + public virtual string GetUIThingLabel() + { + return "PRFMassStorageUIThingLabel".Translate(StoredItemsCount); + } + + public virtual string GetITabString(int itemsSelected) + { + return "PRFItemsTabLabel".Translate(StoredItemsCount, itemsSelected); + } + + public virtual void RegisterNewItem(Thing newItem) + { + if (items.Contains(newItem)) + { + Log.Message($"dup: {newItem}"); + return; + } + + var items_arr = items.ToArray(); + for (var i = 0; i < items_arr.Length; i++) + { + var item = items_arr[i]; + //CanStackWith is already called by TryAbsorbStack... + //Is the Item Check really needed? + if (item.def.category == ThingCategory.Item) + item.TryAbsorbStack(newItem, true); + if (newItem.Destroyed) break; + } + + //Add a new stack of a thing + if (!newItem.Destroyed) + { + items.Add(newItem); + + //What appens if its full? + if (CanStoreMoreItems) + { + newItem.Position = Position; + } + if (newItem.Spawned) newItem.DeSpawn(); + } + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Collections.Look(ref ports, "ports", LookMode.Reference); + Scribe_Deep.Look(ref this.thingOwner, "thingowner",this); + Scribe_Values.Look(ref uniqueName, "uniqueName"); + Scribe_Deep.Look(ref settings, "settings", this); + ModExtension_Crate ??= def.GetModExtension(); + } + + public override string GetInspectString() + { + var original = base.GetInspectString(); + var stringBuilder = new StringBuilder(); + if (!string.IsNullOrEmpty(original)) stringBuilder.AppendLine(original); + stringBuilder.Append("PRF_TotalStacksNum".Translate(items.Count)); + return stringBuilder.ToString(); + } + + public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) + { + var thingsToSplurge = items; + for (var i = 0; i < thingsToSplurge.Count; i++) + if (thingsToSplurge[i].def.category == ThingCategory.Item) + { + //thingsToSplurge[i].DeSpawn(); + GenPlace.TryPlaceThing(thingsToSplurge[i], Position, Map, ThingPlaceMode.Near); + } + PatchStorageUtil.GetPRFMapComponent(Map).DeRegisterColdStorageBuilding(this); + base.DeSpawn(mode); + } + + public override void SpawnSetup(Map map, bool respawningAfterLoad) + { + base.SpawnSetup(map, respawningAfterLoad); + PatchStorageUtil.GetPRFMapComponent(Map).RegisterColdStorageBuilding(this); + ModExtension_Crate ??= def.GetModExtension(); + foreach (var port in ports) + { + if (port?.Spawned ?? false) + { + if (port.Map != map) + { + port.BoundStorageUnit = null; + } + } + } + + } + + public float GetItemWealth() + { + float output = 0; + var itemsc = items.Count; + for (int i = 0;i< itemsc; i++) + { + var item = items[i]; + output += item.MarketValue * item.stackCount; + } + + return output; + } + + public override void DrawGUIOverlay() + { + base.DrawGUIOverlay(); + if (Current.CameraDriver.CurrentZoom <= CameraZoomRange.Close) + GenMapUI.DrawThingLabel(this, LabelCap + "\n\r" + GetUIThingLabel()); + } + + public bool OutputItem(Thing item) + { + var outputCell = GetComp()?.CurrentCell ?? Position + new IntVec3(0, 0, -2); + return GenPlace.TryPlaceThing(item.SplitOff(item.stackCount), outputCell, Map, ThingPlaceMode.Near); + } + + //----------- For compatibility with Pick Up And Haul: ----------- + // (not used internally in any way) + // true if can store, capacity is how many can store (more than one stack possible) + public bool CapacityAt(Thing thing, IntVec3 cell, Map map, out int capacity) + { + //Some Sanity Checks + capacity = 0; + if (thing == null || map == null || map != this.Map || cell == null || !this.Spawned) + { + Log.Error("PRF DSU CapacityAt Sanity Check Error"); + return false; + } + thing = thing.GetInnerIfMinified(); + + //Check if thing can be stored based upon the storgae settings + if (!this.Accepts(thing)) + { + return false; + } + + //TODO Check if we want to forbid access if power is off + //if (!GetComp().PowerOn) return false; + + //Get List of items stored in the DSU + var storedItems = Position.GetThingList(Map).Where(t => t.def.category == ThingCategory.Item); + + //Find the Stack size for the thing + int maxstacksize = thing.def.stackLimit; + //Get capacity of partial Stacks + // So 45 Steel and 75 Steel and 11 Steel give 30+64 more capacity for steel + foreach (Thing partialStack in storedItems.Where(t => t.def == thing.def && t.stackCount < maxstacksize)) + { + capacity += maxstacksize - partialStack.stackCount; + } + + //capacity of empy slots + capacity += (MaxNumberItemsInternal - storedItems.Count()) * maxstacksize; + + //Access point: + if (cell != Position) + { + var maybeThing = Map.thingGrid.ThingAt(cell, ThingCategory.Item); + if (maybeThing != null) + { + if (maybeThing.def == thing.def) capacity += (thing.def.stackLimit - maybeThing.stackCount); + } + else + { + capacity += thing.def.stackLimit; + } + } + return capacity > 0; + } + + // ...The above? I think? But without needing to know how many + public bool StackableAt(Thing thing, IntVec3 cell, Map map) + { + return CapacityAt(thing, cell, map, out _); + } + + public bool Accepts(Thing t) + { + return settings.AllowedToAccept(t); + } + + StorageSettings IStoreSettingsParent.GetStoreSettings() + { + return settings; + } + + StorageSettings IStoreSettingsParent.GetParentStoreSettings() + { + StorageSettings fixedStorageSettings = def.building.fixedStorageSettings; + if (fixedStorageSettings != null) + { + return fixedStorageSettings; + } + return StorageSettings.EverStorableFixedSettings(); + } + + public override void PostMake() + { + base.PostMake(); + settings = new StorageSettings(this); + if (def.building.defaultStorageSettings != null) + { + settings.CopyFrom(def.building.defaultStorageSettings); + } + } + + public void HandleNewItem(Thing item) + { + RegisterNewItem(item); + } + + public void HandleMoveItem(Thing item) + { + //With the use of thingOwner this check might be redundent + if (items.Contains(item)) + { + items.Remove(item); + } + } + + public bool CanReciveThing(Thing item) + { + return settings.AllowedToAccept(item) && CanReceiveIO && CanStoreMoreItems; + } + + public void GetChildHolders(List outChildren) + { + + } + + public ThingOwner GetDirectlyHeldThings() + { + return thingOwner; + } + + + //Only used for Advanced IO + public bool HoldsPos(IntVec3 pos) + { + return false; + } + } +} \ No newline at end of file diff --git a/Source/ProjectRimFactory/Storage/Building_ColdStoragePowerd.cs b/Source/ProjectRimFactory/Storage/Building_ColdStoragePowerd.cs new file mode 100644 index 00000000..70d0ca81 --- /dev/null +++ b/Source/ProjectRimFactory/Storage/Building_ColdStoragePowerd.cs @@ -0,0 +1,166 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Verse; +using ProjectRimFactory.Storage.Editables; +using UnityEngine; + +namespace ProjectRimFactory.Storage +{ + [StaticConstructorOnStartup] + public class Building_ColdStoragePowered : Building_ColdStorage + { + private static Texture2D StoragePawnAccessSwitchIcon = ContentFinder.Get("PRFUi/dsu", true); + + //Initialized on spawn + private CompPowerTrader compPowerTrader = null; + + public override bool Powered => compPowerTrader?.PowerOn ?? false; + + public override bool CanStoreMoreItems => (Powered) && this.Spawned && + (ModExtension_Crate == null || StoredItemsCount < MaxNumberItemsInternal); + public override bool CanReceiveIO => base.CanReceiveIO && compPowerTrader.PowerOn && this.Spawned; + + public override bool ForbidPawnInput => this.ForbidPawnAccess || !this.pawnAccess || !this.CanStoreMoreItems; + + public override bool ForbidPawnOutput => this.ForbidPawnAccess || !this.pawnAccess; + + private bool pawnAccess = true; + + public void UpdatePowerConsumption() + { + compPowerTrader ??= GetComp(); + compPowerTrader.PowerOutput = -10 * StoredItemsCount; + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref pawnAccess, "pawnAccess", true); + compPowerTrader ??= GetComp(); + } + + protected override void ReceiveCompSignal(string signal) + { + base.ReceiveCompSignal(signal); + } + + public override void Tick() + { + base.Tick(); + if (this.IsHashIntervalTick(60)) + { + UpdatePowerConsumption(); + } + thingOwner.ThingOwnerTick(); + } + + public override void PostMapInit() + { + base.PostMapInit(); + compPowerTrader ??= GetComp(); + } + + public override IEnumerable GetGizmos() + { + foreach (Gizmo g in base.GetGizmos()) yield return g; + if (Prefs.DevMode) + { + yield return new Command_Action() + { + defaultLabel = "DEBUG: Debug actions", + action = () => + { + Find.WindowStack.Add(new FloatMenu(new List(DebugActions()))); + } + }; + } + + if (!this.ForbidPawnAccess) + { + yield return new Command_Toggle() + { + defaultLabel = "PRFPawnAccessLabel".Translate(), + isActive = () => this.pawnAccess, + toggleAction = () => this.pawnAccess = !this.pawnAccess, + defaultDesc = "PRFPawnAccessDesc".Translate(), + icon = StoragePawnAccessSwitchIcon + }; + } + } + + public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) + { + if (mode == DestroyMode.Deconstruct) + { + if (def.GetModExtension()?.destroyContainsItems ?? false) + { + this.StoredItems.Where(t => !t.Destroyed).ToList().ForEach(x => x.Destroy()); + } + } + base.DeSpawn(mode); + } + + protected virtual IEnumerable DebugActions() + { + yield return new FloatMenuOption("Update power consumption", UpdatePowerConsumption); + yield return new FloatMenuOption("Log item count", () => Log.Message(StoredItemsCount.ToString())); + } + + public override string GetUIThingLabel() + { + if ((def.GetModExtension()?.limit).HasValue) + { + return "PRFCrateUIThingLabel".Translate(StoredItemsCount, def.GetModExtension().limit); + } + else + { + return base.GetUIThingLabel(); + } + } + + public override string GetITabString(int itemsSelected) + { + if ((def.GetModExtension()?.limit).HasValue) + { + return "PRFItemsTabLabel_Crate".Translate(StoredItemsCount, def.GetModExtension().limit, itemsSelected); + } + else + { + return base.GetITabString(itemsSelected); + } + } + + //This Exists as I don't know how to call .Any() with CodeInstruction + //Can be removed if the Transpiler is Updated to inclued that + public static bool AnyPowerd(Map map) + { + return AllPowered(map).Any(); + } + + public static IEnumerable AllPowered(Map map) + { + foreach (Building_MassStorageUnitPowered item in map.listerBuildings.AllBuildingsColonistOfClass()) + { + CompPowerTrader comp = item.GetComp(); + if (comp == null || comp.PowerOn) + { + yield return item; + } + } + } + + public override void SpawnSetup(Map map, bool respawningAfterLoad) + { + base.SpawnSetup(map, respawningAfterLoad); + } + + public override void PostMake() + { + base.PostMake(); + thingOwner ??= new ThingOwner(this); + } + } +} diff --git a/Source/ProjectRimFactory/Storage/Building_IOPusher.cs b/Source/ProjectRimFactory/Storage/Building_IOPusher.cs index 71c5c833..ed8b94ed 100644 --- a/Source/ProjectRimFactory/Storage/Building_IOPusher.cs +++ b/Source/ProjectRimFactory/Storage/Building_IOPusher.cs @@ -25,6 +25,8 @@ public override IntVec3 WorkPosition { public override StorageIOMode IOMode { get => StorageIOMode.Output; set => _ = value; } + public override bool IsAdvancedPort => false; + public override void SpawnSetup(Map map, bool respawningAfterLoad) { base.SpawnSetup(map, respawningAfterLoad); diff --git a/Source/ProjectRimFactory/Storage/Building_MassStorageUnit.cs b/Source/ProjectRimFactory/Storage/Building_MassStorageUnit.cs index 5250dfb4..3fef565c 100644 --- a/Source/ProjectRimFactory/Storage/Building_MassStorageUnit.cs +++ b/Source/ProjectRimFactory/Storage/Building_MassStorageUnit.cs @@ -13,7 +13,7 @@ namespace ProjectRimFactory.Storage { [StaticConstructorOnStartup] public abstract class Building_MassStorageUnit : Building_Storage, IHideItem, IHideRightClickMenu, - IForbidPawnOutputItem, IForbidPawnInputItem ,IRenameBuilding + IForbidPawnOutputItem, IForbidPawnInputItem ,IRenameBuilding, ILinkableStorageParent { private static readonly Texture2D RenameTex = ContentFinder.Get("UI/Buttons/Rename"); @@ -23,6 +23,12 @@ public abstract class Building_MassStorageUnit : Building_Storage, IHideItem, IH public string UniqueName { get => uniqueName; set => uniqueName = value; } private string uniqueName; public Building Building => this; + public IntVec3 GetPosition => this.Position; + public StorageSettings GetSettings => settings; + + public bool CanUseIOPort => def.GetModExtension() != null; + + public LocalTargetInfo GetTargetInfo => this; //Initialized at spawn public DefModExtension_Crate ModExtension_Crate = null; @@ -64,6 +70,8 @@ public override void Notify_LostThing(Thing newItem) public virtual bool HideRightClickMenus => ModExtension_Crate?.hideRightClickMenus ?? false; + public bool AdvancedIOAllowed => true; + public void DeregisterPort(Building_StorageUnitIOBase port) { ports.Remove(port); @@ -166,10 +174,12 @@ public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) Map.GetComponent().DeRegisterIForbidPawnOutputItem(cell, this); } base.DeSpawn(mode); + ConditionalPatchHelper.Deregister(this); } public override void SpawnSetup(Map map, bool respawningAfterLoad) { + ConditionalPatchHelper.Register(this); base.SpawnSetup(map, respawningAfterLoad); Map.GetComponent().AddIHideRightClickMenu(this); foreach (var cell in this.OccupiedRect().Cells) @@ -179,6 +189,16 @@ public override void SpawnSetup(Map map, bool respawningAfterLoad) } ModExtension_Crate ??= def.GetModExtension(); RefreshStorage(); + foreach(var port in ports) + { + if (port?.Spawned ?? false) + { + if (port.Map != map) + { + port.BoundStorageUnit = null; + } + } + } } @@ -286,7 +306,24 @@ public bool StackableAt(Thing thing, IntVec3 cell, Map map) return CapacityAt(thing, cell, map, out _); } + public void HandleNewItem(Thing item) + { + //throw new System.NotImplementedException(); + } + public void HandleMoveItem(Thing item) + { + //throw new System.NotImplementedException(); + } + public bool CanReciveThing(Thing item) + { + return settings.AllowedToAccept(item) && CanReceiveIO && CanStoreMoreItems; + } + + public bool HoldsPos(IntVec3 pos) + { + return AllSlotCells()?.Contains(pos) ?? false; + } } } \ No newline at end of file diff --git a/Source/ProjectRimFactory/Storage/Building_MassStorageUnitPowered.cs b/Source/ProjectRimFactory/Storage/Building_MassStorageUnitPowered.cs index aa36b610..29a46753 100644 --- a/Source/ProjectRimFactory/Storage/Building_MassStorageUnitPowered.cs +++ b/Source/ProjectRimFactory/Storage/Building_MassStorageUnitPowered.cs @@ -21,7 +21,7 @@ public class Building_MassStorageUnitPowered : Building_MassStorageUnit public override bool CanStoreMoreItems => (Powered) && this.Spawned && (ModExtension_Crate == null || StoredItemsCount < MaxNumberItemsInternal); - public override bool CanReceiveIO => base.CanReceiveIO && compPowerTrader.PowerOn && this.Spawned; + public override bool CanReceiveIO => base.CanReceiveIO && Powered && this.Spawned; public override bool ForbidPawnInput => this.ForbidPawnAccess || !this.pawnAccess || !this.CanStoreMoreItems; @@ -150,25 +150,5 @@ public override string GetITabString(int itemsSelected) return base.GetITabString(itemsSelected); } } - - //This Exists as I don't know how to call .Any() with CodeInstruction - //Can be removed if the Transpiler is Updated to inclued that - public static bool AnyPowerd(Map map) - { - return AllPowered(map).Any(); - } - - public static IEnumerable AllPowered(Map map) - { - foreach (Building_MassStorageUnitPowered item in map.listerBuildings.AllBuildingsColonistOfClass()) - { - CompPowerTrader comp = item.GetComp(); - if (comp == null || comp.PowerOn) - { - yield return item; - } - } - } - } } diff --git a/Source/ProjectRimFactory/Storage/Building_StorageUnitIOPort.cs b/Source/ProjectRimFactory/Storage/Building_StorageUnitIOPort.cs index 6d0ffe04..60126729 100644 --- a/Source/ProjectRimFactory/Storage/Building_StorageUnitIOPort.cs +++ b/Source/ProjectRimFactory/Storage/Building_StorageUnitIOPort.cs @@ -28,7 +28,8 @@ public abstract class Building_StorageUnitIOBase : Building_Storage, IForbidPawn public static readonly Texture2D IOModeTex = ContentFinder.Get("PRFUi/IoIcon"); public StorageIOMode mode; - public Building_MassStorageUnit boundStorageUnit; + private Building linkedStorageParentBuilding; + public ILinkableStorageParent boundStorageUnit => linkedStorageParentBuilding as ILinkableStorageParent; protected StorageSettings outputStoreSettings; private OutputSettings outputSettings; @@ -36,6 +37,8 @@ public abstract class Building_StorageUnitIOBase : Building_Storage, IForbidPawn protected CompPowerTrader powerComp; + public abstract bool IsAdvancedPort { get; } + public virtual bool ShowLimitGizmo => true; @@ -68,7 +71,7 @@ public virtual StorageIOMode IOMode } } - public Building_MassStorageUnit BoundStorageUnit + public ILinkableStorageParent BoundStorageUnit { get { @@ -77,7 +80,7 @@ public Building_MassStorageUnit BoundStorageUnit set { boundStorageUnit?.DeregisterPort(this); - boundStorageUnit = value; + linkedStorageParentBuilding = (Building)value; value?.RegisterPort(this); Notify_NeedRefresh(); } @@ -123,7 +126,7 @@ public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref mode, "mode"); - Scribe_References.Look(ref boundStorageUnit, "boundStorageUnit"); + Scribe_References.Look(ref linkedStorageParentBuilding, "boundStorageUnit"); Scribe_Deep.Look(ref outputStoreSettings, "outputStoreSettings", this); Scribe_Deep.Look(ref outputSettings, "outputSettings", "IOPort_Minimum_UseTooltip", "IOPort_Maximum_UseTooltip"); Scribe_Values.Look(ref uniqueName, "uniqueName"); @@ -150,7 +153,11 @@ public override void SpawnSetup(Map map, bool respawningAfterLoad) base.SpawnSetup(map, respawningAfterLoad); powerComp = GetComp(); - if (boundStorageUnit?.Map != map) BoundStorageUnit = null; + //Issues occurs if the boundStorageUnit spawns after this... Needs a check form the other way + if (boundStorageUnit?.Map != map && (linkedStorageParentBuilding?.Spawned ?? false)) + { + BoundStorageUnit = null; + } } protected override void ReceiveCompSignal(string signal) @@ -215,15 +222,15 @@ public void RefreshStoreSettings() if (mode == StorageIOMode.Output) { settings = outputStoreSettings; - if (boundStorageUnit != null && settings.Priority != boundStorageUnit.settings.Priority) + if (boundStorageUnit != null && settings.Priority != boundStorageUnit.GetSettings.Priority) { //the setter of settings.Priority is expensive - settings.Priority = boundStorageUnit.settings.Priority; + settings.Priority = boundStorageUnit.GetSettings.Priority; } } else if (boundStorageUnit != null) { - settings = boundStorageUnit.settings; + settings = boundStorageUnit.GetSettings; } else { @@ -236,16 +243,9 @@ public virtual void RefreshInput() if (powerComp.PowerOn) { Thing item = WorkPosition.GetFirstItem(Map); - if (mode == StorageIOMode.Input && item != null && boundStorageUnit != null && boundStorageUnit.settings.AllowedToAccept(item) && boundStorageUnit.CanReceiveIO && boundStorageUnit.CanStoreMoreItems) + if (mode == StorageIOMode.Input && item != null && (boundStorageUnit?.CanReciveThing(item) ?? false)) { - foreach (IntVec3 cell in boundStorageUnit.AllSlotCells()) - { - if (cell.GetFirstItem(Map) == null) - { - boundStorageUnit.RegisterNewItem(item); - break; - } - } + boundStorageUnit.HandleNewItem(item); } } } @@ -294,7 +294,9 @@ protected virtual void RefreshOutput() // int count = Math.Min(item.stackCount, OutputSettings.CountNeededToReachMax(currentItem.stackCount, currentItem.def.stackLimit)); if (count > 0) { - currentItem.TryAbsorbStack(item.SplitOff(count), true); + var ThingToRemove = item.SplitOff(count); + if (item.stackCount <= 0) boundStorageUnit.HandleMoveItem(item); + currentItem.TryAbsorbStack(ThingToRemove, true); } } } @@ -303,7 +305,9 @@ protected virtual void RefreshOutput() // int count = OutputSettings.CountNeededToReachMax(0, item.stackCount); if (count > 0) { - currentItem = GenSpawn.Spawn(item.SplitOff(count), WorkPosition, Map); + var ThingToRemove = item.SplitOff(count); + if (item.stackCount <= 0) boundStorageUnit.HandleMoveItem(item); + currentItem = GenSpawn.Spawn(ThingToRemove, WorkPosition, Map); } } if (currentItem != null && !OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit)) @@ -314,20 +318,20 @@ protected virtual void RefreshOutput() // } } //Transfre a item back if it is either too few or disallowed - if (currentItem != null && (!settings.AllowedToAccept(currentItem) || !OutputSettings.SatisfiesMin(currentItem.stackCount)) && boundStorageUnit.settings.AllowedToAccept(currentItem)) + if (currentItem != null && (!settings.AllowedToAccept(currentItem) || !OutputSettings.SatisfiesMin(currentItem.stackCount)) && boundStorageUnit.GetSettings.AllowedToAccept(currentItem)) { currentItem.SetForbidden(false, false); - boundStorageUnit.RegisterNewItem(currentItem); + boundStorageUnit.HandleNewItem(currentItem); } //Transfer the diffrence back if it is too much - if (currentItem != null && (!OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit) && boundStorageUnit.settings.AllowedToAccept(currentItem))) + if (currentItem != null && (!OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit) && boundStorageUnit.GetSettings.AllowedToAccept(currentItem))) { int splitCount = -OutputSettings.CountNeededToReachMax(currentItem.stackCount, currentItem.def.stackLimit); if (splitCount > 0) { Thing returnThing = currentItem.SplitOff(splitCount); returnThing.SetForbidden(false, false); - boundStorageUnit.RegisterNewItem(returnThing); + boundStorageUnit.HandleNewItem(returnThing); } } if (currentItem != null) @@ -345,11 +349,12 @@ public override IEnumerable GetGizmos() defaultLabel = "PRFBoundStorageBuilding".Translate() + ": " + (boundStorageUnit?.LabelCap ?? "NoneBrackets".Translate()), action = () => { + //ILinkableStorageParent + List mylist = Map.listerBuildings.allBuildingsColonist.Where(b => (b as ILinkableStorageParent) != null && (b as ILinkableStorageParent).CanUseIOPort).ToList(); + if (IsAdvancedPort) mylist.RemoveAll(b => !(b as ILinkableStorageParent).AdvancedIOAllowed); List list = new List( - from Building_MassStorageUnit b in Find.CurrentMap.listerBuildings.AllBuildingsColonistOfClass() - where b.def.GetModExtension() != null - select new FloatMenuOption(b.LabelCap, () => SelectedPorts().ToList().ForEach(p => p.BoundStorageUnit = b)) - ); + mylist.Select(b => new FloatMenuOption(b.LabelCap, () => SelectedPorts().ToList().ForEach(p => p.BoundStorageUnit = (b as ILinkableStorageParent)))) + ) ; if (list.Count == 0) { list.Add(new FloatMenuOption("NoneBrackets".Translate(), null)); @@ -450,22 +455,16 @@ public override StorageIOMode IOMode } } + public override bool IsAdvancedPort => false; + public override void Notify_ReceivedThing(Thing newItem) { base.Notify_ReceivedThing(newItem); - if (mode == StorageIOMode.Input) - { - RefreshInput(); - } } public override void Notify_LostThing(Thing newItem) { base.Notify_LostThing(newItem); - if (mode == StorageIOMode.Output) - { - RefreshOutput(); - } } public override void RefreshInput() @@ -473,16 +472,9 @@ public override void RefreshInput() if (powerComp.PowerOn) { Thing item = Position.GetFirstItem(Map); - if (mode == StorageIOMode.Input && item != null && boundStorageUnit != null && boundStorageUnit.settings.AllowedToAccept(item) && boundStorageUnit.CanReceiveIO && boundStorageUnit.CanStoreMoreItems) + if (mode == StorageIOMode.Input && item != null && (boundStorageUnit?.CanReciveThing(item) ?? false)) { - foreach (IntVec3 cell in boundStorageUnit.AllSlotCells()) - { - if (cell.GetFirstItem(Map) == null) - { - boundStorageUnit.RegisterNewItem(item); - break; - } - } + boundStorageUnit.HandleNewItem(item); } } } @@ -563,6 +555,7 @@ protected override void RefreshOutput() //For SplitOff "MakeThing" is expensive //For TryAbsorbStack "Destroy" is expensive AbsorbAmmount(ref currentItem, ref Mything, count); + if (Mything.stackCount <= 0) boundStorageUnit.HandleMoveItem(Mything); } } } @@ -573,7 +566,9 @@ protected override void RefreshOutput() { //Nothing on the IO Port - grab thing from storage and place it on the port //For SplitOff "MakeThing" is expensive - currentItem = GenSpawn.Spawn(item.SplitOff(count), Position, Map); + var ThingToRemove = item.SplitOff(count); + if (item.stackCount <= 0 || ThingToRemove == item) boundStorageUnit.HandleMoveItem(item); + currentItem = GenSpawn.Spawn(ThingToRemove, Position, Map); } } if (currentItem != null && !OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit)) @@ -584,20 +579,20 @@ protected override void RefreshOutput() } } //Transfre a item back if it is either too few or disallowed - if (currentItem != null && (!settings.AllowedToAccept(currentItem) || !OutputSettings.SatisfiesMin(currentItem.stackCount)) && boundStorageUnit.settings.AllowedToAccept(currentItem)) + if (currentItem != null && (!settings.AllowedToAccept(currentItem) || !OutputSettings.SatisfiesMin(currentItem.stackCount)) && boundStorageUnit.GetSettings.AllowedToAccept(currentItem)) { currentItem.SetForbidden(false, false); - boundStorageUnit.RegisterNewItem(currentItem); + boundStorageUnit.HandleNewItem(currentItem); } //Transfer the diffrence back if it is too much - if (currentItem != null && (!OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit) && boundStorageUnit.settings.AllowedToAccept(currentItem))) + if (currentItem != null && (!OutputSettings.SatisfiesMax(currentItem.stackCount, currentItem.def.stackLimit) && boundStorageUnit.GetSettings.AllowedToAccept(currentItem))) { int splitCount = -OutputSettings.CountNeededToReachMax(currentItem.stackCount, currentItem.def.stackLimit); if (splitCount > 0) { Thing returnThing = currentItem.SplitOff(splitCount); returnThing.SetForbidden(false, false); - boundStorageUnit.RegisterNewItem(returnThing); + boundStorageUnit.HandleNewItem(returnThing); } } if (currentItem != null) diff --git a/Source/ProjectRimFactory/Storage/ILinkableStorageParent.cs b/Source/ProjectRimFactory/Storage/ILinkableStorageParent.cs new file mode 100644 index 00000000..2ce05f9c --- /dev/null +++ b/Source/ProjectRimFactory/Storage/ILinkableStorageParent.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using RimWorld; +using Verse; + +namespace ProjectRimFactory.Storage +{ + /// + /// Interface for buildings that can have IO Ports link to them + /// + public interface ILinkableStorageParent + { + public List StoredItems { get; } + + public bool AdvancedIOAllowed { get; } + + public void HandleNewItem(Thing item); + + public void HandleMoveItem(Thing item); + + public bool CanReciveThing(Thing item); + + public bool HoldsPos(IntVec3 pos); + + //What is that even for ?? + public void DeregisterPort(Building_StorageUnitIOBase port); + public void RegisterPort(Building_StorageUnitIOBase port); + + public StorageSettings GetSettings { get; } + + public IntVec3 GetPosition { get; } + + public string LabelCap { get; } + public bool CanReceiveIO { get; } + public Map Map { get; } + + public int StoredItemsCount { get; } + + public string GetITabString(int itemsSelected); + + public LocalTargetInfo GetTargetInfo { get; } + + public bool OutputItem(Thing item); + + public bool Powered { get; } + + public bool CanUseIOPort { get; } + + } +} \ No newline at end of file diff --git a/Source/ProjectRimFactory/Storage/UI/ITab_Items.cs b/Source/ProjectRimFactory/Storage/UI/ITab_Items.cs index 5b7711a9..e747c3a3 100644 --- a/Source/ProjectRimFactory/Storage/UI/ITab_Items.cs +++ b/Source/ProjectRimFactory/Storage/UI/ITab_Items.cs @@ -40,10 +40,10 @@ public ITab_Items() labelKey = "PRFItemsTab"; } - private static Building_MassStorageUnit oldSelectedMassStorageUnit = null; + private static ILinkableStorageParent oldSelectedMassStorageUnit = null; - public Building_MassStorageUnit SelectedMassStorageUnit => - IOPortSelected ? SelectedIOPort.BoundStorageUnit : (Building_MassStorageUnit) SelThing; + public ILinkableStorageParent SelectedMassStorageUnit => + IOPortSelected ? SelectedIOPort.BoundStorageUnit : (ILinkableStorageParent) SelThing; public override bool IsVisible => IOPortSelected ? SelectedIOPort.BoundStorageUnit?.CanReceiveIO ?? false : true; @@ -144,8 +144,8 @@ orderby t.Label descending //Do it once as they are all on the same spot in the DSU //Even if is where to have multible sport's that way should work I think - pawnCanReach_Touch_Deadly = pawns.Where(p => p.CanReach(SelectedMassStorageUnit, PathEndMode.ClosestTouch, Danger.Deadly)).ToList(); - pawnCanReach_Oncell_Deadly = pawns.Where(p => p.CanReach(SelectedMassStorageUnit, PathEndMode.OnCell, Danger.Deadly)).ToList(); + pawnCanReach_Touch_Deadly = pawns.Where(p => p.CanReach(SelectedMassStorageUnit.GetTargetInfo, PathEndMode.ClosestTouch, Danger.Deadly)).ToList(); + pawnCanReach_Oncell_Deadly = pawns.Where(p => p.CanReach(SelectedMassStorageUnit.GetTargetInfo, PathEndMode.OnCell, Danger.Deadly)).ToList(); @@ -191,7 +191,7 @@ orderby t.Label descending // Credits to LWM Deep Storage :) private void DrawThingRow(ref float y, float width, Thing thing, List colonists) { - if (thing == null || !thing.Spawned) return; // not here, whatever happened... + //if (thing == null || !thing.Spawned) return; // not here, whatever happened... //each call to LabelCap also accesses MaxHitPoints therefor it is read here slightly diffrently; @@ -307,9 +307,13 @@ private void dropThing(Thing thing) var item = SelectedMassStorageUnit .StoredItems.Where(i => i == thing).ToList(); if (IOPortSelected && SelectedIOPort.OutputItem(item[0])) + { itemsToShow.Remove(thing); + } else if (SelectedMassStorageUnit.OutputItem(item[0])) + { itemsToShow.Remove(thing); + } } diff --git a/Textures/Storage/ColdStorageUnit.png b/Textures/Storage/ColdStorageUnit.png new file mode 100644 index 00000000..a8c3bfaa Binary files /dev/null and b/Textures/Storage/ColdStorageUnit.png differ