diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index b9c9af0..889af9c 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/BackstoryDefs/ARA_BackstoryDef.xml b/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml index 596747c..5cecb6f 100644 --- a/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml +++ b/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml @@ -91,7 +91,6 @@ 工艺种 [PAWN_nameDef]是一只阿拉克涅工艺种督虫。能够产出专门用来孵化阿拉克涅武器种的孵化茧,负责阿拉克涅虫巢的基础维护。\n\n[PAWN_nameDef]在战斗中并不是一个值得正视的对手,她没有可以接入武装器官的副肢,脆弱臃肿的特性也决定了她几乎无法躲开任何攻击。 Adulthood - Cooking
  • ArachnaeNode_spawnCategories_WeaponSmith
  • @@ -104,10 +103,6 @@ 原虫种 [PAWN_nameDef]是一只阿拉克涅原虫种督虫。[PAWN_nameDef]通过独特的神经链接管伸入受害者身体来接管受害者的身体。不同于普通阿拉克涅虫族,阿拉克涅原虫种拥有自我意识,不需要女皇种的监管。 Adulthood - Cooking - - -
  • ArachnaeNode_spawnCategories_Facehugger
  • diff --git a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml index 6dfe6f3..b2252d6 100644 --- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml +++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml @@ -3,15 +3,58 @@ ARA_Possession - - 这个生物的身体正被另一个实体所控制。 + + 这个生物的身体被阿拉克涅原虫所夺取了,这具身体原本的主人已经没有可能再回来了。 ArachnaeSwarm.Hediff_Possession + (0.6, 0.4, 0.8) false false 1.0 + +
  • + PawnRenderNode_AttachmentHead + PawnRenderNodeWorker_FlipWhenCrawling + ArachnaeSwarm/Things/ARA_HiveNode/Heads/Average_Normal + Skin + Head + true + true + Fresh, Rotting + + + 70 + + +
  • +
  • + PawnRenderNode_AttachmentHead + PawnRenderNodeWorker_FlipWhenCrawling + ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Addons_Base + Skin + Head + true + true + Fresh, Rotting + + + 70 + + +
  • +
  • - + 0 + +
  • Mood
  • +
  • Joy
  • +
  • Beauty
  • +
  • Comfort
  • +
  • Outdoors
  • +
  • Indoors
  • +
  • DrugDesire
  • +
  • RoomSize
  • +
    diff --git a/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs b/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs index 31cab75..f162724 100644 --- a/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs +++ b/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs @@ -12,34 +12,33 @@ namespace ArachnaeSwarm Pawn caster = this.parent.pawn; Pawn targetPawn = target.Pawn; - if (targetPawn == null) + if (targetPawn == null || caster == null) return; + + Log.Message($"[夺舍] 开始执行。施法者: {caster.LabelShort}, 目标: {targetPawn.LabelShort}"); + + // 步骤 1: 创建Hediff实例 + Hediff_Possession hediff = (Hediff_Possession)HediffMaker.MakeHediff(HediffDef.Named("ARA_Possession"), targetPawn); + + // 步骤 2: 使用SplitOff(1)将施法者的一个安全、独立的副本存入容器。 + // 这是从地图上移除Pawn并将其存入容器的标准、原子性操作。 + if (hediff.GetDirectlyHeldThings().TryAdd(caster.SplitOff(1), true)) { + Log.Message($"[夺舍] 成功将 {caster.LabelShort} 的副本存入Hediff。"); + } + else + { + Log.Error($"[夺舍] 无法将 {caster.LabelShort} 的副本存入Hediff。中止操作。"); return; } - - // Optional: Add checks here. E.g., cannot possess mechanical, already possessed, etc. - // if (targetPawn.RaceProps.IsMechanoid) - // { - // Messages.Message("Cannot possess a mechanoid.", MessageTypeDefOf.RejectInput); - // return; - // } - Log.Message("[夺舍] Apply方法开始执行。施法者: " + caster.LabelShort + ", 目标: " + targetPawn.LabelShort); + // 步骤 3: 使用原始施法者的数据覆盖目标Pawn。 + // 即使caster的stackCount变为0,其数据在当前Tick中依然可读。 + PawnDataUtility.TransferSoul(caster, targetPawn); - Log.Message("[夺舍] 步骤1: 创建Hediff实例..."); - Hediff_Possession hediff = (Hediff_Possession)HediffMaker.MakeHediff(HediffDef.Named("ARA_Possession"), targetPawn); - - Log.Message("[夺舍] 步骤2: 将施法者 " + caster.LabelShort + " 安全地转移到Hediff容器中..."); - // 使用标准的游戏框架方法,将施法者从其当前的持有者(地图)转移到Hediff的内部容器中。 - // 这会自动处理施法者从地图上消失的逻辑。 - caster.holdingOwner.TryTransferToContainer(caster, hediff.GetDirectlyHeldThings(), 1); - - Log.Message("[夺舍] 步骤3: 调用Hediff的PostPossessionApply方法来执行数据覆盖..."); - // 我们创建一个新的方法来处理夺舍后的逻辑,而不是依赖PostAdd - hediff.PostPossessionApply(caster, targetPawn); - - Log.Message("[夺舍] 步骤4: 将Hediff添加到目标Pawn身上..."); + // 步骤 4: 将准备好的Hediff添加到目标身上。 targetPawn.health.AddHediff(hediff); + + Log.Message($"[夺舍] {targetPawn.LabelShort} (原 {caster.LabelShort}) 夺舍完成。"); } } } \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs b/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs index a596151..0d8903b 100644 --- a/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs +++ b/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs @@ -7,7 +7,6 @@ namespace ArachnaeSwarm public class Hediff_Possession : HediffWithComps, IThingHolder { private ThingOwner innerContainer; - private Pawn originalCaster; public Hediff_Possession() { @@ -28,20 +27,8 @@ namespace ArachnaeSwarm return innerContainer; } - // PostAdd在游戏加载时也会被调用,因此不适合放置一次性的夺舍逻辑。 - // 我们创建一个新的公共方法,由CompAbilityEffect在正确的时机调用。 - public void PostPossessionApply(Pawn caster, Pawn target) - { - Log.Message("[夺舍] Hediff.PostPossessionApply 开始执行,施法者: " + caster.LabelShort + ", 目标: " + target.LabelShort); - - // 将施法者的引用保存下来,用于将来的重生逻辑 - this.originalCaster = caster; - - Log.Message("[夺舍] 步骤5: 调用 TransferSoul 将灵魂从 " + caster.LabelShort + " 转移到 " + target.LabelShort); - PawnDataUtility.TransferSoul(caster, target); - - Log.Message($"[夺舍] {target.LabelShort} 已被 {StoredCasterPawn.LabelShort} 夺舍成功!"); - } + // PostAdd现在只在游戏加载时起作用,我们不需要在这里做任何特殊操作。 + // 所有的夺舍逻辑都在CompAbilityEffect_Possess中处理了。 public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null) { @@ -61,24 +48,33 @@ namespace ArachnaeSwarm this.EjectContents(); } - public void SetCaster(Pawn caster) - { - this.originalCaster = caster; - } public void EjectContents() { - if (StoredCasterPawn != null) + if (StoredCasterPawn == null) return; + + // 采用更稳健的方式获取地图和位置,防止因宿主死亡导致Map为null + Map map = this.pawn.MapHeld ?? Find.AnyPlayerHomeMap; + if (map == null) { - this.innerContainer.TryDropAll(this.pawn.Position, this.pawn.Map, ThingPlaceMode.Near); + Log.Error("[夺舍] 无法找到一个有效的地图来重生抱脸虫。"); + return; } + + IntVec3 cell = this.pawn.PositionHeld; + if (!cell.IsValid) + { + cell = map.Center; + } + + Log.Message($"[夺舍] 准备在地图 {map.ToString()} 的位置 {cell.ToString()} 处重生 {StoredCasterPawn.LabelShort}。"); + this.innerContainer.TryDropAll(cell, map, ThingPlaceMode.Near); } public override void ExposeData() { base.ExposeData(); Scribe_Deep.Look(ref innerContainer, "innerContainer", this); - Scribe_References.Look(ref originalCaster, "originalCaster", false); } } } \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs b/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs index a202dc8..62cb26a 100644 --- a/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs +++ b/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs @@ -56,9 +56,12 @@ namespace ArachnaeSwarm { foreach (RecordDef recordDef in DefDatabase.AllDefs) { + // 根据您的指示,我们不再处理时间类型的记录,以避免警告 + if (recordDef.type == RecordType.Time) + { + continue; + } float sourceValue = soulSource.records.GetValue(recordDef); - // For Time records, we must set them directly to avoid warnings. - // The AddTo(delta) trick works for all types and is the standard way to "set" a value. bodyTarget.records.AddTo(recordDef, sourceValue - bodyTarget.records.GetValue(recordDef)); } } @@ -81,7 +84,11 @@ namespace ArachnaeSwarm bodyTarget.workSettings.EnableAndInitialize(); foreach (WorkTypeDef workDef in DefDatabase.AllDefs) { - bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef)); + // 在设置优先级之前,检查目标Pawn是否禁用了该工作类型 + if (!bodyTarget.WorkTypeIsDisabled(workDef)) + { + bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef)); + } } }