暂存
This commit is contained in:
@@ -112,6 +112,12 @@
|
||||
<Compile Include="DataContracts.cs" />
|
||||
<Compile Include="CompTemperatureRuinableDamage.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Possession\Hediff_Possession.cs" />
|
||||
<Compile Include="Possession\PawnDataUtility.cs" />
|
||||
<Compile Include="Possession\CompAbilityEffect_Possess.cs" />
|
||||
<Compile Include="Possession\CompProperties_AbilityPossess.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||
|
||||
33
Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
Normal file
33
Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
public class CompAbilityEffect_Possess : CompAbilityEffect
|
||||
{
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
|
||||
Pawn caster = this.parent.pawn;
|
||||
Pawn targetPawn = target.Pawn;
|
||||
|
||||
if (targetPawn == null)
|
||||
{
|
||||
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;
|
||||
// }
|
||||
|
||||
Hediff_Possession hediff = (Hediff_Possession)HediffMaker.MakeHediff(HediffDef.Named("ARA_Possession"), targetPawn);
|
||||
hediff.SetCaster(caster);
|
||||
|
||||
targetPawn.health.AddHediff(hediff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using RimWorld;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
public class CompProperties_AbilityPossess : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_AbilityPossess()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_Possess);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
Normal file
90
Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
public class Hediff_Possession : HediffWithComps, IThingHolder
|
||||
{
|
||||
private ThingOwner innerContainer;
|
||||
private Pawn originalCaster;
|
||||
|
||||
public Hediff_Possession()
|
||||
{
|
||||
this.innerContainer = new ThingOwner<Thing>(this, false, LookMode.Deep);
|
||||
}
|
||||
|
||||
public Pawn StoredCasterPawn => innerContainer.Count > 0 ? innerContainer[0] as Pawn : null;
|
||||
|
||||
public IThingHolder ParentHolder => this.pawn;
|
||||
|
||||
public void GetChildHolders(List<IThingHolder> outChildren)
|
||||
{
|
||||
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, this.GetDirectlyHeldThings());
|
||||
}
|
||||
|
||||
public ThingOwner GetDirectlyHeldThings()
|
||||
{
|
||||
return innerContainer;
|
||||
}
|
||||
|
||||
public override void PostAdd(DamageInfo? dinfo)
|
||||
{
|
||||
base.PostAdd(dinfo);
|
||||
|
||||
if (this.originalCaster == null)
|
||||
{
|
||||
Log.Error("Hediff_Possession was added without an original caster.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.innerContainer.TryAdd(this.originalCaster);
|
||||
PawnDataUtility.TransferSoul(this.originalCaster, this.pawn);
|
||||
|
||||
if (!this.originalCaster.Destroyed)
|
||||
{
|
||||
this.originalCaster.Destroy(DestroyMode.Vanish);
|
||||
}
|
||||
|
||||
Log.Message($"{this.pawn.LabelShort} has been possessed by {StoredCasterPawn.LabelShort}!");
|
||||
}
|
||||
|
||||
public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
|
||||
{
|
||||
base.Notify_PawnDied(dinfo, culprit);
|
||||
|
||||
Pawn deadBody = this.pawn;
|
||||
Pawn storedCaster = this.StoredCasterPawn;
|
||||
|
||||
if (storedCaster == null)
|
||||
{
|
||||
Log.Error("Possessed pawn died, but no caster soul was found inside.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Message($"Host {deadBody.LabelShort} died. Transferring experience back to {storedCaster.LabelShort} and ejecting.");
|
||||
PawnDataUtility.TransferSoul(deadBody, storedCaster);
|
||||
this.EjectContents();
|
||||
}
|
||||
|
||||
public void SetCaster(Pawn caster)
|
||||
{
|
||||
this.originalCaster = caster;
|
||||
}
|
||||
|
||||
public void EjectContents()
|
||||
{
|
||||
if (StoredCasterPawn != null)
|
||||
{
|
||||
this.innerContainer.TryDropAll(this.pawn.Position, this.pawn.Map, ThingPlaceMode.Near);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
|
||||
Scribe_References.Look(ref originalCaster, "originalCaster");
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
Normal file
106
Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
public static class PawnDataUtility
|
||||
{
|
||||
public static void TransferSoul(Pawn soulSource, Pawn bodyTarget)
|
||||
{
|
||||
if (soulSource == null || bodyTarget == null)
|
||||
{
|
||||
Log.Error("Cannot transfer soul: source or target is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Message($"Beginning soul transfer from {soulSource.LabelShort} to {bodyTarget.LabelShort}.");
|
||||
|
||||
// Name
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
bodyTarget.needs.mood.thoughts.memories.Memories.Clear();
|
||||
}
|
||||
if (soulSource.needs.mood?.thoughts?.memories != null)
|
||||
{
|
||||
foreach (Thought_Memory memory in soulSource.needs.mood.thoughts.memories.Memories)
|
||||
{
|
||||
bodyTarget.needs.mood.thoughts.memories.TryGainMemory(memory);
|
||||
}
|
||||
}
|
||||
|
||||
// Work Settings
|
||||
if (soulSource.workSettings != null && bodyTarget.workSettings != null)
|
||||
{
|
||||
bodyTarget.workSettings.EnableAndInitialize();
|
||||
foreach (WorkTypeDef workDef in DefDatabase<WorkTypeDef>.AllDefs)
|
||||
{
|
||||
bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef));
|
||||
}
|
||||
}
|
||||
|
||||
// Timetable
|
||||
if (soulSource.timetable != null && bodyTarget.timetable != null)
|
||||
{
|
||||
bodyTarget.timetable.times = new List<TimeAssignmentDef>(soulSource.timetable.times);
|
||||
}
|
||||
|
||||
// Social Relations
|
||||
if (soulSource.relations != null && bodyTarget.relations != null)
|
||||
{
|
||||
bodyTarget.relations.ClearAllRelations();
|
||||
foreach (DirectPawnRelation relation in soulSource.relations.DirectRelations)
|
||||
{
|
||||
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.
|
||||
bodyTarget.Drawer.renderer.SetAllGraphicsDirty();
|
||||
|
||||
Log.Message("Soul transfer complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user