diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index fd734bf..08dc8cc 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs index 6e3f1d8..16079ec 100644 --- a/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs +++ b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using RimWorld; @@ -66,14 +66,14 @@ namespace ArachnaeSwarm this.graceTicks--; return; } - if (this.Props.hungerRelative && this.pawn.Starving()) + if (this.Props.hungerRelative && IsHungry(this.pawn, this.myDebug)) { int num = (int)(this.RandomGraceDays() * 60000f); this.hungerReset++; this.graceTicks = num; return; } - if (this.Props.healthRelative && this.pawn.Starving()) + if (this.Props.healthRelative && IsInjured(this.pawn, this.myDebug)) { int num2 = (int)(this.RandomGraceDays() * 60000f); this.healthReset++; @@ -350,7 +350,7 @@ namespace ArachnaeSwarm if (this.Props.animalThing) { - // 动物生成逻辑保持不变 + // 鍔ㄧ墿鐢熸垚閫昏緫淇濇寔涓嶅彉 if (this.Props.spawnMaxAdjacent > 0 && pawn.Map.mapPawns.AllPawns.Where(delegate(Pawn mP) { ThingDef defToCompare = this.Props.animalThing ? this.Props.animalToSpawn?.race : this.Props.thingToSpawn; @@ -394,7 +394,7 @@ namespace ArachnaeSwarm i++; continue; } - if (PawnUtility.ShouldSendNotificationAbout(pawn) || PawnUtility.ShouldSendNotificationAbout(pawn)) + if (PawnUtility.ShouldSendNotificationAbout(pawn)) { Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.PositiveEvent, true); } @@ -402,10 +402,10 @@ namespace ArachnaeSwarm } else { - // 重新设计物品生成逻辑:按优先级顺序尝试 + // 閲嶆柊璁捐鐗╁搧鐢熸垚閫昏緫锛氭寜浼樺厛绾ч『搴忓皾璇? bool success = TrySpawnItemWithPriority(pawn); - // === 新增:如果配置了销毁随机部位,在成功生成物品后执行 === + // === 鏂板锛氬鏋滈厤缃簡閿€姣侀殢鏈洪儴浣嶏紝鍦ㄦ垚鍔熺敓鎴愮墿鍝佸悗鎵ц === if (success && this.Props.destroyRandomBodyPart) { DestroyRandomBodyPart(pawn); @@ -415,7 +415,7 @@ namespace ArachnaeSwarm } } - // 新增:销毁随机身体部位(参考 CompAbilityEffect_DestroyOwnBodyPart) + // 鏂板锛氶攢姣侀殢鏈鸿韩浣撻儴浣嶏紙鍙傝€?CompAbilityEffect_DestroyOwnBodyPart锛? private void DestroyRandomBodyPart(Pawn pawn) { try @@ -426,7 +426,7 @@ namespace ArachnaeSwarm return; } - // 获取所有可以销毁的身体部位 + // 鑾峰彇鎵€鏈夊彲浠ラ攢姣佺殑韬綋閮ㄤ綅 List possibleParts = GetDestroyableBodyParts(pawn); if (possibleParts.Count == 0) @@ -435,7 +435,7 @@ namespace ArachnaeSwarm return; } - // 随机选择一个部位 + // 闅忔満閫夋嫨涓€涓儴浣? BodyPartRecord partToDestroy = possibleParts.RandomElement(); if (partToDestroy == null) @@ -444,10 +444,10 @@ namespace ArachnaeSwarm return; } - // 记录部位名称 - string partName = partToDestroy.def?.label ?? "未知部位"; + // 璁板綍閮ㄤ綅鍚嶇О + string partName = partToDestroy.def?.label ?? "鏈煡閮ㄤ綅"; - // 添加缺失部位hediff + // 娣诲姞缂哄け閮ㄤ綅hediff pawn.health.AddHediff(HediffDefOf.MissingBodyPart, partToDestroy); Warn($"Destroyed {partName} on {pawn.LabelShort}", this.myDebug); @@ -458,7 +458,7 @@ namespace ArachnaeSwarm } } - // 新增:获取可以销毁的身体部位列表 + // 鏂板锛氳幏鍙栧彲浠ラ攢姣佺殑韬綋閮ㄤ綅鍒楄〃 private List GetDestroyableBodyParts(Pawn pawn) { List destroyableParts = new List(); @@ -466,22 +466,25 @@ namespace ArachnaeSwarm if (pawn?.health?.hediffSet == null) return destroyableParts; - // 获取所有身体部位 + // 鑾峰彇鎵€鏈夎韩浣撻儴浣? List allParts = pawn.RaceProps.body.AllParts; foreach (BodyPartRecord part in allParts) { - // 排除核心部位(避免死亡) + // 鎺掗櫎鏍稿績閮ㄤ綅锛堥伩鍏嶆浜★級 if (IsCriticalBodyPart(part)) continue; - // 排除已经缺失的部位 + // 鎺掗櫎宸茬粡缂哄け鐨勯儴浣? if (pawn.health.hediffSet.PartIsMissing(part)) continue; - // 排除已经有严重伤害的部位(可选) + // 鎺掗櫎宸茬粡鏈変弗閲嶄激瀹崇殑閮ㄤ綅锛堝彲閫夛級 if (pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part)) continue; + + if (PartOrAnyDescendantHasDirectlyAddedParts(pawn, part)) + continue; destroyableParts.Add(part); } @@ -489,34 +492,34 @@ namespace ArachnaeSwarm return destroyableParts; } - // 新增:检查是否是关键身体部位 + // 鏂板锛氭鏌ユ槸鍚︽槸鍏抽敭韬綋閮ㄤ綅 private bool IsCriticalBodyPart(BodyPartRecord part) { if (part == null) return false; - // 根据标签判断是否为关键部位 + // 鏍规嵁鏍囩鍒ゆ柇鏄惁涓哄叧閿儴浣? if (part.def.tags != null) { - // 这些标签通常表示关键部位 - if (part.def.tags.Contains(BodyPartTagDefOf.ConsciousnessSource) || // 意识源(大脑) - part.def.tags.Contains(BodyPartTagDefOf.BloodPumpingSource) || // 血液泵源(心脏) - part.def.tags.Contains(BodyPartTagDefOf.BreathingSource) || // 呼吸源(肺) - part.def.tags.Contains(BodyPartTagDefOf.MetabolismSource) // 代谢源(肝脏) + // 杩欎簺鏍囩閫氬父琛ㄧず鍏抽敭閮ㄤ綅 + if (part.def.tags.Contains(BodyPartTagDefOf.ConsciousnessSource) || // 鎰忚瘑婧愶紙澶ц剳锛? + part.def.tags.Contains(BodyPartTagDefOf.BloodPumpingSource) || // 琛€娑叉车婧愶紙蹇冭剰锛? + part.def.tags.Contains(BodyPartTagDefOf.BreathingSource) || // 鍛煎惛婧愶紙鑲猴級 + part.def.tags.Contains(BodyPartTagDefOf.MetabolismSource) // 浠h阿婧愶紙鑲濊剰锛? ) { return true; } } - // 根据深度判断(深度较深的通常是内部器官) + // 鏍规嵁娣卞害鍒ゆ柇锛堟繁搴﹁緝娣辩殑閫氬父鏄唴閮ㄥ櫒瀹橈級 if (part.depth == BodyPartDepth.Inside && part.parent == null) return true; return false; } - // 新增:按优先级顺序尝试生成物品 + // 鏂板锛氭寜浼樺厛绾ч『搴忓皾璇曠敓鎴愮墿鍝? private bool TrySpawnItemWithPriority(Pawn pawn) { Thing thing = ThingMaker.MakeThing(this.Props.thingToSpawn, null); @@ -527,51 +530,60 @@ namespace ArachnaeSwarm } thing.stackCount = this.calculatedQuantity; - // 记录原始物品用于校验 ThingDef originalThingDef = thing.def; int originalStackCount = thing.stackCount; - // 按优先级顺序尝试生成 bool success = false; string spawnMethod = ""; + Thing spawnedThing = null; + int addedInventoryCount = 0; - // 优先级1: 尝试在pawn附近空地生成 if (!success) { - success = TrySpawnAtNearbyEmptyCell(pawn, thing, ref spawnMethod); + success = TrySpawnAtNearbyEmptyCell(pawn, thing, ref spawnMethod, out spawnedThing); } - // 优先级2: 尝试在pawn脚底生成 if (!success) { - success = TrySpawnAtPawnPosition(pawn, thing, ref spawnMethod); + success = TrySpawnAtPawnPosition(pawn, thing, ref spawnMethod, out spawnedThing); } - // 优先级3: 尝试放入pawn物品栏 if (!success) { - success = TrySpawnInInventory(pawn, thing, ref spawnMethod); + success = TrySpawnInInventory(pawn, thing, ref spawnMethod, out spawnedThing, out addedInventoryCount); } - // 生成后校验 if (success) { - bool verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, spawnMethod); - - // 如果校验失败且不是在物品栏中生成的,尝试在物品栏中重新生成 + bool verified = VerifySpawnSuccess( + pawn, + originalThingDef, + originalStackCount, + spawnMethod, + spawnedThing, + addedInventoryCount + ); + if (!verified && spawnMethod != "inventory") { Warn($"Spawn verification failed for {spawnMethod}, attempting inventory fallback", this.myDebug); - - // 重新创建物品 + Thing fallbackThing = ThingMaker.MakeThing(originalThingDef, null); fallbackThing.stackCount = originalStackCount; - - success = TrySpawnInInventory(pawn, fallbackThing, ref spawnMethod); - + + success = TrySpawnInInventory(pawn, fallbackThing, ref spawnMethod, out spawnedThing, out addedInventoryCount); + if (success) { - verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, "inventory_fallback"); + spawnMethod = "inventory_fallback"; + verified = VerifySpawnSuccess( + pawn, + originalThingDef, + originalStackCount, + spawnMethod, + spawnedThing, + addedInventoryCount + ); if (!verified) { Warn("Inventory fallback also failed verification", this.myDebug); @@ -584,9 +596,14 @@ namespace ArachnaeSwarm { if (PawnUtility.ShouldSendNotificationAbout(pawn)) { - Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN"), thing.Named("THING")), - spawnMethod == "inventory" || spawnMethod == "inventory_fallback" ? pawn : thing, - MessageTypeDefOf.PositiveEvent, true); + Thing messageThing = spawnedThing ?? thing; + bool spawnedInInventory = spawnMethod == "inventory" || spawnMethod == "inventory_fallback"; + Messages.Message( + this.Props.spawnVerb.Translate(pawn.Named("PAWN"), messageThing.Named("THING")), + spawnedInInventory ? pawn : messageThing, + MessageTypeDefOf.PositiveEvent, + true + ); } Warn($"Successfully spawned {originalStackCount}x {originalThingDef.defName} via {spawnMethod}", this.myDebug); return true; @@ -597,9 +614,9 @@ namespace ArachnaeSwarm return false; } - // 新增:尝试在附近空地生成 - private bool TrySpawnAtNearbyEmptyCell(Pawn pawn, Thing thing, ref string spawnMethod) + private bool TrySpawnAtNearbyEmptyCell(Pawn pawn, Thing thing, ref string spawnMethod, out Thing spawnedThing) { + spawnedThing = null; IntVec3 spawnCell; if (TryFindSpawnCell(out spawnCell)) { @@ -607,19 +624,21 @@ namespace ArachnaeSwarm { thing.SetForbidden(true, true); } - - if (GenPlace.TryPlaceThing(thing, spawnCell, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4))) + + Thing resultingThing; + if (GenPlace.TryPlaceThing(thing, spawnCell, pawn.Map, ThingPlaceMode.Direct, out resultingThing, null, null, default(Rot4))) { spawnMethod = "nearby_cell"; + spawnedThing = resultingThing; return true; } } return false; } - // 新增:尝试在pawn位置生成 - private bool TrySpawnAtPawnPosition(Pawn pawn, Thing thing, ref string spawnMethod) + private bool TrySpawnAtPawnPosition(Pawn pawn, Thing thing, ref string spawnMethod, out Thing spawnedThing) { + spawnedThing = null; IntVec3 pawnPosition = pawn.Position; if (pawnPosition.IsValid && pawnPosition.Walkable(pawn.Map)) { @@ -627,54 +646,61 @@ namespace ArachnaeSwarm { thing.SetForbidden(true, true); } - - if (GenPlace.TryPlaceThing(thing, pawnPosition, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4))) + + Thing resultingThing; + if (GenPlace.TryPlaceThing(thing, pawnPosition, pawn.Map, ThingPlaceMode.Direct, out resultingThing, null, null, default(Rot4))) { spawnMethod = "pawn_position"; + spawnedThing = resultingThing; return true; } } return false; } - // 新增:尝试在物品栏生成 - private bool TrySpawnInInventory(Pawn pawn, Thing thing, ref string spawnMethod) + private bool TrySpawnInInventory(Pawn pawn, Thing thing, ref string spawnMethod, out Thing spawnedThing, out int addedCount) { + spawnedThing = null; + addedCount = 0; if (pawn.inventory == null) { Warn($"Pawn {pawn.Label} does not have an inventory", this.myDebug); return false; } - + + int before = CountDefInInventory(pawn, thing.def); if (pawn.inventory.innerContainer.TryAdd(thing)) { + int after = CountDefInInventory(pawn, thing.def); + addedCount = Math.Max(0, after - before); spawnMethod = "inventory"; + spawnedThing = pawn.inventory.innerContainer.FirstOrDefault(t => t.def == thing.def); return true; } return false; } - // 新增:生成后校验 - private bool VerifySpawnSuccess(Pawn pawn, ThingDef thingDef, int expectedCount, string spawnMethod) + private bool VerifySpawnSuccess(Pawn pawn, ThingDef thingDef, int expectedCount, string spawnMethod, Thing spawnedThing, int addedInventoryCount) { bool verificationSuccess = false; - + switch (spawnMethod) { case "nearby_cell": case "pawn_position": - case "inventory_fallback": - // 检查地图上是否有生成的物品 - verificationSuccess = pawn.Map.listerThings.ThingsOfDef(thingDef) - .Any(t => t.stackCount >= expectedCount && t.Position.InHorDistOf(pawn.Position, 2f)); + verificationSuccess = + spawnedThing != null && + spawnedThing.def == thingDef && + spawnedThing.Map == pawn.Map && + spawnedThing.Position.InHorDistOf(pawn.Position, 2f); break; - + case "inventory": - // 检查物品栏中是否有生成的物品 - verificationSuccess = pawn.inventory.innerContainer.Any(t => t.def == thingDef && t.stackCount >= expectedCount); + case "inventory_fallback": + verificationSuccess = addedInventoryCount >= expectedCount; break; } - + if (!verificationSuccess) { Warn($"Spawn verification failed for {thingDef.defName} via {spawnMethod}", this.myDebug); @@ -683,10 +709,19 @@ namespace ArachnaeSwarm { Warn($"Spawn verification successful for {thingDef.defName} via {spawnMethod}", this.myDebug); } - + return verificationSuccess; } + private int CountDefInInventory(Pawn pawn, ThingDef thingDef) + { + if (pawn?.inventory?.innerContainer == null || thingDef == null) + { + return 0; + } + return pawn.inventory.innerContainer.Where(t => t.def == thingDef).Sum(t => t.stackCount); + } + private bool TryFindSpawnCell(out IntVec3 result) { result = IntVec3.Invalid; @@ -704,19 +739,19 @@ namespace ArachnaeSwarm } else { - // 修改这里:将半径从5减少到2,让生成位置更靠近pawn + // 淇敼杩欓噷锛氬皢鍗婂緞浠?鍑忓皯鍒?锛岃鐢熸垚浣嶇疆鏇撮潬杩憄awn int searchRadius = 2; - // 首先尝试在pawn的相邻单元格生成(半径为1) + // 棣栧厛灏濊瘯鍦╬awn鐨勭浉閭诲崟鍏冩牸鐢熸垚锛堝崐寰勪负1锛? result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, 1, null); - // 如果相邻单元格找不到合适位置,再尝试稍远一点(半径为2) + // 濡傛灉鐩搁偦鍗曞厓鏍兼壘涓嶅埌鍚堥€備綅缃紝鍐嶅皾璇曠◢杩滀竴鐐癸紙鍗婂緞涓?锛? if (!result.IsValid) { result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, searchRadius, null); } - // 如果还是找不到,尝试pawn当前位置(作为最后手段) + // 濡傛灉杩樻槸鎵句笉鍒帮紝灏濊瘯pawn褰撳墠浣嶇疆锛堜綔涓烘渶鍚庢墜娈碉級 if (!result.IsValid && this.pawn.Position.IsValid && this.pawn.Position.Walkable(map)) { result = this.pawn.Position; @@ -813,7 +848,7 @@ namespace ArachnaeSwarm } } - // === 整合的 Tools 方法 === + // === 鏁村悎鐨?Tools 鏂规硶 === private void DestroyParentHediff(Hediff parentHediff, bool debug = false) { @@ -851,12 +886,86 @@ namespace ArachnaeSwarm } return result; } - private bool OkPawn(Pawn pawn) { return pawn != null && pawn.Map != null; } + private bool IsHungry(Pawn pawn, bool debug = false) + { + if (pawn == null) + { + if (debug) + { + Warn("pawn is null - IsHungry", debug); + } + return false; + } + + bool starving = pawn.needs.food != null && pawn.needs.food.CurCategory == HungerCategory.Starving; + if (debug && starving) + { + Warn(pawn.Label + " is hungry", debug); + } + return starving; + } + + private bool IsInjured(Pawn pawn, bool debug = false) + { + if (pawn == null) + { + if (debug) + { + Warn("pawn is null - IsInjured", debug); + } + return false; + } + + float injurySeverity = 0f; + List hediffs = pawn.health.hediffSet.hediffs; + for (int i = 0; i < hediffs.Count; i++) + { + if (hediffs[i] is Hediff_Injury && !hediffs[i].IsPermanent()) + { + injurySeverity += hediffs[i].Severity; + } + } + + bool injured = injurySeverity > 0f; + if (debug && injured) + { + Warn(pawn.Label + " is injured", debug); + } + return injured; + } + + private bool PartOrAnyDescendantHasDirectlyAddedParts(Pawn pawn, BodyPartRecord part) + { + if (pawn?.health?.hediffSet == null || part == null) + { + return false; + } + + if (pawn.health.hediffSet.HasDirectlyAddedPartFor(part)) + { + return true; + } + + if (part.parts == null || part.parts.Count == 0) + { + return false; + } + + for (int i = 0; i < part.parts.Count; i++) + { + if (PartOrAnyDescendantHasDirectlyAddedParts(pawn, part.parts[i])) + { + return true; + } + } + + return false; + } private void Warn(string warning, bool debug = false) { if (debug) @@ -880,4 +989,5 @@ namespace ArachnaeSwarm private readonly int errorExponentialLimit = 20; private readonly int errorSpawnCount = 750; } -} \ No newline at end of file +} +