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