Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/ThingComp/WULA_GiveHediffsInRange/CompGiveHediffsInRange.cs
2025-11-25 17:31:19 +08:00

405 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RimWorld;
using Verse;
using System.Collections.Generic;
using UnityEngine;
namespace WulaFallenEmpire
{
public class CompGiveHediffsInRange : ThingComp
{
private CompProperties_GiveHediffsInRange Props => (CompProperties_GiveHediffsInRange)props;
// 跟踪受影响的pawn和他们的Hediff
private Dictionary<Pawn, Hediff> affectedPawns = new Dictionary<Pawn, Hediff>();
// 效果实例缓存
private Dictionary<Pawn, Effecter> effecters = new Dictionary<Pawn, Effecter>();
public override void CompTick()
{
base.CompTick();
if (parent == null || !parent.Spawned || parent.Map == null)
return;
// 使用间隔检查优化性能
if (Find.TickManager.TicksGame % Props.checkIntervalTicks != 0)
return;
UpdateAffectedPawns();
}
private void UpdateAffectedPawns()
{
if (Props.hediff == null) return;
// 获取范围内的所有pawn
List<Pawn> pawnsInRange = GetPawnsInRange();
// 处理新进入范围的pawn
foreach (var pawn in pawnsInRange)
{
if (!affectedPawns.ContainsKey(pawn) && ShouldAffectPawn(pawn))
{
AddHediffToPawn(pawn);
}
}
// 处理离开范围的pawn
var pawnsToRemove = new List<Pawn>();
foreach (var kvp in affectedPawns)
{
if (!pawnsInRange.Contains(kvp.Key) || !ShouldAffectPawn(kvp.Key))
{
pawnsToRemove.Add(kvp.Key);
}
else
{
// 更新持续时间的Hediff
UpdateHediffDuration(kvp.Key, kvp.Value);
}
}
foreach (var pawn in pawnsToRemove)
{
RemoveHediffFromPawn(pawn);
}
}
private List<Pawn> GetPawnsInRange()
{
var pawns = new List<Pawn>();
if (parent?.Map == null) return pawns;
var map = parent.Map;
var center = parent.Position;
// 使用网格搜索优化性能
foreach (var thing in map.listerThings.ThingsInGroup(ThingRequestGroup.Pawn))
{
if (thing is Pawn pawn &&
pawn.Position.DistanceTo(center) <= Props.range &&
pawn.Spawned)
{
pawns.Add(pawn);
}
}
return pawns;
}
/// <summary>
/// 检查pawn是否应该受到效果影响
/// </summary>
private bool ShouldAffectPawn(Pawn pawn)
{
if (pawn == null || pawn.Dead || pawn.Destroyed)
return false;
// 派系检查
if (Props.onlyPawnsInSameFaction && pawn.Faction != parent.Faction)
return false;
// 种族类型检查
if (Props.requireHumanlike && !pawn.RaceProps.Humanlike)
return false;
if (Props.requireAnimal && !pawn.RaceProps.Animal)
return false;
if (Props.requireMechanoid && !pawn.RaceProps.IsMechanoid)
return false;
// 特定种族检查
if (Props.allowedRaces != null && Props.allowedRaces.Count > 0)
{
if (!Props.allowedRaces.Contains(pawn.def))
return false;
}
// 排除种族检查
if (Props.excludedRaces != null && Props.excludedRaces.Count > 0)
{
if (Props.excludedRaces.Contains(pawn.def))
return false;
}
// 修复:安全的派系关系检查
if (parent.Faction != null && pawn.Faction != null)
{
// 避免检查同一派系与自身的关系
if (parent.Faction == pawn.Faction)
{
// 同一派系,视为盟友
if (!Props.affectAllies)
return false;
}
else
{
try
{
FactionRelationKind relation = parent.Faction.RelationKindWith(pawn.Faction);
if (!Props.affectAllies && relation == FactionRelationKind.Ally)
return false;
if (!Props.affectEnemies && relation == FactionRelationKind.Hostile)
return false;
if (!Props.affectNeutrals && relation == FactionRelationKind.Neutral)
return false;
}
catch (System.Exception ex)
{
Log.Warning($"检查派系关系时出错: {ex.Message}");
// 出错时保守处理,不施加效果
return false;
}
}
}
else
{
// 如果建筑或pawn没有派系根据设置处理
if (parent.Faction == null && pawn.Faction == null)
{
// 两者都没有派系,视为中立
if (!Props.affectNeutrals)
return false;
}
else if (pawn.Faction == null)
{
// pawn没有派系野生动物等视为中立
if (!Props.affectNeutrals)
return false;
}
}
// 囚犯和奴隶检查
if (!Props.affectPrisoners && pawn.IsPrisoner)
return false;
if (!Props.affectSlaves && pawn.IsSlave)
return false;
return true;
}
private void AddHediffToPawn(Pawn pawn)
{
try
{
// 检查pawn是否已经有这个Hediff
Hediff existingHediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediff);
if (existingHediff != null)
{
// 如果已经有相同的Hediff更新它而不是创建新的
affectedPawns[pawn] = existingHediff;
UpdateHediffDuration(pawn, existingHediff);
return;
}
// 添加Hediff
Hediff newHediff = HediffMaker.MakeHediff(Props.hediff, pawn);
newHediff.Severity = Props.initialSeverity;
// 正确设置持续时间
if (Props.hediffDurationTicks > 0)
{
var disappearComp = newHediff.TryGetComp<HediffComp_Disappears>();
if (disappearComp != null)
{
// 使用 SetDuration 方法正确设置持续时间
disappearComp.SetDuration(Props.hediffDurationTicks);
}
}
pawn.health.AddHediff(newHediff);
affectedPawns[pawn] = newHediff;
// 创建视觉效果
CreateEffectForPawn(pawn);
// 记录日志(可选,调试时使用)
// Log.Message($"给予 {pawn.LabelShort} ({pawn.def.defName}) Hediff: {Props.hediff.defName}");
}
catch (System.Exception ex)
{
Log.Warning($"无法给 {pawn.LabelShort} 添加Hediff: {ex.Message}");
}
}
private void RemoveHediffFromPawn(Pawn pawn)
{
if (affectedPawns.TryGetValue(pawn, out var hediff))
{
try
{
// 安全地移除Hediff
if (pawn.health.hediffSet.hediffs.Contains(hediff))
{
pawn.health.RemoveHediff(hediff);
}
}
catch (System.Exception ex)
{
Log.Warning($"移除 {pawn.LabelShort} 的Hediff时出错: {ex.Message}");
}
affectedPawns.Remove(pawn);
}
// 移除视觉效果
RemoveEffectForPawn(pawn);
}
private void UpdateHediffDuration(Pawn pawn, Hediff hediff)
{
if (Props.hediffDurationTicks > 0)
{
var disappearComp = hediff.TryGetComp<HediffComp_Disappears>();
if (disappearComp != null)
{
// 使用 SetDuration 方法重置持续时间,让效果持续
disappearComp.SetDuration(Props.hediffDurationTicks);
}
}
}
private void CreateEffectForPawn(Pawn pawn)
{
if (Props.mote != null)
{
try
{
// 创建持续的视觉效果
var effecterDef = DefDatabase<EffecterDef>.GetNamedSilentFail(Props.mote.defName + "_Effecter");
if (effecterDef != null)
{
var effecter = effecterDef.Spawn();
effecters[pawn] = effecter;
}
else
{
// 如果没有对应的EffecterDef直接创建Mote
MoteMaker.MakeStaticMote(pawn.Position, pawn.Map, Props.mote, 1f);
}
}
catch (System.Exception ex)
{
Log.Warning($"创建视觉效果时出错: {ex.Message}");
}
}
}
private void RemoveEffectForPawn(Pawn pawn)
{
if (effecters.TryGetValue(pawn, out var effecter))
{
try
{
effecter.Cleanup();
}
catch (System.Exception ex)
{
Log.Warning($"清理视觉效果时出错: {ex.Message}");
}
effecters.Remove(pawn);
}
}
public override void CompTickRare()
{
base.CompTickRare();
// 更新视觉效果
var effectersToRemove = new List<Pawn>();
foreach (var kvp in effecters)
{
if (kvp.Key != null && kvp.Key.Spawned && affectedPawns.ContainsKey(kvp.Key))
{
try
{
kvp.Value.EffectTick(kvp.Key, kvp.Key);
}
catch (System.Exception ex)
{
Log.Warning($"更新视觉效果时出错: {ex.Message}");
effectersToRemove.Add(kvp.Key);
}
}
else
{
effectersToRemove.Add(kvp.Key);
}
}
// 清理无效的效果器
foreach (var pawn in effectersToRemove)
{
RemoveEffectForPawn(pawn);
}
}
public override void PostDeSpawn(Map map, DestroyMode mode = DestroyMode.Vanish)
{
base.PostDeSpawn(map);
CleanupAllEffects();
}
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
base.PostDestroy(mode, previousMap);
CleanupAllEffects();
}
/// <summary>
/// 清理所有效果
/// </summary>
private void CleanupAllEffects()
{
// 移除所有Hediff
var pawnsToRemove = new List<Pawn>(affectedPawns.Keys);
foreach (var pawn in pawnsToRemove)
{
RemoveHediffFromPawn(pawn);
}
affectedPawns.Clear();
// 清理所有视觉效果
var effectersToRemove = new List<Pawn>(effecters.Keys);
foreach (var pawn in effectersToRemove)
{
RemoveEffectForPawn(pawn);
}
effecters.Clear();
}
// 调试方法:显示影响范围
public override void PostDraw()
{
base.PostDraw();
if (Find.Selector.IsSelected(parent))
{
try
{
GenDraw.DrawRadiusRing(parent.Position, Props.range, Color.green);
}
catch (System.Exception ex)
{
Log.Warning($"绘制范围环时出错: {ex.Message}");
}
}
}
// 获取当前受影响的pawn数量用于显示
public int GetAffectedPawnCount()
{
return affectedPawns.Count;
}
// 获取受影响的pawn列表用于调试
public IEnumerable<Pawn> GetAffectedPawns()
{
return affectedPawns.Keys;
}
}
}