This commit is contained in:
2025-09-05 17:10:45 +08:00
parent a84e7bbb94
commit a3d15c30e8
5 changed files with 110 additions and 10 deletions

Binary file not shown.

View File

@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!-- ==================== Ability Def ==================== -->
<AbilityDef>
<!-- ==================== Original commented out ==================== -->
<!--<AbilityDef>
<defName>ARA_Ability_Possess</defName>
<label>阿拉克涅寄生</label>
<description>将你的意识注入另一个生物的身体,完全占据它。</description>
<iconPath>UI/Commands/EggSpew</iconPath>
<cooldownTicksRange>600</cooldownTicksRange>
<casterMustBeCapableOfViolence>false</casterMustBeCapableOfViolence>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<warmupTime>1.5</warmupTime>
@@ -26,6 +27,39 @@
<hediffDef>ARA_HiveMindDrone</hediffDef>
</li>
</comps>
</AbilityDef>-->
<!-- ==================== Jump Possession ==================== -->
<AbilityDef>
<defName>ARA_Ability_Possess</defName>
<label>阿拉克涅突袭寄生</label>
<description>向目标跳跃,将你的意识注入另一个生物的身体,完全占据它。</description>
<iconPath>UI/Abilities/Longjump</iconPath>
<cooldownTicksRange>800</cooldownTicksRange>
<casterMustBeCapableOfViolence>false</casterMustBeCapableOfViolence>
<verbProperties>
<!-- 使用我们新的Verb -->
<verbClass>ArachnaeSwarm.Verb_JumpAndCastOnLanding</verbClass>
<warmupTime>1.0</warmupTime>
<range>19.9</range>
<requireLineOfSight>true</requireLineOfSight>
<soundCast>Longjump_Jump</soundCast>
<soundLanding>Longjump_Land</soundLanding>
<targetParams>
<canTargetPawns>true</canTargetPawns>
<canTargetBuildings>false</canTargetBuildings>
<canTargetSelf>false</canTargetSelf>
<canTargetLocations>false</canTargetLocations>
</targetParams>
</verbProperties>
<comps>
<!-- comps部分现在只包含夺舍效果因为跳跃由Verb处理 -->
<li Class="ArachnaeSwarm.CompProperties_AbilityPossess"/>
<li Class="CompProperties_AbilityGiveHediff">
<compClass>CompAbilityEffect_GiveHediff</compClass>
<hediffDef>ARA_HiveMindDrone</hediffDef>
</li>
</comps>
</AbilityDef>
</Defs>

View File

@@ -1,26 +1,29 @@
using RimWorld;
using RimWorld.Planet;
using Verse;
namespace ArachnaeSwarm
{
public class CompAbilityEffect_Possess : CompAbilityEffect
public class CompAbilityEffect_Possess : CompAbilityEffect, ICompAbilityEffectOnJumpCompleted
{
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
Log.Message($"[CompAbilityEffect_Possess] Apply called. Target: {target.Thing?.LabelShort ?? "null"}");
base.Apply(target, dest);
Pawn caster = this.parent.pawn;
Pawn targetPawn = target.Pawn;
if (targetPawn == null || caster == null) return;
if (targetPawn == null || caster == null)
{
Log.Warning($"[CompAbilityEffect_Possess] Apply aborted. TargetPawn or Caster is 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。");
@@ -31,14 +34,17 @@ namespace ArachnaeSwarm
return;
}
// 步骤 3: 使用原始施法者的数据覆盖目标Pawn。
// 即使caster的stackCount变为0其数据在当前Tick中依然可读。
PawnDataUtility.TransferSoul(caster, targetPawn);
// 步骤 4: 将准备好的Hediff添加到目标身上。
targetPawn.health.AddHediff(hediff);
Log.Message($"[夺舍] {targetPawn.LabelShort} (原 {caster.LabelShort}) 夺舍完成。");
}
public void OnJumpCompleted(IntVec3 JUMPINPOS_UNUSED, LocalTargetInfo landingTarget)
{
Log.Message($"[CompAbilityEffect_Possess] OnJumpCompleted called. Landing target: {landingTarget.Thing?.LabelShort ?? "null"}");
this.Apply(landingTarget, null);
}
}
}

View File

@@ -0,0 +1,59 @@
using RimWorld;
using RimWorld.Utility;
using UnityEngine;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class Verb_JumpAndCastOnLanding : Verb_CastAbility
{
private LocalTargetInfo capturedTarget;
public override bool TryStartCastOn(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, bool canHitNonTargetPawns = true, bool preventFriendlyFire = false, bool nonInterruptingSelfCast = false)
{
this.capturedTarget = castTarg;
return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
}
public virtual ThingDef JumpFlyerDef => ThingDefOf.PawnFlyer;
public override float EffectiveRange => this.verbProps.range;
public override void DrawHighlight(LocalTargetInfo target)
{
if (target.IsValid && JumpUtility.ValidJumpTarget(CasterPawn, caster.Map, target.Cell))
{
GenDraw.DrawTargetHighlightWithLayer(target.CenterVector3, AltitudeLayer.MetaOverlays);
}
GenDraw.DrawRadiusRing(caster.Position, EffectiveRange, Color.white, (IntVec3 c) => GenSight.LineOfSight(caster.Position, c, caster.Map) && JumpUtility.ValidJumpTarget(caster, caster.Map, c));
}
public override bool ValidateTarget(LocalTargetInfo target, bool showMessages = true)
{
if (!base.ValidateTarget(target, showMessages)) return false;
if (!JumpUtility.ValidJumpTarget(CasterPawn, caster.Map, target.Cell)) return false;
return true;
}
protected override bool TryCastShot()
{
LocalTargetInfo physicalTarget = this.currentTarget;
LocalTargetInfo logicalTargetForUs = this.capturedTarget;
if (logicalTargetForUs == null || !logicalTargetForUs.HasThing)
{
return false;
}
return JumpUtility.DoJump(
CasterPawn,
physicalTarget,
this.ReloadableCompSource,
verbProps,
this.ability,
logicalTargetForUs,
this.JumpFlyerDef
);
}
}
}

View File

@@ -119,6 +119,7 @@
<Compile Include="ARA_HuggingFace\PawnDataUtility.cs" />
<Compile Include="ARA_HuggingFace\CompAbilityEffect_Possess.cs" />
<Compile Include="ARA_HuggingFace\CompProperties_AbilityPossess.cs" />
<Compile Include="ARA_HuggingFace\Verb_JumpAndCastOnLanding.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ARA_TrainingWork\JobClean\ARA_TrainableDefOf_Cleaning.cs" />