diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 5157529b..3f48b6b 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/AbilityDefs/ARA_Possession_Defs.xml b/1.6/1.6/Defs/AbilityDefs/ARA_Possession_Defs.xml
new file mode 100644
index 0000000..993203b
--- /dev/null
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Possession_Defs.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ ARA_Ability_Possess
+
+ 将你的意识注入另一个生物的身体,完全占据它。
+ UI/Abilities/Possess
+ 600
+
+ Verb_CastAbility
+ 1.5
+ 5.9
+
+ true
+ false
+ false
+ false
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml b/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml
index ad5604f..596747c 100644
--- a/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml
+++ b/1.6/1.6/Defs/BackstoryDefs/ARA_BackstoryDef.xml
@@ -97,4 +97,20 @@
ArachnaeNode_spawnCategories_WeaponSmith
+
+
+ Arachnae_Node_BS_Adult_Facehugger
+ 阿拉克涅原虫种
+ 原虫种
+ [PAWN_nameDef]是一只阿拉克涅原虫种督虫。[PAWN_nameDef]通过独特的神经链接管伸入受害者身体来接管受害者的身体。不同于普通阿拉克涅虫族,阿拉克涅原虫种拥有自我意识,不需要女皇种的监管。
+ Adulthood
+ Cooking
+
+
+
+
+
+ ArachnaeNode_spawnCategories_Facehugger
+
+
\ No newline at end of file
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 095afb3..6dfe6f3 100644
--- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml
+++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml
@@ -5,7 +5,7 @@
ARA_Possession
这个生物的身体正被另一个实体所控制。
- ArachnaeSwarm.Possession.Hediff_Possession
+ ArachnaeSwarm.Hediff_Possession
false
false
1.0
diff --git a/1.6/1.6/Defs/Misc/ARA_Possession_Defs.xml b/1.6/1.6/Defs/Misc/ARA_Possession_Defs.xml
deleted file mode 100644
index 40efc0a..0000000
--- a/1.6/1.6/Defs/Misc/ARA_Possession_Defs.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
-
-
-
- ARA_Ability_Possess
-
- 将你的意识注入另一个生物的身体,完全占据它。
- UI/Abilities/Possess
- 600
-
- Verb_CastAbility
- 1.5
- 5.9
-
- true
- false
- false
- false
-
-
-
-
-
-
-
-
- ARA_Facehugger
- Humanlike_PostMentalState
- 100
-
-
-
-
-
- Possess
-
-
-
-
-
-
-
-
-
- ARA_Facehugger
-
- ARA_FacehuggerRace
- 25
-
-
-
- Things/Pawn/Animal/ARA_Facehugger
- 0.8
-
-
- Things/Pawn/Animal/Dessicated/CritterDessicated
- 0.8
-
-
-
- ARA_Facehugger
-
- ARA_Ability_Possess
-
-
-
-
-
-
- ARA_FacehuggerRace
-
- 一种小型的、脆弱的寄生生物,其唯一的生存目的就是寻找并占据一个更强大的宿主。它通过将自己的意识注入目标来完成这一过程。
-
- 4.0
- 50
- -10
- 50
-
-
-
-
-
- Scratch
-
- 2
- 1.5
-
-
-
- Animal
- ARA_FacehuggerBody
- 0.2
- 0.3
- 0.1
-
-
- AnimalAdult
- 0
-
-
-
-
-
-
- ARA_FacehuggerBody
-
-
- Body
- 20
- 20
-
-
- Head
- 0.3
-
-
- Skull
- 0.2
- Inside
-
-
- Brain
- 0.1
- Inside
-
-
-
-
- Eye
- left eye
- 0.07
-
-
- Eye
- right eye
- 0.07
-
-
-
-
- Leg
- front left leg
- 0.1
-
-
- Leg
- front right leg
- 0.1
-
-
- Leg
- rear left leg
- 0.1
-
-
- Leg
- rear right leg
- 0.1
-
-
-
-
-
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_Race_HuggingFaceSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_Race_HuggingFaceSwarm.xml
new file mode 100644
index 0000000..220a030
--- /dev/null
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_Race_HuggingFaceSwarm.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+ ArachnaeNode_Race_Facehugger
+
+ ArachnaeNode_Race_Facehugger
+ PlayerColony
+ 0
+
+
+
+ ArachnaeNode_spawnCategoriesA
+ ArachnaeNode_spawnCategories_Facehugger
+
+
+
+
+ ARA_Facehugger
+
+
+
+ 0
+
+
+
+
+ ArachnaeNode_Race_Facehugger
+
+ 阿拉克涅原虫,通过独特的神经链接管伸入受害者身体来接管受害者的身体。不同于普通阿拉克涅虫族,阿拉克涅原虫种拥有自我意识,不需要女皇种的监管。
+
+
+
+
+
+
+
+ ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Myrmecocystus_Addons_Stomach
+ false
+
+
+
+
+
+
+
+
+
+
+ ARA_InsectJelly
+
+ false
+
+
+
+
+ ARA_InsectJelly
+ 3
+ 4
+
+
+
+
+
+
+ 2
+
+
+
+ 5
+ 1
+
+ 100
+ 70
+ 10
+
+ 0.5
+
+
+
+
+
+
+
+
+ 0.18
+ 0.27
+ 0.2
+
+
+
+ OmnivoreHuman,CarnivoreAnimal,OvivoreAnimal,VegetarianRoughAnimal
+
+ ArachnaeMyrmecocystus_Body
+
+ 2.5
+
+ 3
+
+ 1.5
+
+
+ ArachnaeNode_Myrmecocystus_Adult
+ 0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs b/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
index f0e2b8b..f9f7f4e 100644
--- a/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
+++ b/Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
@@ -1,7 +1,7 @@
using RimWorld;
using Verse;
-namespace ArachnaeSwarm.Possession
+namespace ArachnaeSwarm
{
public class CompAbilityEffect_Possess : CompAbilityEffect
{
diff --git a/Source/ArachnaeSwarm/Possession/CompProperties_AbilityPossess.cs b/Source/ArachnaeSwarm/Possession/CompProperties_AbilityPossess.cs
index 7cea6a7..b4402d0 100644
--- a/Source/ArachnaeSwarm/Possession/CompProperties_AbilityPossess.cs
+++ b/Source/ArachnaeSwarm/Possession/CompProperties_AbilityPossess.cs
@@ -1,6 +1,6 @@
using RimWorld;
-namespace ArachnaeSwarm.Possession
+namespace ArachnaeSwarm
{
public class CompProperties_AbilityPossess : CompProperties_AbilityEffect
{
diff --git a/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs b/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
index 7054207..34c6e0f 100644
--- a/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
+++ b/Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
using RimWorld;
using Verse;
-namespace ArachnaeSwarm.Possession
+namespace ArachnaeSwarm
{
public class Hediff_Possession : HediffWithComps, IThingHolder
{
diff --git a/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs b/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
index 6b78f42..39f2318 100644
--- a/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
+++ b/Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
@@ -1,8 +1,9 @@
using System.Collections.Generic;
+using System.Linq;
using RimWorld;
using Verse;
-namespace ArachnaeSwarm.Possession
+namespace ArachnaeSwarm
{
public static class PawnDataUtility
{
@@ -16,43 +17,59 @@ namespace ArachnaeSwarm.Possession
Log.Message($"Beginning soul transfer from {soulSource.LabelShort} to {bodyTarget.LabelShort}.");
- // Name
+ // --- 1. Core Identity ---
bodyTarget.Name = soulSource.Name;
-
- // Story (Backstory and Traits)
bodyTarget.story.Childhood = soulSource.story.Childhood;
bodyTarget.story.Adulthood = soulSource.story.Adulthood;
- bodyTarget.story.traits.allTraits.Clear();
- foreach (Trait trait in soulSource.story.traits.allTraits)
+
+ if (bodyTarget.story.traits != null) bodyTarget.story.traits.allTraits.Clear();
+ if (soulSource.story.traits != null)
{
- bodyTarget.story.traits.GainTrait(trait);
+ foreach (Trait trait in soulSource.story.traits.allTraits)
+ {
+ bodyTarget.story.traits.GainTrait(trait);
+ }
}
- // Skills
- bodyTarget.skills.skills.Clear();
- foreach (SkillRecord skill in soulSource.skills.skills)
- {
- SkillRecord newSkill = new SkillRecord(bodyTarget, skill.def)
- {
- levelInt = skill.levelInt,
- xpSinceLastLevel = skill.xpSinceLastLevel,
- passion = skill.passion
- };
- bodyTarget.skills.skills.Add(newSkill);
- }
-
- // Faction
if (bodyTarget.Faction != soulSource.Faction)
{
bodyTarget.SetFaction(soulSource.Faction, soulSource);
}
- // Thoughts and Memories
- if (bodyTarget.needs.mood?.thoughts?.memories != null)
+ // --- 2. Growth & Experience ---
+ if (bodyTarget.skills != null) bodyTarget.skills.skills.Clear();
+ if (soulSource.skills != null)
+ {
+ foreach (SkillRecord skill in soulSource.skills.skills)
+ {
+ SkillRecord newSkill = new SkillRecord(bodyTarget, skill.def)
+ {
+ levelInt = skill.levelInt,
+ xpSinceLastLevel = skill.xpSinceLastLevel,
+ passion = skill.passion
+ };
+ bodyTarget.skills.skills.Add(newSkill);
+ }
+ }
+
+ if (bodyTarget.records != null && soulSource.records != null)
+ {
+ foreach (RecordDef recordDef in DefDatabase.AllDefs)
+ {
+ // Correct way: Get value from source and add the difference to target.
+ // This effectively sets the value.
+ float sourceValue = soulSource.records.GetValue(recordDef);
+ float targetValue = bodyTarget.records.GetValue(recordDef);
+ bodyTarget.records.AddTo(recordDef, sourceValue - targetValue);
+ }
+ }
+
+ // --- 3. Mind & Settings ---
+ if (bodyTarget.needs?.mood?.thoughts?.memories != null)
{
bodyTarget.needs.mood.thoughts.memories.Memories.Clear();
}
- if (soulSource.needs.mood?.thoughts?.memories != null)
+ if (soulSource.needs?.mood?.thoughts?.memories != null)
{
foreach (Thought_Memory memory in soulSource.needs.mood.thoughts.memories.Memories)
{
@@ -60,7 +77,6 @@ namespace ArachnaeSwarm.Possession
}
}
- // Work Settings
if (soulSource.workSettings != null && bodyTarget.workSettings != null)
{
bodyTarget.workSettings.EnableAndInitialize();
@@ -70,34 +86,67 @@ namespace ArachnaeSwarm.Possession
}
}
- // Timetable
if (soulSource.timetable != null && bodyTarget.timetable != null)
{
bodyTarget.timetable.times = new List(soulSource.timetable.times);
}
- // Social Relations
+ if (soulSource.playerSettings != null && bodyTarget.playerSettings != null)
+ {
+ bodyTarget.playerSettings.hostilityResponse = soulSource.playerSettings.hostilityResponse;
+ bodyTarget.playerSettings.medCare = soulSource.playerSettings.medCare;
+ bodyTarget.playerSettings.selfTend = soulSource.playerSettings.selfTend;
+ }
+
+ if (soulSource.outfits != null && bodyTarget.outfits != null) bodyTarget.outfits.CurrentApparelPolicy = soulSource.outfits.CurrentApparelPolicy;
+ if (soulSource.drugs != null && bodyTarget.drugs != null) bodyTarget.drugs.CurrentPolicy = soulSource.drugs.CurrentPolicy;
+ if (soulSource.foodRestriction != null && bodyTarget.foodRestriction != null) bodyTarget.foodRestriction.CurrentFoodPolicy = soulSource.foodRestriction.CurrentFoodPolicy;
+ // Ownership is claimed on the Building, not the pawn. We can't directly transfer this.
+ // if (soulSource.ownership != null && bodyTarget.ownership != null)
+ // {
+ // // This requires finding the bed and calling bed.SetOwner(pawn)
+ // }
+
+
+ // --- 4. DLC & Social ---
+ if (ModsConfig.IdeologyActive && soulSource.ideo != null && bodyTarget.ideo != null)
+ {
+ bodyTarget.ideo.SetIdeo(soulSource.ideo.Ideo);
+ // Can't set certainty directly, but setting the ideo resets it.
+ }
+
+ if (ModsConfig.RoyaltyActive && soulSource.royalty != null && bodyTarget.royalty != null)
+ {
+ // Clear existing royalty status from the target body
+ bodyTarget.royalty.AllTitlesForReading.Clear();
+
+ // Transfer titles
+ foreach(var title in soulSource.royalty.AllTitlesForReading)
+ {
+ bodyTarget.royalty.SetTitle(title.faction, title.def, true, false, false);
+ }
+ // Transfer permits
+ if(soulSource.royalty.AllFactionPermits != null)
+ {
+ foreach (var permit in soulSource.royalty.AllFactionPermits)
+ {
+ bodyTarget.royalty.AddPermit(permit.Permit, permit.Faction);
+ }
+ }
+ // Abilities are handled by the titles and should update automatically.
+ bodyTarget.royalty.UpdateAvailableAbilities();
+ }
+
if (soulSource.relations != null && bodyTarget.relations != null)
{
bodyTarget.relations.ClearAllRelations();
- foreach (DirectPawnRelation relation in soulSource.relations.DirectRelations)
+ foreach (DirectPawnRelation relation in soulSource.relations.DirectRelations.Where(r => !r.def.familyByBloodRelation).ToList())
{
bodyTarget.relations.AddDirectRelation(relation.def, relation.otherPawn);
}
}
- // Guest status
- if (soulSource.guest != null && bodyTarget.guest != null)
- {
- bodyTarget.guest.SetGuestStatus(soulSource.guest.HostFaction, soulSource.guest.GuestStatus);
- if (soulSource.guest.IsPrisoner)
- {
- bodyTarget.guest.SetExclusiveInteraction(soulSource.guest.ExclusiveInteractionMode);
- }
- bodyTarget.guest.joinStatus = soulSource.guest.joinStatus;
- }
-
- // Refresh the UI and game state to reflect the changes.
+ // --- 5. Finalization ---
bodyTarget.Drawer.renderer.SetAllGraphicsDirty();
Log.Message("Soul transfer complete.");
diff --git a/Source/Documents/Possession_Implementation_Guide.md b/Source/Documents/Possession_Implementation_Guide.md
index d10dcdc..e69425b 100644
--- a/Source/Documents/Possession_Implementation_Guide.md
+++ b/Source/Documents/Possession_Implementation_Guide.md
@@ -37,6 +37,55 @@ graph TD
### 3.1 `CompAbilityEffect_Possess.cs` - 技能效果的起点
这是技能被使用时第一个被调用的C#文件。它的职责是创建`Hediff_Possession`并将其附加到目标身上,从而启动整个夺舍流程。
+## 3. 最终数据迁移规范 (Final Data Transfer Specification)
+
+通过对真实存档文件 (`Human.xml`) 的深度分析,我们最终确定了“灵魂”与“肉体”的数据边界。`PawnDataUtility.TransferSoul` 方法将严格遵循以下规范进行数据迁移:
+
+### 3.1 必须复制的“灵魂”数据
+
+这些数据定义了Pawn的身份、经历、思想和核心能力,将**完全从抱脸虫(源)复制到宿主(目标)**。
+
+- **核心身份 (`Name`, `Story`, `Faction`)**:
+ - `Name`: 姓名与昵称。
+ - `Story`: 童年和成年背景 (`Childhood`, `Adulthood`)。
+ - `Traits`: 所有特性。
+ - `Faction`: 所属阵营。
+- **成长与经历 (`Skills`, `Records`)**:
+ - `Skills`: 所有技能的等级、经验和热情。
+ - `Records`: 全部生平记录 (如击杀数、建造数等)。
+- **思想与设定 (`Needs`, `WorkSettings`, etc.)**:
+ - `Needs`: 主要是指`thoughts.memories` (思想和记忆)。
+ - `WorkSettings`: 工作优先级。
+ - `Timetable`: 时间表。
+ - `PlayerSettings`: 玩家设定 (如医疗策略)。
+ - `Ownership`: 对床、王座等的所有权。
+ - `Outfits` & `Drugs`: 穿着和药物策略。
+ - `FoodRestriction`: 食物策略。
+- **DLC核心数据 (`Ideo`, `Royalty`)**:
+ - `Ideo`: 完整的信仰体系。
+ - `Royalty`: 完整的贵族系统,包括头衔、恩惠、许可、灵能和相关技能 (`abilities`)。
+- **社交 (`Relations`)**:
+ - 将采用**简化处理**:清空目标的旧关系,然后只复制源的**非亲属**直接关系 (如朋友、对手、爱人)。这可以避免破坏家族树。
+
+### 3.2 必须保留的“肉体”数据
+
+这些数据属于物理身体的范畴,在夺舍过程中将**完全保留宿主原有的数据**,不进行任何复制。
+
+- **健康与生理 (`Health`, `Age`)**:
+ - `Health`: 所有伤口、疤痕、疾病和植入物。
+ - `Age`: 生物年龄和时间年龄。
+- **外观与基因 (`Style`, `Genes`, `BodyType`)**:
+ - `Style`: 发型、胡须、纹身。
+ - `Genes`: 所有内生和异种基因。
+ - `BodyType`, `HeadType`, `HairColor`: 身体类型、头型和发色。
+- **装备与物品 (`Apparel`, `Equipment`, `Inventory`)**:
+ - `Apparel`: 身上穿着的衣物。
+ - `Equipment`: 手中持有的装备。
+ - `Inventory`: 物品栏中的物品。
+- **物理状态 (`Position`, `Stances`, `Pather`)**:
+ - Pawn在世界中的位置、姿态和寻路信息。
+
+---
```csharp
// 路径: Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs