This commit is contained in:
2025-09-04 23:02:54 +08:00
parent 00d43cfba3
commit c049cf4c5e
6 changed files with 95 additions and 55 deletions

Binary file not shown.

View File

@@ -91,7 +91,6 @@
<titleShort>工艺种</titleShort>
<description>[PAWN_nameDef]是一只阿拉克涅工艺种督虫。能够产出专门用来孵化阿拉克涅武器种的孵化茧,负责阿拉克涅虫巢的基础维护。\n\n[PAWN_nameDef]在战斗中并不是一个值得正视的对手,她没有可以接入武装器官的副肢,脆弱臃肿的特性也决定了她几乎无法躲开任何攻击。</description>
<slot>Adulthood</slot>
<requiredWorkTags>Cooking</requiredWorkTags>
<spawnCategories>
<li>ArachnaeNode_spawnCategories_WeaponSmith</li>
@@ -104,10 +103,6 @@
<titleShort>原虫种</titleShort>
<description>[PAWN_nameDef]是一只阿拉克涅原虫种督虫。[PAWN_nameDef]通过独特的神经链接管伸入受害者身体来接管受害者的身体。不同于普通阿拉克涅虫族,阿拉克涅原虫种拥有自我意识,不需要女皇种的监管。</description>
<slot>Adulthood</slot>
<requiredWorkTags>Cooking</requiredWorkTags>
<forcedHediffs Insert="false">
</forcedHediffs>
<spawnCategories>
<li>ArachnaeNode_spawnCategories_Facehugger</li>

View File

@@ -3,15 +3,58 @@
<HediffDef>
<defName>ARA_Possession</defName>
<label>阿拉克涅原虫寄生</label>
<description>这个生物的身体正被另一个实体所控制</description>
<label>阿拉克涅原虫</label>
<description>这个生物的身体被阿拉克涅原虫所夺取了,这具身体原本的主人已经没有可能再回来了</description>
<hediffClass>ArachnaeSwarm.Hediff_Possession</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad>
<scenarioCanAdd>false</scenarioCanAdd>
<maxSeverity>1.0</maxSeverity>
<renderNodeProperties>
<li>
<nodeClass>PawnRenderNode_AttachmentHead</nodeClass>
<workerClass>PawnRenderNodeWorker_FlipWhenCrawling</workerClass>
<texPath>ArachnaeSwarm/Things/ARA_HiveNode/Heads/Average_Normal</texPath>
<colorType>Skin</colorType>
<parentTagDef>Head</parentTagDef>
<useSkinShader>true</useSkinShader>
<useRottenColor>true</useRottenColor>
<rotDrawMode>Fresh, Rotting</rotDrawMode>
<drawData>
<defaultData>
<layer>70</layer>
</defaultData>
</drawData>
</li>
<li>
<nodeClass>PawnRenderNode_AttachmentHead</nodeClass>
<workerClass>PawnRenderNodeWorker_FlipWhenCrawling</workerClass>
<texPath>ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Addons_Base</texPath>
<colorType>Skin</colorType>
<parentTagDef>Head</parentTagDef>
<useSkinShader>true</useSkinShader>
<useRottenColor>true</useRottenColor>
<rotDrawMode>Fresh, Rotting</rotDrawMode>
<drawData>
<defaultData>
<layer>70</layer>
</defaultData>
</drawData>
</li>
</renderNodeProperties>
<stages>
<li>
<label>被寄生</label>
<minSeverity>0</minSeverity>
<disablesNeeds>
<li>Mood</li>
<li>Joy</li>
<li>Beauty</li>
<li>Comfort</li>
<li>Outdoors</li>
<li>Indoors</li>
<li>DrugDesire</li>
<li>RoomSize</li>
</disablesNeeds>
</li>
</stages>
</HediffDef>

View File

@@ -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}) 夺舍完成。");
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -56,9 +56,12 @@ namespace ArachnaeSwarm
{
foreach (RecordDef recordDef in DefDatabase<RecordDef>.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<WorkTypeDef>.AllDefs)
{
bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef));
// 在设置优先级之前检查目标Pawn是否禁用了该工作类型
if (!bodyTarget.WorkTypeIsDisabled(workDef))
{
bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef));
}
}
}