This commit is contained in:
2025-09-04 21:01:54 +08:00
parent 760ddee0cc
commit 0982682cc9
11 changed files with 300 additions and 210 deletions

View File

@@ -1,7 +1,7 @@
using RimWorld;
using Verse;
namespace ArachnaeSwarm.Possession
namespace ArachnaeSwarm
{
public class CompAbilityEffect_Possess : CompAbilityEffect
{

View File

@@ -1,6 +1,6 @@
using RimWorld;
namespace ArachnaeSwarm.Possession
namespace ArachnaeSwarm
{
public class CompProperties_AbilityPossess : CompProperties_AbilityEffect
{

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using RimWorld;
using Verse;
namespace ArachnaeSwarm.Possession
namespace ArachnaeSwarm
{
public class Hediff_Possession : HediffWithComps, IThingHolder
{

View File

@@ -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<RecordDef>.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<TimeAssignmentDef>(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.");