diff --git a/1.6/1.6/Assemblies/AlienRace.dll b/1.6/1.6/Assemblies/AlienRace.dll new file mode 100644 index 0000000..dbf4c0d Binary files /dev/null and b/1.6/1.6/Assemblies/AlienRace.dll differ diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 4bafd8d..a1d8e77 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Defs/Thing_building/ARA_Building.xml b/1.6/1.6/Defs/Thing_building/ARA_Building.xml index 74274ed..754988a 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_Building.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_Building.xml @@ -119,6 +119,9 @@ 0.6 2 + + 1 + 10 ConstructMetal 6 diff --git a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml index 15034fb..272b99c 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml @@ -740,7 +740,7 @@ true true - true + false
  • 200 diff --git a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml index 6d5e181..6165de2 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml @@ -134,7 +134,7 @@ 虫蜜 - true + false true true true @@ -300,7 +300,7 @@ 虫蜜 - true + false true true
  • @@ -441,7 +441,7 @@ 虫蜜 - true + false true true @@ -604,7 +604,7 @@ 虫蜜 - true + false true true diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index 6cc79f5..7d4dade 100644 Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json index 3a9bb06..8c60bea 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -3,32 +3,16 @@ "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\thing\\\u793A\u8303.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing\\\u793A\u8303.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\thing\\highaltitudeflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing\\highaltitudeflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\thing\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_arachnaegravengine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_arachnaegravengine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\hediffs\\ara_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\compabilityeffect_randomhediff.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_randomhediff.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\powerarmor\\comppowerarmorstation.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:powerarmor\\comppowerarmorstation.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" } ], "DocumentGroupContainers": [ @@ -47,87 +31,39 @@ { "$type": "Document", "DocumentIndex": 0, - "Title": "\u793A\u8303.md", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\\u793A\u8303.md", - "RelativeDocumentMoniker": "Thing\\\u793A\u8303.md", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\\u793A\u8303.md", - "RelativeToolTip": "Thing\\\u793A\u8303.md", - "ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAkAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|", - "WhenOpened": "2025-10-27T03:36:17.112Z", + "Title": "Building_NutrientVat.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs", + "RelativeDocumentMoniker": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs", + "RelativeToolTip": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs", + "ViewState": "AgIAAMwAAAAAAAAAAAAswMoAAAAuAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2025-10-27T07:14:35.288Z", "EditorCaption": "" }, - { - "$type": "Document", - "DocumentIndex": 1, - "Title": "HighAltitudeFlyOver.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\HighAltitudeFlyOver.cs", - "RelativeDocumentMoniker": "Thing\\HighAltitudeFlyOver.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\HighAltitudeFlyOver.cs", - "RelativeToolTip": "Thing\\HighAltitudeFlyOver.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAACMAAAARAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-27T03:32:08.102Z" - }, { "$type": "Document", "DocumentIndex": 2, - "Title": "ThingclassFlyOver.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\ThingclassFlyOver.cs", - "RelativeDocumentMoniker": "Thing\\ThingclassFlyOver.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing\\ThingclassFlyOver.cs*", - "RelativeToolTip": "Thing\\ThingclassFlyOver.cs*", - "ViewState": "AgIAAAcAAAAAAAAAAAAgwCEAAAAEAAAAAAAAAA==", + "Title": "CompPowerArmorStation.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PowerArmor\\CompPowerArmorStation.cs", + "RelativeDocumentMoniker": "PowerArmor\\CompPowerArmorStation.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PowerArmor\\CompPowerArmorStation.cs", + "RelativeToolTip": "PowerArmor\\CompPowerArmorStation.cs", + "ViewState": "AgIAABoAAAAAAAAAAAAAwBoAAABhAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-27T03:03:30.662Z" + "WhenOpened": "2025-10-27T06:39:11.711Z" }, { "$type": "Document", - "DocumentIndex": 4, + "DocumentIndex": 1, "Title": "Building_RefuelingVat.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs", "RelativeDocumentMoniker": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs", "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs", "RelativeToolTip": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs", - "ViewState": "AgIAAEQAAAAAAAAAAAAAAEABAAAQAAAAAAAAAA==", + "ViewState": "AgIAAMwAAAAAAAAAAAAAwJIAAAAXAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-10-24T06:16:14.743Z" - }, - { - "$type": "Document", - "DocumentIndex": 3, - "Title": "Building_ArachnaeGravEngine.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ArachnaeGravEngine.cs", - "RelativeDocumentMoniker": "Buildings\\Building_ArachnaeGravEngine.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ArachnaeGravEngine.cs", - "RelativeToolTip": "Buildings\\Building_ArachnaeGravEngine.cs", - "ViewState": "AgIAAHwAAAAAAAAAAAAgwJcAAAAJAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-24T02:30:45.288Z" - }, - { - "$type": "Document", - "DocumentIndex": 5, - "Title": "CompHediffTerrainSpawn.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs", - "RelativeDocumentMoniker": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs", - "RelativeToolTip": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs", - "ViewState": "AgIAAB0AAAAAAAAAAAAswE0AAABHAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-23T08:00:28.236Z" - }, - { - "$type": "Document", - "DocumentIndex": 6, - "Title": "CompAbilityEffect_RandomHediff.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_RandomHediff.cs", - "RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_RandomHediff.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_RandomHediff.cs", - "RelativeToolTip": "Abilities\\CompAbilityEffect_RandomHediff.cs", - "ViewState": "AgIAALoAAAAAAAAAAAAqwNcAAAAZAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-22T06:34:08.063Z" } ] } diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index ff222a7..20c20b3 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -38,6 +38,9 @@ ..\..\..\..\..\..\workshop\content\294100\2009463077\1.5\Assemblies\0Harmony.dll False + + ..\..\..\..\..\..\workshop\content\294100\839005762\1.6\Assemblies\AlienRace.dll + ..\..\..\..\..\..\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll False diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs index 61bd1e4..12c9e5c 100644 --- a/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs +++ b/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs @@ -17,6 +17,9 @@ namespace ArachnaeSwarm private CompAutoEjector cachedAutoEjectorComp; private Graphic cachedTopGraphic; + // 新增字段:跟踪被建筑杀死的pawn + private HashSet pawnsKilledByVat = new HashSet(); + // IThingHolderWithDrawnPawn implementation public float HeldPawnDrawPos_Y => DrawPos.y + 0.03658537f; public float HeldPawnBodyAngle => base.Rotation.AsAngle; @@ -134,12 +137,21 @@ namespace ArachnaeSwarm 1.5f, // 每次1.5点伤害 2f, // 护甲穿透 -1f, // 随机角度 - instigator: null, + instigator: this, // 将建筑设为伤害来源 hitPart: targetPart ); + // 标记这个pawn将被建筑杀死 + pawnsKilledByVat.Add(pawn); + // 应用伤害 pawn.TakeDamage(acidDamage); + + // 立即检查pawn是否死亡 + if (pawn.Dead) + { + HandlePawnDeath(pawn); + } } catch (Exception ex) { @@ -147,6 +159,48 @@ namespace ArachnaeSwarm } } + // 新增方法:处理pawn死亡 + private void HandlePawnDeath(Pawn pawn) + { + try + { + // 检查是否是被建筑杀死的 + if (pawnsKilledByVat.Contains(pawn)) + { + Log.Message($"Pawn {pawn.Label} killed by RefuelingVat, destroying corpse."); + + // 从容器中移除pawn + if (innerContainer.Contains(pawn)) + { + innerContainer.Remove(pawn); + } + + // 销毁pawn的尸体 + if (!pawn.Destroyed) + { + pawn.Destroy(); + } + + // 从跟踪列表中移除 + pawnsKilledByVat.Remove(pawn); + pawnTickCounters.Remove(pawn); + + // 立即调用完成逻辑 + if (selectedPawn == pawn) + { + selectedPawn = null; + startTick = -1; + } + + return; // 直接返回,不执行后续弹出逻辑 + } + } + catch (Exception ex) + { + Log.Error($"Error handling pawn death for {pawn}: {ex}"); + } + } + private BodyPartRecord GetRandomVulnerablePart(Pawn pawn) { // 优先选择外部身体部位 @@ -176,7 +230,15 @@ namespace ArachnaeSwarm // 检查俘虏是否死亡 - 增加更严格的检查 if (selectedPawn.Dead || selectedPawn.Destroyed) { - Finish(); + // 检查是否是被建筑杀死的 + if (pawnsKilledByVat.Contains(selectedPawn)) + { + HandlePawnDeath(selectedPawn); + } + else + { + Finish(); // 其他原因的死亡正常弹出 + } return; } @@ -246,6 +308,9 @@ namespace ArachnaeSwarm { startTick = Find.TickManager.TicksGame; pawnTickCounters[pawn] = 0; // 初始化伤害计数器 + + // 确保pawn不在死亡跟踪列表中 + pawnsKilledByVat.Remove(pawn); } if (deselected) { @@ -259,20 +324,27 @@ namespace ArachnaeSwarm { try { + // 检查pawn是否还活着,如果已经死亡且是被建筑杀死的,则跳过弹出 + if (selectedPawn.Dead && pawnsKilledByVat.Contains(selectedPawn)) + { + HandlePawnDeath(selectedPawn); + return; + } + Notify_PawnRemoved(); bool ejected = false; string ejectionMethod = "None"; // 方法1:标准弹出 - 在交互单元格附近 - if (innerContainer.Contains(selectedPawn)) + if (innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { ejected = innerContainer.TryDrop(selectedPawn, InteractionCell, base.Map, ThingPlaceMode.Near, 1, out var _); if (ejected) ejectionMethod = "Standard"; } // 方法2:尝试随机相邻单元格 - if (!ejected && innerContainer.Contains(selectedPawn)) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { var adjacentCells = GenAdj.CellsAdjacent8Way(this).Where(c => c.Walkable(base.Map) && c.InBounds(base.Map)).ToList(); if (adjacentCells.Count > 0) @@ -283,10 +355,10 @@ namespace ArachnaeSwarm } } - // 方法3:强制移除 - if (!ejected && innerContainer.Contains(selectedPawn)) + // 方法3:强制移除(仅对活着的pawn) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { - Log.Warning($"Forcing removal of dead pawn {selectedPawn} from RefuelingVat"); + Log.Warning($"Forcing removal of pawn {selectedPawn} from RefuelingVat"); innerContainer.Remove(selectedPawn); GenPlace.TryPlaceThing(selectedPawn, this.Position, base.Map, ThingPlaceMode.Near); ejected = true; @@ -297,7 +369,7 @@ namespace ArachnaeSwarm { Log.Message($"Successfully ejected {selectedPawn} using method: {ejectionMethod}"); } - else + else if (!selectedPawn.Dead) // 只有活着的pawn弹出失败才报错 { Log.Error($"Failed to eject {selectedPawn} from RefuelingVat"); } @@ -317,10 +389,12 @@ namespace ArachnaeSwarm { if (selectedPawn != null) { + // 从跟踪列表中移除 + pawnsKilledByVat.Remove(selectedPawn); pawnTickCounters.Remove(selectedPawn); - // 确保pawn不在容器中 - if (innerContainer.Contains(selectedPawn)) + // 确保pawn不在容器中(除非是被建筑杀死的) + if (innerContainer.Contains(selectedPawn) && !(selectedPawn.Dead && pawnsKilledByVat.Contains(selectedPawn))) { Log.Warning($"Pawn {selectedPawn} still in container during OnStop, forcing removal."); innerContainer.Remove(selectedPawn); @@ -597,6 +671,22 @@ namespace ArachnaeSwarm { base.ExposeData(); Scribe_Collections.Look(ref pawnTickCounters, "pawnTickCounters", LookMode.Reference, LookMode.Value); + Scribe_Collections.Look(ref pawnsKilledByVat, "pawnsKilledByVat", LookMode.Reference); + + // 确保集合不为null + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + pawnsKilledByVat ??= new HashSet(); + pawnTickCounters ??= new Dictionary(); + + // 清理可能已销毁的pawn引用 + pawnsKilledByVat.RemoveWhere(pawn => pawn == null || pawn.Destroyed); + var deadPawns = pawnTickCounters.Keys.Where(pawn => pawn == null || pawn.Destroyed).ToList(); + foreach (var deadPawn in deadPawns) + { + pawnTickCounters.Remove(deadPawn); + } + } } } } diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientVat/Building_NutrientVat.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientVat/Building_NutrientVat.cs index b1ba301..0b47e52 100644 --- a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientVat/Building_NutrientVat.cs +++ b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientVat/Building_NutrientVat.cs @@ -15,6 +15,9 @@ namespace ArachnaeSwarm private CompRefuelableNutrition cachedRefuelableComp; private Graphic cachedTopGraphic; + // 新增字段:跟踪被建筑杀死的pawn + private HashSet pawnsKilledByVat = new HashSet(); + // IThingHolderWithDrawnPawn implementation public float HeldPawnDrawPos_Y => DrawPos.y + 0.03658537f; public float HeldPawnBodyAngle => base.Rotation.AsAngle; @@ -124,12 +127,21 @@ namespace ArachnaeSwarm 3f, // 每次3点伤害 2f, // 护甲穿透 -1f, // 随机角度 - instigator: null, + instigator: this, // 将建筑设为伤害来源 hitPart: targetPart ); + // 标记这个pawn将被建筑杀死 + pawnsKilledByVat.Add(pawn); + // 应用伤害 pawn.TakeDamage(acidDamage); + + // 立即检查pawn是否死亡 + if (pawn.Dead) + { + HandlePawnDeath(pawn); + } } catch (Exception ex) { @@ -137,6 +149,48 @@ namespace ArachnaeSwarm } } + // 新增方法:处理pawn死亡(与RefuelingVat相同) + private void HandlePawnDeath(Pawn pawn) + { + try + { + // 检查是否是被建筑杀死的 + if (pawnsKilledByVat.Contains(pawn)) + { + Log.Message($"Pawn {pawn.Label} killed by NutrientVat, destroying corpse."); + + // 从容器中移除pawn + if (innerContainer.Contains(pawn)) + { + innerContainer.Remove(pawn); + } + + // 销毁pawn的尸体 + if (!pawn.Destroyed) + { + pawn.Destroy(); + } + + // 从跟踪列表中移除 + pawnsKilledByVat.Remove(pawn); + pawnTickCounters.Remove(pawn); + + // 立即调用完成逻辑 + if (selectedPawn == pawn) + { + selectedPawn = null; + startTick = -1; + } + + return; // 直接返回,不执行后续弹出逻辑 + } + } + catch (Exception ex) + { + Log.Error($"Error handling pawn death for {pawn}: {ex}"); + } + } + private BodyPartRecord GetRandomVulnerablePart(Pawn pawn) { // 优先选择外部身体部位 @@ -166,7 +220,15 @@ namespace ArachnaeSwarm // 检查俘虏是否死亡 - 增加更严格的检查 if (selectedPawn.Dead || selectedPawn.Destroyed) { - Finish(); + // 检查是否是被建筑杀死的 + if (pawnsKilledByVat.Contains(selectedPawn)) + { + HandlePawnDeath(selectedPawn); + } + else + { + Finish(); // 其他原因的死亡正常弹出 + } return; } @@ -270,6 +332,9 @@ namespace ArachnaeSwarm { startTick = Find.TickManager.TicksGame; pawnTickCounters[pawn] = 0; // 初始化伤害计数器 + + // 确保pawn不在死亡跟踪列表中 + pawnsKilledByVat.Remove(pawn); } if (deselected) { @@ -283,20 +348,27 @@ namespace ArachnaeSwarm { try { + // 检查pawn是否还活着,如果已经死亡且是被建筑杀死的,则跳过弹出 + if (selectedPawn.Dead && pawnsKilledByVat.Contains(selectedPawn)) + { + HandlePawnDeath(selectedPawn); + return; + } + Notify_PawnRemoved(); bool ejected = false; string ejectionMethod = "None"; // 方法1:标准弹出 - 在交互单元格附近 - if (innerContainer.Contains(selectedPawn)) + if (innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { ejected = innerContainer.TryDrop(selectedPawn, InteractionCell, base.Map, ThingPlaceMode.Near, 1, out var _); if (ejected) ejectionMethod = "Standard"; } // 方法2:尝试随机相邻单元格 - if (!ejected && innerContainer.Contains(selectedPawn)) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { var adjacentCells = GenAdj.CellsAdjacent8Way(this).Where(c => c.Walkable(base.Map) && c.InBounds(base.Map)).ToList(); if (adjacentCells.Count > 0) @@ -307,8 +379,8 @@ namespace ArachnaeSwarm } } - // 方法3:强制移除 - if (!ejected && innerContainer.Contains(selectedPawn)) + // 方法3:强制移除(仅对活着的pawn) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { Log.Warning($"Forcing removal of pawn {selectedPawn} from NutrientVat"); innerContainer.Remove(selectedPawn); @@ -321,7 +393,7 @@ namespace ArachnaeSwarm { Log.Message($"Successfully ejected {selectedPawn} using method: {ejectionMethod}"); } - else + else if (!selectedPawn.Dead) // 只有活着的pawn弹出失败才报错 { Log.Error($"Failed to eject {selectedPawn} from NutrientVat"); } @@ -343,20 +415,27 @@ namespace ArachnaeSwarm { try { + // 检查pawn是否还活着,如果已经死亡且是被建筑杀死的,则跳过弹出 + if (selectedPawn.Dead && pawnsKilledByVat.Contains(selectedPawn)) + { + HandlePawnDeath(selectedPawn); + return; + } + Notify_PawnRemoved(); bool ejected = false; string ejectionMethod = "None"; // 方法1:标准弹出 - 在交互单元格附近 - if (innerContainer.Contains(selectedPawn)) + if (innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { ejected = innerContainer.TryDrop(selectedPawn, InteractionCell, base.Map, ThingPlaceMode.Near, 1, out var _); if (ejected) ejectionMethod = "Standard"; } // 方法2:尝试随机相邻单元格 - if (!ejected && innerContainer.Contains(selectedPawn)) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { var adjacentCells = GenAdj.CellsAdjacent8Way(this).Where(c => c.Walkable(base.Map) && c.InBounds(base.Map)).ToList(); if (adjacentCells.Count > 0) @@ -367,8 +446,8 @@ namespace ArachnaeSwarm } } - // 方法3:强制移除 - if (!ejected && innerContainer.Contains(selectedPawn)) + // 方法3:强制移除(仅对活着的pawn) + if (!ejected && innerContainer.Contains(selectedPawn) && !selectedPawn.Dead) { Log.Warning($"Forcing removal of failed pawn {selectedPawn} from NutrientVat"); innerContainer.Remove(selectedPawn); @@ -384,7 +463,7 @@ namespace ArachnaeSwarm Hediff firstHediffOfDef = selectedPawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.BioStarvation); selectedPawn.Kill(null, firstHediffOfDef); } - else + else if (!selectedPawn.Dead) // 只有活着的pawn弹出失败才报错 { Log.Error($"Failed to eject failed pawn {selectedPawn} from NutrientVat"); // 即使弹出失败也要杀死俘虏 @@ -407,10 +486,12 @@ namespace ArachnaeSwarm { if (selectedPawn != null) { + // 从跟踪列表中移除 + pawnsKilledByVat.Remove(selectedPawn); pawnTickCounters.Remove(selectedPawn); - // 确保pawn不在容器中 - if (innerContainer.Contains(selectedPawn)) + // 确保pawn不在容器中(除非是被建筑杀死的) + if (innerContainer.Contains(selectedPawn) && !(selectedPawn.Dead && pawnsKilledByVat.Contains(selectedPawn))) { Log.Warning($"Pawn {selectedPawn} still in container during OnStop, forcing removal."); innerContainer.Remove(selectedPawn); @@ -671,6 +752,22 @@ namespace ArachnaeSwarm { base.ExposeData(); Scribe_Collections.Look(ref pawnTickCounters, "pawnTickCounters", LookMode.Reference, LookMode.Value); + Scribe_Collections.Look(ref pawnsKilledByVat, "pawnsKilledByVat", LookMode.Reference); + + // 确保集合不为null + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + pawnsKilledByVat ??= new HashSet(); + pawnTickCounters ??= new Dictionary(); + + // 清理可能已销毁的pawn引用 + pawnsKilledByVat.RemoveWhere(pawn => pawn == null || pawn.Destroyed); + var deadPawns = pawnTickCounters.Keys.Where(pawn => pawn == null || pawn.Destroyed).ToList(); + foreach (var deadPawn in deadPawns) + { + pawnTickCounters.Remove(deadPawn); + } + } } } } diff --git a/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs index 196ce62..0041b8a 100644 --- a/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs +++ b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs @@ -1,14 +1,20 @@ using RimWorld; using Verse; using System.Collections.Generic; -using Verse.AI; // For PathEndMode and Danger -using UnityEngine; // For Texture2D +using Verse.AI; +using UnityEngine; +using AlienRace; +using System; // 添加 System 命名空间用于 Action 类型 +using System.Text; // 添加 System.Text 命名空间用于 StringBuilder +using System.Linq; // 添加 System.Linq 命名空间用于 Any() 方法 namespace ArachnaeSwarm { public class CompProperties_PowerArmorStation : CompProperties { public ThingDef apparelDef; + public bool enableRaceRestrictionCheck = true; + public string customRestrictionMessage; public CompProperties_PowerArmorStation() { @@ -26,11 +32,64 @@ namespace ArachnaeSwarm var fuelComp = parent.GetComp(); if (fuelComp != null) { - // Set consumption rate to 0 when in building form fuelComp.currentConsumptionRate = 0f; } } + // 使用 Alien Race 框架提供的静态方法检查装备限制 + private AcceptanceReport CheckRaceRestriction(Pawn pawn, ThingDef apparelDef) + { + if (pawn == null || apparelDef == null) + return true; + + if (!Props.enableRaceRestrictionCheck) + return true; + + // 使用 Alien Race 框架的 CanWear 方法 + bool canWear = RaceRestrictionSettings.CanWear(apparelDef, pawn.def); + + if (!canWear) + { + if (!Props.customRestrictionMessage.NullOrEmpty()) + { + return Props.customRestrictionMessage.Translate(pawn.def.label, apparelDef.label); + } + + return "ARA_PowerArmorForbiddenByRace".Translate(pawn.def.label, apparelDef.label); + } + + return true; + } + + public AcceptanceReport CanPawnEnter(Pawn pawn) + { + // 基础可达性检查 + if (!pawn.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly)) + { + return "CannotReach".Translate(); + } + + if (Props.apparelDef == null) + { + return "ARA_NoApparelDefined".Translate(); + } + + // 使用 Alien Race 框架的方法检查种族限制 + AcceptanceReport raceCheck = CheckRaceRestriction(pawn, Props.apparelDef); + if (!raceCheck.Accepted) + { + return raceCheck; + } + + // 检查是否已经穿戴了同类型装备 + if (pawn.apparel?.WornApparel?.Any(a => a.def == Props.apparelDef) == true) + { + return "ARA_AlreadyWearingSameApparel".Translate(Props.apparelDef.label); + } + + return true; + } + public override IEnumerable CompFloatMenuOptions(Pawn selPawn) { foreach (FloatMenuOption option in base.CompFloatMenuOptions(selPawn)) @@ -38,26 +97,58 @@ namespace ArachnaeSwarm yield return option; } - // Check if there's an apparelDef defined if (Props.apparelDef == null) { - yield break; // No apparel to wear + yield break; } - // Check if the pawn can interact with the building - if (!selPawn.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly)) + AcceptanceReport canEnter = CanPawnEnter(selPawn); + + string label = "ARA_EnterPowerArmor".Translate(parent.Label); + if (!canEnter.Accepted) { - yield return new FloatMenuOption("CannotEnterPowerArmor".Translate() + ": " + "CannotReach".Translate(), null); + label += ": " + canEnter.Reason; } - else + + Action enterAction = null; + if (canEnter.Accepted) { - void enterAction() + enterAction = () => { Job job = JobMaker.MakeJob(DefDatabase.GetNamed("ARA_EnterPowerArmor"), parent); selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); - } - yield return new FloatMenuOption("ARA_EnterPowerArmor".Translate(parent.Label), enterAction); + }; } + + yield return new FloatMenuOption(label, enterAction) + { + Disabled = !canEnter.Accepted + }; + } + + public override string CompInspectStringExtra() + { + StringBuilder sb = new StringBuilder(); + string baseString = base.CompInspectStringExtra(); + + if (!string.IsNullOrEmpty(baseString)) + sb.Append(baseString); + + if (Props.apparelDef != null) + { + if (sb.Length > 0) + sb.AppendLine(); + + sb.Append("ARA_PowerArmorStationApparel".Translate(Props.apparelDef.label)); + + if (Props.enableRaceRestrictionCheck) + { + sb.AppendLine(); + sb.Append("ARA_RaceRestrictionEnabled".Translate()); + } + } + + return sb.ToString(); } } -} \ No newline at end of file +}