Files
ArachnaeSwarm/Source/ArachnaeSwarm/Pawn_Comps/ARA_CompHediffGiver/CompHediffGiver.cs
2026-02-13 11:58:35 +08:00

411 lines
16 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 System;
using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;
namespace ArachnaeSwarm
{
public class CompHediffGiver : ThingComp
{
private bool hediffsApplied = false; // 标记是否已经应用过hediff
// 用于记录添加的hediff和部位用于调试和撤销
private Dictionary<HediffDef, List<BodyPartRecord>> appliedHediffParts =
new Dictionary<HediffDef, List<BodyPartRecord>>();
public CompProperties_HediffGiver Props => (CompProperties_HediffGiver)this.props;
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
// 只有当thing是pawn时才添加hediff
if (this.parent is Pawn pawn)
{
// 检查是否已经应用过hediff或者是否是读档
if (!hediffsApplied && !respawningAfterLoad)
{
AddHediffsToPawn(pawn);
hediffsApplied = true; // 标记为已应用
}
}
}
private void AddHediffsToPawn(Pawn pawn)
{
// 检查是否有hediff列表
if (Props.hediffs == null || Props.hediffs.Count == 0)
return;
// 检查概率
if (Props.addChance < 1.0f && Rand.Value > Props.addChance)
return;
// 显示应用消息(如果有)
if (Props.showApplicationMessage && pawn.Faction == Faction.OfPlayer)
{
string message = Props.applicationMessageKey != null
? Props.applicationMessageKey.Translate(pawn.LabelShort)
: "ARA_HediffGiver_Applied".Translate(pawn.LabelShort, Props.hediffs.Count);
Messages.Message(message, pawn, MessageTypeDefOf.NeutralEvent);
}
// 为每个hediff添加到pawn
foreach (HediffDef hediffDef in Props.hediffs)
{
// 检查是否允许重复添加
if (!Props.allowDuplicates && pawn.health.hediffSet.HasHediff(hediffDef))
continue;
// === 新增:获取应应用的部位 ===
BodyPartDef bodyPartDef = Props.GetBodyPartForHediff(hediffDef);
List<BodyPartRecord> bodyParts = GetBodyPartsForHediff(pawn, hediffDef, bodyPartDef);
// 如果没有指定部位,或者没有找到匹配部位,则添加到全身
if (bodyParts == null || bodyParts.Count == 0)
{
AddHediffToPawn(pawn, hediffDef, null);
continue;
}
// 根据选择规则添加hediff到相应部位
foreach (var bodyPart in bodyParts)
{
AddHediffToPawn(pawn, hediffDef, bodyPart);
}
// 记录应用到的部位
if (bodyParts.Count > 0)
{
if (!appliedHediffParts.ContainsKey(hediffDef))
{
appliedHediffParts[hediffDef] = new List<BodyPartRecord>();
}
appliedHediffParts[hediffDef].AddRange(bodyParts);
}
}
// 播放应用效果(如果有)
if (Props.applicationEffect != null && pawn.Spawned)
{
Effecter effecter = Props.applicationEffect.Spawn();
effecter.Trigger(pawn, pawn);
effecter.Cleanup();
}
}
/// <summary>
/// 添加hediff到pawn的指定部位
/// </summary>
private void AddHediffToPawn(Pawn pawn, HediffDef hediffDef, BodyPartRecord bodyPart)
{
try
{
Hediff hediff = HediffMaker.MakeHediff(hediffDef, pawn, bodyPart);
// 设置严重度(如果有指定)
if (Props.initialSeverity >= 0f)
{
hediff.Severity = Props.initialSeverity;
}
// 添加hediff
pawn.health.AddHediff(hediff);
ArachnaeLog.Debug($"Added hediff {hediffDef.defName} to {pawn.Label} " +
$"{(bodyPart != null ? $"on {bodyPart.def.defName}" : "to whole body")}");
}
catch (Exception)
{
}
}
/// <summary>
/// 获取hediff应应用的身体部位列表
/// </summary>
private List<BodyPartRecord> GetBodyPartsForHediff(Pawn pawn, HediffDef hediffDef, BodyPartDef bodyPartDef)
{
if (pawn == null || pawn.RaceProps?.body == null)
return null;
// 如果没有指定身体部位,返回空列表
if (bodyPartDef == null)
return null;
try
{
// 获取所有匹配的身体部位
List<BodyPartRecord> allMatchingParts = pawn.RaceProps.body.GetPartsWithDef(bodyPartDef);
if (allMatchingParts == null || allMatchingParts.Count == 0)
{
// 如果没有找到匹配部位,检查是否有备用部位
var mapping = Props.GetMappingForHediff(hediffDef);
if (mapping != null && mapping.fallbackToDefault)
{
// 使用默认方式添加(全身)
return null;
}
return new List<BodyPartRecord>();
}
// 检查部位有效性
if (Props.checkPartValidity)
{
allMatchingParts = allMatchingParts.Where(part => IsBodyPartValid(pawn, part)).ToList();
}
if (allMatchingParts.Count == 0)
{
return new List<BodyPartRecord>();
}
// 获取选择规则
BodyPartSelectionRule rule = Props.GetPartSelectionRuleForHediff(hediffDef);
var mappingConfig = Props.GetMappingForHediff(hediffDef);
// 根据规则选择部位
List<BodyPartRecord> selectedParts = new List<BodyPartRecord>();
if (rule == null)
{
// 默认规则:使用第一个匹配的部位
selectedParts.Add(allMatchingParts[0]);
}
else
{
// 根据规则选择部位
switch (rule.mode)
{
case BodyPartSelectionMode.First:
selectedParts.Add(allMatchingParts[0]);
break;
case BodyPartSelectionMode.Random:
int count = Math.Min(rule.maxParts, allMatchingParts.Count);
selectedParts = allMatchingParts.InRandomOrder().Take(count).ToList();
break;
case BodyPartSelectionMode.All:
selectedParts = allMatchingParts;
break;
case BodyPartSelectionMode.MostDamaged:
var mostDamaged = allMatchingParts.OrderByDescending(p => GetPartDamage(pawn, p)).FirstOrDefault();
if (mostDamaged != null) selectedParts.Add(mostDamaged);
break;
case BodyPartSelectionMode.LeastDamaged:
var leastDamaged = allMatchingParts.OrderBy(p => GetPartDamage(pawn, p)).FirstOrDefault();
if (leastDamaged != null) selectedParts.Add(leastDamaged);
break;
}
// 如果配置了随机选择部位
if (mappingConfig != null && mappingConfig.chooseRandomPart)
{
selectedParts = allMatchingParts.InRandomOrder().Take(1).ToList();
}
// 处理对称性
if (rule.symmetrical && selectedParts.Count > 0)
{
selectedParts = GetSymmetricalParts(pawn, selectedParts[0], allMatchingParts);
}
}
return selectedParts;
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// 获取对称的身体部位
/// </summary>
private List<BodyPartRecord> GetSymmetricalParts(Pawn pawn, BodyPartRecord referencePart, List<BodyPartRecord> allParts)
{
List<BodyPartRecord> symmetricalParts = new List<BodyPartRecord> { referencePart };
// 查找对称部位(如左臂对应的右臂)
foreach (var part in allParts)
{
if (part != referencePart && part.def == referencePart.def)
{
// 简单的对称检测:检查部位标签或名称
if (IsSymmetricalPart(referencePart, part))
{
symmetricalParts.Add(part);
}
}
}
return symmetricalParts;
}
/// <summary>
/// 检查两个部位是否对称
/// </summary>
private bool IsSymmetricalPart(BodyPartRecord part1, BodyPartRecord part2)
{
// 简单的对称检测逻辑
string label1 = part1.customLabel ?? part1.def.label;
string label2 = part2.customLabel ?? part2.def.label;
// 检查是否包含对称标识符
string[] symmetryKeywords = { "Left", "Right", "Left", "Right", "Front", "Back", "Upper", "Lower" };
foreach (var keyword in symmetryKeywords)
{
if (label1.Contains(keyword) && label2.Contains(keyword))
{
// 检查是否是对称的关键词对
if ((keyword == "Left" && label2.Contains("Right")) ||
(keyword == "Right" && label2.Contains("Left")) ||
(keyword == "Front" && label2.Contains("Back")) ||
(keyword == "Back" && label2.Contains("Front")))
{
return true;
}
}
}
return false;
}
/// <summary>
/// 检查身体部位是否有效
/// </summary>
private bool IsBodyPartValid(Pawn pawn, BodyPartRecord part)
{
if (part == null)
return false;
// 检查部位是否已完全损坏
if (pawn.health.hediffSet.PartIsMissing(part))
return false;
// 检查部位是否被覆盖(如被装备遮挡)
// 这里可以添加更多有效性检查
return true;
}
/// <summary>
/// 获取部位的伤害值
/// </summary>
private float GetPartDamage(Pawn pawn, BodyPartRecord part)
{
if (part == null)
return 0f;
float totalDamage = 0f;
foreach (var hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.Part == part && hediff is Hediff_Injury injury)
{
totalDamage += injury.Severity;
}
}
return totalDamage;
}
// 序列化hediffsApplied标记
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref hediffsApplied, "hediffsApplied", false);
// 新增序列化已应用的hediff部位记录
Scribe_Collections.Look(ref appliedHediffParts, "appliedHediffParts",
LookMode.Def, LookMode.Deep);
}
// 调试方法用于手动触发hediff添加仅开发模式
public void DebugApplyHediffs()
{
if (this.parent is Pawn pawn && !hediffsApplied)
{
AddHediffsToPawn(pawn);
hediffsApplied = true;
ArachnaeLog.Debug($"Debug: Applied hediffs to {pawn.Label}");
}
}
/// <summary>
/// 获取已应用的hediff信息用于调试
/// </summary>
public string GetAppliedHediffInfo()
{
if (!hediffsApplied || !(this.parent is Pawn pawn))
return "No hediffs applied";
var result = new System.Text.StringBuilder();
result.AppendLine("Applied hediffs:");
foreach (var hediffDef in Props.hediffs)
{
var hediffs = pawn.health.hediffSet.hediffs.Where(h => h.def == hediffDef).ToList();
if (hediffs.Count > 0)
{
result.AppendLine($"- {hediffDef.defName} ({hediffs.Count} instances):");
foreach (var hediff in hediffs)
{
string partInfo = hediff.Part?.def?.defName ?? "No specific part";
result.AppendLine($" * On {partInfo}, Severity: {hediff.Severity:F2}");
}
}
else
{
result.AppendLine($"- {hediffDef.defName} (not applied)");
}
}
return result.ToString();
}
/// <summary>
/// 新增移除所有由该组件添加的hediff
/// </summary>
public void RemoveAppliedHediffs()
{
if (!(this.parent is Pawn pawn) || !hediffsApplied)
return;
int removedCount = 0;
foreach (var hediffDef in Props.hediffs)
{
var hediffs = pawn.health.hediffSet.hediffs.Where(h => h.def == hediffDef).ToList();
foreach (var hediff in hediffs)
{
pawn.health.RemoveHediff(hediff);
removedCount++;
}
}
hediffsApplied = false;
appliedHediffParts.Clear();
ArachnaeLog.Debug($"Removed {removedCount} hediffs from {pawn.Label}");
}
/// <summary>
/// 新增检查特定hediff是否已应用到指定部位
/// </summary>
public bool HasHediffOnPart(HediffDef hediffDef, BodyPartRecord part)
{
if (!(this.parent is Pawn pawn) || !hediffsApplied)
return false;
return pawn.health.hediffSet.hediffs
.Any(h => h.def == hediffDef && h.Part == part);
}
}
}