public virtual bool TryAbsorbStack(Thing other, bool respectStackLimit) { if (!CanStackWith(other)) { return(false); } int num = ThingUtility.TryAbsorbStackNumToTake(this, other, respectStackLimit); if (def.useHitPoints) { HitPoints = Mathf.CeilToInt((float)(HitPoints * stackCount + other.HitPoints * num) / (float)(stackCount + num)); } stackCount += num; other.stackCount -= num; StealAIDebugDrawer.Notify_ThingChanged(this); if (Spawned) { Map.listerMergeables.Notify_ThingStackChanged(this); } if (other.stackCount <= 0) { other.Destroy(); return(true); } return(false); }
/// <summary> /// destroying a resource outright causes too much overhead: fog, area reveal, pathing, roof updates, etc /// we just want to replace it. So, we manually strip it out of the map and do some cleanup. /// The following is Thing.Despawn code with the unnecessary (for buildings, ar least) parts stripped out, plus key parts from Building.Despawn /// TODO: This approach may break with future releases (if thing despawning changes), so it's worth checking over. /// </summary> private static void SneakilyDestroyResource(Thing res) { var map = res.Map; RegionListersUpdater.DeregisterInRegions(res, map); map.spawnedThings.Remove(res); map.listerThings.Remove(res); map.thingGrid.Deregister(res); map.coverGrid.DeRegister(res); map.tooltipGiverList.Notify_ThingDespawned(res); if (res.def.graphicData != null && res.def.graphicData.Linked) { map.linkGrid.Notify_LinkerCreatedOrDestroyed(res); map.mapDrawer.MapMeshDirty(res.Position, MapMeshFlag.Things, true, false); } Find.Selector.Deselect(res); res.DirtyMapMesh(map); if (res.def.drawerType != DrawerType.MapMeshOnly) { map.dynamicDrawManager.DeRegisterDrawable(res); } ReflectionCache.Thing_State.SetValue(res, res.def.DiscardOnDestroyed ? ThingDiscardedState : ThingMemoryState); Find.TickManager.DeRegisterAllTickabilityFor(res); map.attackTargetsCache.Notify_ThingDespawned(res); StealAIDebugDrawer.Notify_ThingChanged(res); // building-specific cleanup var b = (Building)res; if (res.def.IsEdifice()) { map.edificeGrid.DeRegister(b); } var sustainer = (Sustainer)ReflectionCache.Building_SustainerAmbient.GetValue(res); if (sustainer != null) { sustainer.End(); } map.mapDrawer.MapMeshDirty(b.Position, MapMeshFlag.Buildings); map.glowGrid.MarkGlowGridDirty(b.Position); map.listerBuildings.Remove((Building)res); map.listerBuildingsRepairable.Notify_BuildingDeSpawned(b); map.designationManager.Notify_BuildingDespawned(b); }
public virtual bool TryAbsorbStack(Thing other, bool respectStackLimit) { if (!this.CanStackWith(other)) { return(false); } int num = ThingUtility.TryAbsorbStackNumToTake(this, other, respectStackLimit); if (this.def.useHitPoints) { this.HitPoints = Mathf.CeilToInt((float)(this.HitPoints * this.stackCount + other.HitPoints * num) / (float)(this.stackCount + num)); } this.stackCount += num; other.stackCount -= num; StealAIDebugDrawer.Notify_ThingChanged(this); if (other.stackCount <= 0) { other.Destroy(DestroyMode.Vanish); return(true); } return(false); }
public override void DeSpawn() { if (this.Destroyed) { Log.Error("Tried to despawn " + this.ToStringSafe() + " which is already destroyed."); } else if (!this.Spawned) { Log.Error("Tried to despawn " + this.ToStringSafe() + " which is not spawned."); } else { Map map = this.Map; RegionListersUpdater.DeregisterInRegions(this, map); map.spawnedThings.Remove(this); map.listerThings.Remove(this); map.thingGrid.Deregister(this, false); map.coverGrid.DeRegister(this); if (this.def.receivesSignals) { Find.SignalManager.DeregisterReceiver(this); } map.tooltipGiverList.Notify_ThingDespawned(this); if (this.def.graphicData != null && this.def.graphicData.Linked) { map.linkGrid.Notify_LinkerCreatedOrDestroyed(this); map.mapDrawer.MapMeshDirty(this.Position, MapMeshFlag.Things, true, false); } Find.Selector.Deselect(this); this.DirtyMapMesh(map); if (this.def.drawerType != DrawerType.MapMeshOnly) { map.dynamicDrawManager.DeRegisterDrawable(this); } Region validRegionAt_NoRebuild = map.regionGrid.GetValidRegionAt_NoRebuild(this.Position); Room room = (validRegionAt_NoRebuild != null) ? validRegionAt_NoRebuild.Room : null; if (room != null) { room.Notify_ContainedThingSpawnedOrDespawned(this); } if (this.def.AffectsRegions) { map.regionDirtyer.Notify_ThingAffectingRegionsDespawned(this); } if (this.def.pathCost != 0 || this.def.passability == Traversability.Impassable) { map.pathGrid.RecalculatePerceivedPathCostUnderThing(this); } if (this.def.AffectsReachability) { map.reachability.ClearCache(); } Find.TickManager.DeRegisterAllTickabilityFor(this); this.mapIndexOrState = -1; if (this.def.category == ThingCategory.Item) { map.listerHaulables.Notify_DeSpawned(this); } map.attackTargetsCache.Notify_ThingDespawned(this); StealAIDebugDrawer.Notify_ThingChanged(this); if (this is IThingHolder && Find.ColonistBar != null) { Find.ColonistBar.MarkColonistsDirty(); } if (this.def.category == ThingCategory.Item) { SlotGroup slotGroup = this.Position.GetSlotGroup(map); if (slotGroup != null && slotGroup.parent != null) { slotGroup.parent.Notify_LostThing(this); } } } }
public override void SpawnSetup(Map map, bool respawningAfterLoad) { if (this.Destroyed) { Log.Error("Spawning destroyed thing " + this + " at " + this.Position + ". Correcting."); this.mapIndexOrState = -1; if (this.HitPoints <= 0 && this.def.useHitPoints) { this.HitPoints = 1; } } if (this.Spawned) { Log.Error("Tried to spawn already-spawned thing " + this + " at " + this.Position); } else { int num = Find.Maps.IndexOf(map); if (num < 0) { Log.Error("Tried to spawn thing " + this + ", but the map provided does not exist."); } else { if (this.stackCount > this.def.stackLimit) { Log.Error("Spawned " + this + " with stackCount " + this.stackCount + " but stackLimit is " + this.def.stackLimit + ". Truncating."); this.stackCount = this.def.stackLimit; } this.mapIndexOrState = (sbyte)num; RegionListersUpdater.RegisterInRegions(this, map); if (!map.spawnedThings.TryAdd(this, false)) { Log.Error("Couldn't add thing " + this + " to spawned things."); } map.listerThings.Add(this); map.thingGrid.Register(this); if (Find.TickManager != null) { Find.TickManager.RegisterAllTickabilityFor(this); } this.DirtyMapMesh(map); if (this.def.drawerType != DrawerType.MapMeshOnly) { map.dynamicDrawManager.RegisterDrawable(this); } map.tooltipGiverList.Notify_ThingSpawned(this); if (this.def.graphicData != null && this.def.graphicData.Linked) { map.linkGrid.Notify_LinkerCreatedOrDestroyed(this); map.mapDrawer.MapMeshDirty(this.Position, MapMeshFlag.Things, true, false); } if (!this.def.CanOverlapZones) { map.zoneManager.Notify_NoZoneOverlapThingSpawned(this); } if (this.def.AffectsRegions) { map.regionDirtyer.Notify_ThingAffectingRegionsSpawned(this); } if (this.def.pathCost != 0 || this.def.passability == Traversability.Impassable) { map.pathGrid.RecalculatePerceivedPathCostUnderThing(this); } if (this.def.AffectsReachability) { map.reachability.ClearCache(); } map.coverGrid.Register(this); if (this.def.category == ThingCategory.Item) { map.listerHaulables.Notify_Spawned(this); } map.attackTargetsCache.Notify_ThingSpawned(this); Region validRegionAt_NoRebuild = map.regionGrid.GetValidRegionAt_NoRebuild(this.Position); Room room = (validRegionAt_NoRebuild != null) ? validRegionAt_NoRebuild.Room : null; if (room != null) { room.Notify_ContainedThingSpawnedOrDespawned(this); } StealAIDebugDrawer.Notify_ThingChanged(this); if (this is IThingHolder && Find.ColonistBar != null) { Find.ColonistBar.MarkColonistsDirty(); } if (this.def.category == ThingCategory.Item) { SlotGroup slotGroup = this.Position.GetSlotGroup(map); if (slotGroup != null && slotGroup.parent != null) { slotGroup.parent.Notify_ReceivedThing(this); } } if (this.def.receivesSignals) { Find.SignalManager.RegisterReceiver(this); } } } }
public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) { if (Destroyed) { Log.Error("Tried to despawn " + this.ToStringSafe() + " which is already destroyed."); return; } if (!Spawned) { Log.Error("Tried to despawn " + this.ToStringSafe() + " which is not spawned."); return; } Map map = Map; RegionListersUpdater.DeregisterInRegions(this, map); map.spawnedThings.Remove(this); map.listerThings.Remove(this); map.thingGrid.Deregister(this); map.coverGrid.DeRegister(this); if (def.receivesSignals) { Find.SignalManager.DeregisterReceiver(this); } map.tooltipGiverList.Notify_ThingDespawned(this); if (def.graphicData != null && def.graphicData.Linked) { map.linkGrid.Notify_LinkerCreatedOrDestroyed(this); map.mapDrawer.MapMeshDirty(Position, MapMeshFlag.Things, regenAdjacentCells: true, regenAdjacentSections: false); } if (Find.Selector.IsSelected(this)) { Find.Selector.Deselect(this); Find.MainButtonsRoot.tabs.Notify_SelectedObjectDespawned(); } DirtyMapMesh(map); if (def.drawerType != DrawerType.MapMeshOnly) { map.dynamicDrawManager.DeRegisterDrawable(this); } (map.regionGrid.GetValidRegionAt_NoRebuild(Position)?.Room)?.Notify_ContainedThingSpawnedOrDespawned(this); if (def.AffectsRegions) { map.regionDirtyer.Notify_ThingAffectingRegionsDespawned(this); } if (def.pathCost != 0 || def.passability == Traversability.Impassable) { map.pathGrid.RecalculatePerceivedPathCostUnderThing(this); } if (def.AffectsReachability) { map.reachability.ClearCache(); } Find.TickManager.DeRegisterAllTickabilityFor(this); mapIndexOrState = -1; if (def.category == ThingCategory.Item) { map.listerHaulables.Notify_DeSpawned(this); map.listerMergeables.Notify_DeSpawned(this); } map.attackTargetsCache.Notify_ThingDespawned(this); map.physicalInteractionReservationManager.ReleaseAllForTarget(this); StealAIDebugDrawer.Notify_ThingChanged(this); IHaulDestination haulDestination = this as IHaulDestination; if (haulDestination != null) { map.haulDestinationManager.RemoveHaulDestination(haulDestination); } if (this is IThingHolder && Find.ColonistBar != null) { Find.ColonistBar.MarkColonistsDirty(); } if (def.category == ThingCategory.Item) { SlotGroup slotGroup = Position.GetSlotGroup(map); if (slotGroup != null && slotGroup.parent != null) { slotGroup.parent.Notify_LostThing(this); } } QuestUtility.SendQuestTargetSignals(questTags, "Despawned", this.Named("SUBJECT")); }
public override void SpawnSetup(Map map, bool respawningAfterLoad) { if (Destroyed) { Log.Error(string.Concat("Spawning destroyed thing ", this, " at ", Position, ". Correcting.")); mapIndexOrState = -1; if (HitPoints <= 0 && def.useHitPoints) { HitPoints = 1; } } if (Spawned) { Log.Error(string.Concat("Tried to spawn already-spawned thing ", this, " at ", Position)); return; } int num = Find.Maps.IndexOf(map); if (num < 0) { Log.Error(string.Concat("Tried to spawn thing ", this, ", but the map provided does not exist.")); return; } if (stackCount > def.stackLimit) { Log.Error(string.Concat("Spawned ", this, " with stackCount ", stackCount, " but stackLimit is ", def.stackLimit, ". Truncating.")); stackCount = def.stackLimit; } mapIndexOrState = (sbyte)num; RegionListersUpdater.RegisterInRegions(this, map); if (!map.spawnedThings.TryAdd(this, canMergeWithExistingStacks: false)) { Log.Error(string.Concat("Couldn't add thing ", this, " to spawned things.")); } map.listerThings.Add(this); map.thingGrid.Register(this); if (Find.TickManager != null) { Find.TickManager.RegisterAllTickabilityFor(this); } DirtyMapMesh(map); if (def.drawerType != DrawerType.MapMeshOnly) { map.dynamicDrawManager.RegisterDrawable(this); } map.tooltipGiverList.Notify_ThingSpawned(this); if (def.graphicData != null && def.graphicData.Linked) { map.linkGrid.Notify_LinkerCreatedOrDestroyed(this); map.mapDrawer.MapMeshDirty(Position, MapMeshFlag.Things, regenAdjacentCells: true, regenAdjacentSections: false); } if (!def.CanOverlapZones) { map.zoneManager.Notify_NoZoneOverlapThingSpawned(this); } if (def.AffectsRegions) { map.regionDirtyer.Notify_ThingAffectingRegionsSpawned(this); } if (def.pathCost != 0 || def.passability == Traversability.Impassable) { map.pathGrid.RecalculatePerceivedPathCostUnderThing(this); } if (def.AffectsReachability) { map.reachability.ClearCache(); } map.coverGrid.Register(this); if (def.category == ThingCategory.Item) { map.listerHaulables.Notify_Spawned(this); map.listerMergeables.Notify_Spawned(this); } map.attackTargetsCache.Notify_ThingSpawned(this); (map.regionGrid.GetValidRegionAt_NoRebuild(Position)?.Room)?.Notify_ContainedThingSpawnedOrDespawned(this); StealAIDebugDrawer.Notify_ThingChanged(this); IHaulDestination haulDestination = this as IHaulDestination; if (haulDestination != null) { map.haulDestinationManager.AddHaulDestination(haulDestination); } if (this is IThingHolder && Find.ColonistBar != null) { Find.ColonistBar.MarkColonistsDirty(); } if (def.category == ThingCategory.Item) { SlotGroup slotGroup = Position.GetSlotGroup(map); if (slotGroup != null && slotGroup.parent != null) { slotGroup.parent.Notify_ReceivedThing(this); } } if (def.receivesSignals) { Find.SignalManager.RegisterReceiver(this); } if (!respawningAfterLoad) { QuestUtility.SendQuestTargetSignals(questTags, "Spawned", this.Named("SUBJECT")); } }
internal void _SpawnSetup() { if (this.Destroyed) { Log.Error(string.Concat(new object[] { "Spawning destroyed thing ", this, " at ", this.Position, ". Correcting." })); SetThingStateInt(this, ThingState.Unspawned); if (this.HitPoints <= 0 && this.def.useHitPoints) { this.HitPoints = 1; } } if (this.Spawned) { Log.Error(string.Concat(new object[] { "Tried to spawn already-spawned thing ", this, " at ", this.Position })); return; } this.holder = null; SetThingStateInt(this, ThingState.Spawned); Find.Map.listerThings.Add(this); if (Find.TickManager != null) { Find.TickManager.RegisterAllTickabilityFor(this); } if (this.def.drawerType != DrawerType.RealtimeOnly) { CellRect.CellRectIterator iterator = this.OccupiedRect().GetIterator(); while (!iterator.Done()) { Find.Map.mapDrawer.MapMeshDirty(iterator.Current, MapMeshFlag.Things); iterator.MoveNext(); } } if (this.def.drawerType != DrawerType.MapMeshOnly) { Find.DynamicDrawManager.RegisterDrawable(this); } if (this.def.hasTooltip) { Find.TooltipGiverList.RegisterTooltipGiver(this); } if (this.def.graphicData != null && this.def.graphicData.Linked) { LinkGrid.Notify_LinkerCreatedOrDestroyed(this); Find.MapDrawer.MapMeshDirty(this.Position, MapMeshFlag.Things, true, false); } if (!this.def.CanOverlapZones) { rNotify_NoZoneOverlapThingSpawned(this); } if (this.def.regionBarrier) { rNotify_BarrierSpawned(this); } if (this.def.pathCost != 0 || this.def.passability == Traversability.Impassable) { Find.PathGrid.RecalculatePerceivedPathCostUnderThing(this); } if (this.def.passability == Traversability.Impassable) { Reachability.ClearCache(); } Find.CoverGrid.Register(this); if (this.def.category == ThingCategory.Item) { ListerHaulables.Notify_Spawned(this); } Find.AttackTargetsCache.Notify_ThingSpawned(this); Region validRegionAt_NoRebuild = Find.RegionGrid.GetValidRegionAt_NoRebuild(this.Position); Room room = (validRegionAt_NoRebuild != null) ? validRegionAt_NoRebuild.Room : null; if (room != null) { room.Notify_ContainedThingSpawnedOrDespawned(this); } if (this.def.category == ThingCategory.Item) { Building_Door building_Door = this.Position.GetEdifice() as Building_Door; if (building_Door != null) { building_Door.Notify_ItemSpawnedOrDespawnedOnTop(this); } } StealAIDebugDrawer.Notify_ThingChanged(this); }
public static bool Prefix(Thing __instance, Thing other, bool respectStackLimit, ref bool __result) { Mod.Debug("Thing.TryAbsorbStack begin"); if (!Limits.HasStackLimit(__instance)) { return(true); } if (!__instance.CanStackWith(other)) { __result = false; return(false); } int num; if (respectStackLimit) { var t = Limits.CalculateStackLimit(__instance) - __instance.stackCount; if (t < 0) { t = 0; } num = Mathf.Min(other.stackCount, t); } else { num = other.stackCount; } if (num <= 0) { __result = false; return(false); } if (__instance.def.useHitPoints) { __instance.HitPoints = Mathf.CeilToInt(((__instance.HitPoints * __instance.stackCount) + (other.HitPoints * num)) / (float)(__instance.stackCount + num)); } __instance.stackCount += num; other.stackCount -= num; StealAIDebugDrawer.Notify_ThingChanged(__instance); if (__instance.Spawned) { __instance.Map.listerMergeables.Notify_ThingStackChanged(__instance); } if (other.stackCount <= 0) { other.Destroy(); __result = true; } else { __result = false; } return(false); }