451 lines
15 KiB
C#
451 lines
15 KiB
C#
using RimWorld;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using Verse;
|
||
|
||
namespace ArachnaeSwarm
|
||
{
|
||
public class CompAbilityEffect_RandomHediff : CompAbilityEffect_WithDuration
|
||
{
|
||
public new CompProperties_AbilityRandomHediff Props => (CompProperties_AbilityRandomHediff)props;
|
||
|
||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||
{
|
||
base.Apply(target, dest);
|
||
|
||
if (!Props.ignoreSelf || target.Pawn != parent.pawn)
|
||
{
|
||
if (!Props.onlyApplyToSelf && Props.applyToTarget)
|
||
{
|
||
ApplyInner(target.Pawn, parent.pawn);
|
||
}
|
||
if (Props.applyToSelf || Props.onlyApplyToSelf)
|
||
{
|
||
ApplyInner(parent.pawn, target.Pawn);
|
||
}
|
||
}
|
||
}
|
||
|
||
protected void ApplyInner(Pawn target, Pawn other)
|
||
{
|
||
if (target == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (TryResist(target))
|
||
{
|
||
MoteMaker.ThrowText(target.DrawPos, target.Map, "Resisted".Translate());
|
||
return;
|
||
}
|
||
|
||
// 随机选择一个 hediff
|
||
var selectedHediffEntry = SelectRandomHediffEntry(target);
|
||
if (selectedHediffEntry == null)
|
||
{
|
||
// 没有可用的 hediff
|
||
if (Props.showNoValidHediffMessage && PawnUtility.ShouldSendNotificationAbout(parent.pawn))
|
||
{
|
||
Messages.Message("ARA_NoValidHediffAvailable".Translate(), target, MessageTypeDefOf.NeutralEvent);
|
||
}
|
||
return;
|
||
}
|
||
|
||
var hediffDef = selectedHediffEntry.hediffDef;
|
||
|
||
// 检查是否允许重复施加(这里应该不会执行到,因为CanApplyOn已经检查过)
|
||
if (!Props.allowMultipleHediffs && target.health.hediffSet.HasHediff(hediffDef))
|
||
{
|
||
if (Props.showAlreadyHasHediffMessage && PawnUtility.ShouldSendNotificationAbout(parent.pawn))
|
||
{
|
||
Messages.Message("ARA_TargetAlreadyHasHediff".Translate(target.LabelShort, hediffDef.label),
|
||
target, MessageTypeDefOf.NeutralEvent);
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 替换现有 hediff(如果配置)
|
||
if (Props.replaceExisting)
|
||
{
|
||
Hediff existingHediff = target.health.hediffSet.GetFirstHediffOfDef(hediffDef);
|
||
if (existingHediff != null)
|
||
{
|
||
target.health.RemoveHediff(existingHediff);
|
||
}
|
||
}
|
||
|
||
// 创建并应用 hediff
|
||
Hediff hediff = HediffMaker.MakeHediff(hediffDef, target, Props.onlyBrain ? target.health.hediffSet.GetBrain() : null);
|
||
|
||
// 设置持续时间
|
||
HediffComp_Disappears disappearsComp = hediff.TryGetComp<HediffComp_Disappears>();
|
||
if (disappearsComp != null)
|
||
{
|
||
disappearsComp.ticksToDisappear = GetDurationSeconds(target).SecondsToTicks();
|
||
}
|
||
|
||
// 设置严重程度
|
||
float severity = selectedHediffEntry.severity >= 0f ? selectedHediffEntry.severity : Props.severity;
|
||
if (severity >= 0f)
|
||
{
|
||
hediff.Severity = severity;
|
||
}
|
||
|
||
// 处理链接 hediff
|
||
HediffComp_Link linkComp = hediff.TryGetComp<HediffComp_Link>();
|
||
if (linkComp != null)
|
||
{
|
||
linkComp.other = other;
|
||
linkComp.drawConnection = target == parent.pawn;
|
||
}
|
||
|
||
target.health.AddHediff(hediff);
|
||
|
||
// 显示施加的消息
|
||
if (Props.showAppliedMessage && PawnUtility.ShouldSendNotificationAbout(parent.pawn))
|
||
{
|
||
Messages.Message("ARA_HediffApplied".Translate(parent.pawn.LabelShort, hediffDef.label, target.LabelShort),
|
||
target, MessageTypeDefOf.PositiveEvent);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据权重和科技要求随机选择一个 hediff
|
||
/// </summary>
|
||
private HediffEntry SelectRandomHediffEntry(Pawn target)
|
||
{
|
||
var availableEntries = new List<HediffEntry>();
|
||
var availableWeights = new List<float>();
|
||
|
||
foreach (var entry in Props.hediffEntries)
|
||
{
|
||
// 检查科技要求
|
||
if (entry.requiredResearchProject != null && !entry.requiredResearchProject.IsFinished)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 检查其他条件
|
||
if (!CheckHediffConditions(entry, target))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 如果不允许重复施加,检查目标是否已经有这个 hediff
|
||
if (!Props.allowMultipleHediffs && target.health.hediffSet.HasHediff(entry.hediffDef))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
availableEntries.Add(entry);
|
||
availableWeights.Add(entry.weight);
|
||
}
|
||
|
||
if (availableEntries.Count == 0)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 使用权重随机选择
|
||
return availableEntries.RandomElementByWeight(entry => entry.weight);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有可用的 hediff 条目(用于显示)
|
||
/// </summary>
|
||
private List<HediffEntry> GetAvailableHediffEntries(Pawn target = null)
|
||
{
|
||
var availableEntries = new List<HediffEntry>();
|
||
|
||
foreach (var entry in Props.hediffEntries)
|
||
{
|
||
// 检查科技要求
|
||
if (entry.requiredResearchProject != null && !entry.requiredResearchProject.IsFinished)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 如果有目标,检查目标条件
|
||
if (target != null && !CheckHediffConditions(entry, target))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 如果不允许重复施加,检查目标是否已经有这个 hediff
|
||
if (target != null && !Props.allowMultipleHediffs && target.health.hediffSet.HasHediff(entry.hediffDef))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
availableEntries.Add(entry);
|
||
}
|
||
|
||
return availableEntries;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查目标是否已经有任何列表中的 hediff(用于CanApplyOn)
|
||
/// </summary>
|
||
private bool TargetHasAnyListedHediff(Pawn target)
|
||
{
|
||
if (target == null || Props.allowMultipleHediffs)
|
||
return false;
|
||
|
||
foreach (var entry in Props.hediffEntries)
|
||
{
|
||
// 检查科技要求
|
||
if (entry.requiredResearchProject != null && !entry.requiredResearchProject.IsFinished)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 检查其他条件
|
||
if (!CheckHediffConditions(entry, target))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 如果目标已经有这个 hediff,返回 true
|
||
if (target.health.hediffSet.HasHediff(entry.hediffDef))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查 hediff 的额外条件
|
||
/// </summary>
|
||
private bool CheckHediffConditions(HediffEntry entry, Pawn target)
|
||
{
|
||
if (entry.onlyApplyToLiving && (target.Dead || target.Destroyed))
|
||
return false;
|
||
|
||
if (entry.onlyApplyToNonMechanoid && target.RaceProps.IsMechanoid)
|
||
return false;
|
||
|
||
if (entry.onlyApplyToOrganic && !target.RaceProps.IsFlesh)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查目标是否在黑名单中
|
||
/// </summary>
|
||
private bool IsTargetBlacklisted(Pawn target)
|
||
{
|
||
if (target == null || Props.blacklistHediffs.NullOrEmpty())
|
||
return false;
|
||
|
||
foreach (var hediffDef in Props.blacklistHediffs)
|
||
{
|
||
if (target.health.hediffSet.HasHediff(hediffDef))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
protected virtual bool TryResist(Pawn pawn)
|
||
{
|
||
if (Props.resistChance > 0f)
|
||
{
|
||
float resistChance = Props.resistChance;
|
||
|
||
if (pawn != null && pawn.health != null)
|
||
{
|
||
resistChance *= pawn.GetStatValue(StatDefOf.ToxicResistance);
|
||
}
|
||
|
||
return Rand.Chance(resistChance);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public override bool AICanTargetNow(LocalTargetInfo target)
|
||
{
|
||
if (parent.pawn.Faction == Faction.OfPlayer)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (target.Pawn == null)
|
||
return false;
|
||
|
||
// 检查目标是否在黑名单中
|
||
if (IsTargetBlacklisted(target.Pawn))
|
||
return false;
|
||
|
||
// 检查目标是否已经有任何列表中的 hediff
|
||
if (TargetHasAnyListedHediff(target.Pawn))
|
||
return false;
|
||
|
||
// 检查是否有至少一个可用的 hediff
|
||
return SelectRandomHediffEntry(target.Pawn) != null;
|
||
}
|
||
|
||
public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest)
|
||
{
|
||
if (!base.CanApplyOn(target, dest))
|
||
return false;
|
||
|
||
if (target.Pawn == null)
|
||
return false;
|
||
|
||
// 检查目标是否在黑名单中
|
||
if (IsTargetBlacklisted(target.Pawn))
|
||
return false;
|
||
|
||
// 检查目标是否已经有任何列表中的 hediff
|
||
if (TargetHasAnyListedHediff(target.Pawn))
|
||
return false;
|
||
|
||
// 检查是否有至少一个可用的 hediff
|
||
return SelectRandomHediffEntry(target.Pawn) != null;
|
||
}
|
||
|
||
public override string ExtraLabelMouseAttachment(LocalTargetInfo target)
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
|
||
if (target.Pawn == null)
|
||
{
|
||
// 没有具体目标时的显示
|
||
sb.AppendLine("ARA_AbilityReady".Translate());
|
||
sb.AppendLine();
|
||
|
||
// 显示所有可能的 hediff(不考虑目标限制)
|
||
var availableEntries = GetAvailableHediffEntries();
|
||
|
||
if (availableEntries.Any())
|
||
{
|
||
sb.AppendLine("ARA_PossibleEffects".Translate());
|
||
foreach (var entry in availableEntries)
|
||
{
|
||
sb.AppendLine($" • {entry.hediffDef.label} ({entry.weight:F1})");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 检查黑名单
|
||
if (IsTargetBlacklisted(target.Pawn))
|
||
{
|
||
sb.AppendLine("ARA_TargetBlacklisted".Translate());
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
// 检查目标是否已经有任何列表中的 hediff
|
||
if (TargetHasAnyListedHediff(target.Pawn))
|
||
{
|
||
sb.AppendLine("ARA_TargetAlreadyHasHediff".Translate());
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
// 有具体目标时的显示
|
||
var availableEntries = GetAvailableHediffEntries(target.Pawn);
|
||
|
||
if (availableEntries.Any())
|
||
{
|
||
// 显示所有可能的 hediff
|
||
var hediffNames = availableEntries.Select(e => e.hediffDef.label).ToArray();
|
||
string hediffList = string.Join(", ", hediffNames);
|
||
|
||
sb.AppendLine("ARA_PotentialHediffs".Translate(hediffList));
|
||
|
||
// 显示抵抗几率信息
|
||
if (Props.resistChance > 0f)
|
||
{
|
||
float actualResistChance = Props.resistChance * target.Pawn.GetStatValue(StatDefOf.ToxicResistance);
|
||
sb.AppendLine("ARA_ResistChance".Translate(actualResistChance.ToStringPercent()));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sb.AppendLine("ARA_NoValidHediff".Translate());
|
||
}
|
||
}
|
||
|
||
return sb.ToString().TrimEndNewlines();
|
||
}
|
||
|
||
public override void DrawEffectPreview(LocalTargetInfo target)
|
||
{
|
||
base.DrawEffectPreview(target);
|
||
|
||
// 可选:在地图上绘制额外的预览效果
|
||
if (target.IsValid && target.Pawn != null)
|
||
{
|
||
// 检查黑名单
|
||
if (IsTargetBlacklisted(target.Pawn))
|
||
{
|
||
// 可以在这里绘制红色轮廓表示目标无效
|
||
return;
|
||
}
|
||
|
||
// 检查目标是否已经有任何列表中的 hediff
|
||
if (TargetHasAnyListedHediff(target.Pawn))
|
||
{
|
||
// 可以在这里绘制红色轮廓表示目标无效
|
||
return;
|
||
}
|
||
|
||
var selectedEntry = SelectRandomHediffEntry(target.Pawn);
|
||
if (selectedEntry != null)
|
||
{
|
||
// 在目标上方显示预览效果
|
||
GenDraw.DrawTargetHighlight(target);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public class CompProperties_AbilityRandomHediff : CompProperties_AbilityEffect
|
||
{
|
||
public List<HediffEntry> hediffEntries;
|
||
|
||
// 基础属性(从原版继承)
|
||
public bool ignoreSelf = true;
|
||
public bool onlyApplyToSelf = false;
|
||
public bool applyToTarget = true;
|
||
public bool applyToSelf = false;
|
||
public bool replaceExisting = false;
|
||
public bool onlyBrain = false;
|
||
public float severity = -1f;
|
||
|
||
// 新添加的属性
|
||
public bool allowMultipleHediffs = false;
|
||
public float resistChance = 0f;
|
||
public bool showAppliedMessage = true;
|
||
public bool showAlreadyHasHediffMessage = true;
|
||
public bool showNoValidHediffMessage = true;
|
||
|
||
// 黑名单功能:拥有这些 hediff 的目标无法成为目标
|
||
public List<HediffDef> blacklistHediffs;
|
||
|
||
public CompProperties_AbilityRandomHediff()
|
||
{
|
||
compClass = typeof(CompAbilityEffect_RandomHediff);
|
||
}
|
||
}
|
||
|
||
public class HediffEntry
|
||
{
|
||
public HediffDef hediffDef;
|
||
public float weight = 1f;
|
||
public ResearchProjectDef requiredResearchProject;
|
||
public float severity = -1f; // 如果为负值,则使用 CompProperties 中的 severity
|
||
|
||
// 额外的条件
|
||
public bool onlyApplyToLiving = true;
|
||
public bool onlyApplyToNonMechanoid = true;
|
||
public bool onlyApplyToOrganic = true;
|
||
}
|
||
}
|