This commit is contained in:
2025-09-17 12:54:07 +08:00
parent 9e992fc08b
commit c77def63c2
123 changed files with 130 additions and 130 deletions

View File

@@ -0,0 +1,166 @@
using RimWorld;
using RimWorld.Planet;
using Verse;
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
namespace ArachnaeSwarm
{
public class CompAbilityEffect_Possess : CompAbilityEffect, ICompAbilityEffectOnJumpCompleted
{
public new CompProperties_AbilityPossess Props => (CompProperties_AbilityPossess)props;
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
{
Pawn targetPawn = target.Pawn;
if (targetPawn == null) return false;
if (!targetPawn.RaceProps.Humanlike)
{
if (throwMessages) Messages.Message("ARA_MustBeHumanlike".Translate(), targetPawn, MessageTypeDefOf.RejectInput, false);
return false;
}
if (targetPawn.health.hediffSet.HasHediff(HediffDef.Named("ARA_Possession")))
{
if (throwMessages) Messages.Message("ARA_AlreadyPossessed".Translate(targetPawn.LabelShort), targetPawn, MessageTypeDefOf.RejectInput, false);
return false;
}
if (Props.raceBlacklist.Contains(targetPawn.def))
{
if (throwMessages) Messages.Message("ARA_CannotPossessRace".Translate(targetPawn.def.label), targetPawn, MessageTypeDefOf.RejectInput, false);
return false;
}
return base.Valid(target, throwMessages);
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
DoPossession(this.parent.pawn, target.Pawn);
}
private void DoPossession(Pawn caster, Pawn targetPawn)
{
if (targetPawn == null || caster == null) return;
Log.Message($"[夺舍] 开始执行。施法者: {caster.LabelShort}, 目标: {targetPawn.LabelShort}");
// 1. 捕获原宿主的完整数据,用于死亡后恢复尸体
OriginalPawnData originalHostData = new OriginalPawnData();
originalHostData.CaptureData(targetPawn);
Log.Message($"[夺舍] 已捕获原始宿主 {targetPawn.LabelShort} 的完整数据。");
// 2. 备份原宿主的技能,用于后续合并
var originalTargetSkills = new Dictionary<SkillDef, (int level, Passion passion)>();
if (targetPawn.skills != null)
{
foreach (var skill in targetPawn.skills.skills)
{
originalTargetSkills[skill.def] = (skill.levelInt, skill.passion);
}
}
// 3. 准备抱脸虫和Hediff
Pawn originalCaster = PawnGenerator.GeneratePawn(caster.kindDef, caster.Faction);
PawnDataUtility.TransferSoul(caster, originalCaster); // 确保克隆体有完全一致的数据
Hediff_Possession hediff = (Hediff_Possession)HediffMaker.MakeHediff(HediffDef.Named("ARA_Possession"), targetPawn);
hediff.originalHostData = originalHostData; // 将宿主数据存入Hediff
// 4. 将抱脸虫存入Hediff
if (hediff.casterContainer.TryAdd(originalCaster, true))
{
Log.Message($"[夺舍] 成功将 {caster.LabelShort} 的原始副本存入Hediff。");
// 5. 灵魂转移,此时 targetPawn 的技能被 caster 的技能覆盖
PawnDataUtility.TransferSoul(caster, targetPawn);
// 夺舍成功后,原始的抱脸虫应该消失
if (!caster.Destroyed)
{
caster.Destroy(DestroyMode.Vanish);
}
// 6. 技能合并:在灵魂转移后,直接在最终的身体 (targetPawn) 上进行合并
if (targetPawn.skills != null)
{
Log.Message("[夺舍] 开始合并技能...");
foreach (var skillRecord in targetPawn.skills.skills)
{
if (originalTargetSkills.TryGetValue(skillRecord.def, out var originalSkill))
{
// 比较等级
if (originalSkill.level > skillRecord.levelInt)
{
skillRecord.levelInt = originalSkill.level;
}
// 比较热情
if (originalSkill.passion > skillRecord.passion)
{
skillRecord.passion = originalSkill.passion;
}
}
}
Log.Message("[夺舍] 技能合并完成。");
}
// 7. 将Hediff添加到最终身体上
targetPawn.health.AddHediff(hediff);
if (Props.hediffToApplyOnSuccess != null)
{
targetPawn.health.AddHediff(Props.hediffToApplyOnSuccess, null, null);
Log.Message($"[夺舍] 成功为 {targetPawn.LabelShort} 添加额外Hediff: {Props.hediffToApplyOnSuccess.defName}");
}
Log.Message($"[夺舍] {targetPawn.LabelShort} (原 {caster.LabelShort}) 夺舍完成。");
}
else
{
Log.Error($"[夺舍] 无法将 {caster.LabelShort} 的副本存入Hediff。中止操作。");
if(originalCaster != null && !originalCaster.Destroyed) originalCaster.Destroy();
}
}
public void OnJumpCompleted(IntVec3 JUMPINPOS_UNUSED, LocalTargetInfo landingTarget)
{
Pawn caster = this.parent.pawn;
if (caster == null || !(landingTarget.Thing is Pawn targetPawn)) return;
Verb bestMeleeVerb = caster.meleeVerbs.TryGetMeleeVerb(targetPawn);
if (bestMeleeVerb == null)
{
Log.Warning($"[Possess] Caster {caster.LabelShort} has no melee verb.");
return;
}
float damageAmount = bestMeleeVerb.verbProps.AdjustedMeleeDamageAmount(bestMeleeVerb, caster);
float armorPenetration = bestMeleeVerb.verbProps.AdjustedArmorPenetration(bestMeleeVerb, caster);
DamageDef damageDef = bestMeleeVerb.verbProps.meleeDamageDef;
var dinfo = new DamageInfo(damageDef, damageAmount, armorPenetration, -1, caster);
DamageWorker.DamageResult damageResult = targetPawn.TakeDamage(dinfo);
Log.Message($"[Possess] Dealt {damageResult.totalDamageDealt} damage to {targetPawn.LabelShort} using {damageDef.defName}.");
if (damageResult.totalDamageDealt > 0)
{
float baseChance = Props.successChance.RandomInRange;
float bonusFromDamage = damageResult.totalDamageDealt * Props.successChanceBonusPerDamage;
float finalChance = Mathf.Clamp01(baseChance + bonusFromDamage);
Log.Message($"[Possess] Base chance: {baseChance}, Bonus: {bonusFromDamage}, Final chance: {finalChance}");
if (Rand.Chance(finalChance))
{
Log.Message($"[Possess] Success! Applying possession effect.");
DoPossession(caster, targetPawn);
}
else
{
Log.Message($"[Possess] Failed possession check.");
}
}
}
}
}