using System.Collections.Generic; using RimWorld; using UnityEngine; using Verse; using Verse.AI; using Verse.AI.Group; using Verse.Sound; namespace WulaFallenEmpire { public class CompFighterInvisible : ThingComp { public CompProperties_FighterInvisible Props => (CompProperties_FighterInvisible)props; [Unsaved(false)] private HediffComp_Invisibility invisibility; private int lastDetectedTick = -99999; private int lastRevealedTick = -99999; private Pawn Sightstealer => (Pawn)parent; // 新增:记录最后一次检查敌人的时间 private int lastEnemyCheckTick = -99999; public HediffDef GetTargetInvisibilityDef() { return Props.InvisibilityDef; } // 添加一个属性来检查是否有效 private bool IsValid => Sightstealer?.health?.hediffSet != null && GetTargetInvisibilityDef() != null && !Sightstealer.IsShambler && Sightstealer.Spawned && Sightstealer.Map != null; private HediffComp_Invisibility Invisibility { get { if (!IsValid) return null; return invisibility ?? (invisibility = Sightstealer.health.hediffSet .GetFirstHediffOfDef(GetTargetInvisibilityDef()) ?.TryGetComp()); } } public override void PostExposeData() { base.PostExposeData(); Scribe_Values.Look(ref lastDetectedTick, "lastDetectedTick", 0); Scribe_Values.Look(ref lastRevealedTick, "lastRevealedTick", 0); Scribe_Values.Look(ref lastEnemyCheckTick, "lastEnemyCheckTick", 0); } public override void CompTick() { // 使用统一的有效性检查 if (!IsValid || Invisibility == null) return; // 检查敌人 CheckForEnemiesInSight(); // 隐身恢复逻辑 if (Sightstealer.IsHashIntervalTick(Props.CheckDetectedIntervalTicks)) { if (Find.TickManager.TicksGame > lastDetectedTick + Props.stealthCooldownTicks) { Invisibility.BecomeInvisible(); } } } public override void Notify_UsedVerb(Pawn pawn, Verb verb) { base.Notify_UsedVerb(pawn, verb); // 统一的 null 检查 if (Invisibility == null) return; Invisibility.BecomeVisible(); lastDetectedTick = Find.TickManager.TicksGame; } /// /// 检查视线内是否有敌人 /// private void CheckForEnemiesInSight() { // 检查频率:每30 tick检查一次(约0.5秒) if (!Sightstealer.IsHashIntervalTick(30) || Find.TickManager.TicksGame <= lastEnemyCheckTick + 30) { return; } lastEnemyCheckTick = Find.TickManager.TicksGame; // 如果配置为只在战斗状态时检查,且当前不在战斗状态,则跳过 if (Props.onlyCheckInCombat && !IsInCombatState()) { return; } // 检查视线内是否有敌人 bool enemyInSight = false; List enemiesInSight = new List(); // 获取地图上所有Pawn IReadOnlyList allPawns = Sightstealer.Map.mapPawns.AllPawnsSpawned; foreach (Pawn otherPawn in allPawns) { // 跳过自身 if (otherPawn == Sightstealer) continue; // 跳过自律机械 if (otherPawn.GetComp() != null) continue; // 跳过死亡的 if (otherPawn.Dead) continue; // 跳过倒地的(如果配置为忽略) if (Props.ignoreDownedEnemies && otherPawn.Downed) continue; // 跳过睡着的(如果配置为忽略) if (Props.ignoreSleepingEnemies && otherPawn.CurJobDef == JobDefOf.LayDown) continue; // 检查是否为敌对关系 if (!otherPawn.HostileTo(Sightstealer)) continue; // 检查敌人类型过滤器(如果有) if (Props.enemyTypeFilter != null && Props.enemyTypeFilter.Count > 0) { if (!Props.enemyTypeFilter.Contains(otherPawn.def)) continue; } // 关键修改:直接检查直线可见性,不使用距离限制 if (GenSight.LineOfSight(Sightstealer.Position, otherPawn.Position, Sightstealer.Map)) { enemiesInSight.Add(otherPawn); enemyInSight = true; // 如果只需要知道是否有敌人,且已经找到一个,可以提前退出循环 if (Props.minEnemiesToReveal <= 1) { break; } } } // 如果启用敌人检测后解除隐身,并且发现了足够数量的敌人 if (enemyInSight && Props.revealOnEnemyInSight && enemiesInSight.Count >= Props.minEnemiesToReveal) { // 立即解除隐身 Invisibility.BecomeVisible(); lastDetectedTick = Find.TickManager.TicksGame; lastRevealedTick = Find.TickManager.TicksGame; // 可选:添加视觉或声音效果 if (Props.showRevealEffect) { ShowRevealEffect(enemiesInSight); } // 可选:发送消息 if (Props.sendRevealMessage && Sightstealer.Faction == Faction.OfPlayer) { SendRevealMessage(enemiesInSight); } } } /// /// 检查是否处于战斗状态 /// private bool IsInCombatState() { // 如果有当前工作且是战斗相关工作 if (Sightstealer.CurJob != null) { JobDef jobDef = Sightstealer.CurJob.def; if (jobDef == JobDefOf.AttackMelee || jobDef == JobDefOf.AttackStatic || jobDef == JobDefOf.Wait_Combat || jobDef == JobDefOf.Flee || jobDef == JobDefOf.FleeAndCower) { return true; } } // 如果有敌人目标 if (Sightstealer.mindState.enemyTarget != null) { return true; } // 如果最近受到过伤害 if (Find.TickManager.TicksGame - Sightstealer.mindState.lastHarmTick < 300) // 最近5秒内受到伤害 { return true; } // 如果最近攻击过目标 if (Find.TickManager.TicksGame - Sightstealer.mindState.lastAttackTargetTick < 300) { return true; } return false; } /// /// 显示解除隐身的效果 /// private void ShowRevealEffect(List enemies) { if (Sightstealer.Map == null) return; // 创建一个闪光效果 FleckMaker.ThrowLightningGlow(Sightstealer.Position.ToVector3Shifted(), Sightstealer.Map, 2f); // 可选:播放声音 if (Props.revealSound != null) { Props.revealSound.PlayOneShot(new TargetInfo(Sightstealer.Position, Sightstealer.Map)); } } /// /// 发送解除隐身消息 /// private void SendRevealMessage(List enemies) { if (enemies.Count == 0) return; string message; if (enemies.Count == 1) { message = "WFE.RevealedBySingleEnemy".Translate( Sightstealer.LabelShort, enemies[0].LabelShort ); } else { message = "WFE.RevealedByMultipleEnemies".Translate( Sightstealer.LabelShort, enemies.Count ); } Messages.Message(message, Sightstealer, MessageTypeDefOf.NeutralEvent); } /// /// 获取下次可以隐身的时间 /// public int NextInvisibilityTick => lastDetectedTick + Props.stealthCooldownTicks; /// /// 手动触发解除隐身(供外部调用) /// public void ForceReveal() { if (Invisibility == null) return; Invisibility.BecomeVisible(); lastDetectedTick = Find.TickManager.TicksGame; lastRevealedTick = Find.TickManager.TicksGame; } } }