// File: Verb_RangeChecker.cs using RimWorld; using System.Collections.Generic; using UnityEngine; using Verse; namespace WulaFallenEmpire { /// /// 用于距离判断的Verb,不发射任何射弹,不造成伤害,仅用于距离计算和AI判断 /// 当发射成功时,会设置Pawn身上所有Comp_MultiTurretGun的focusTarget为目标 /// public class Verb_RangeChecker : Verb_LaunchProjectile { protected override bool TryCastShot() { if (currentTarget.HasThing && currentTarget.Thing.Map != caster.Map) { return false; } ThingDef projectile = Projectile; if (projectile == null) { return false; } ShootLine resultingLine; bool flag = TryFindShootLineFromTo(caster.Position, currentTarget, out resultingLine); if (verbProps.stopBurstWithoutLos && !flag) { return false; } if (base.EquipmentSource != null) { base.EquipmentSource.GetComp()?.Notify_ProjectileLaunched(); base.EquipmentSource.GetComp()?.UsedOnce(); } lastShotTick = Find.TickManager.TicksGame; Thing manningPawn = caster; Thing equipmentSource = base.EquipmentSource; CompMannable compMannable = caster.TryGetComp(); if (compMannable?.ManningPawn != null) { manningPawn = compMannable.ManningPawn; equipmentSource = caster; } Vector3 drawPos = caster.DrawPos; Projectile projectile2 = (Projectile)GenSpawn.Spawn(projectile, resultingLine.Source, caster.Map); if (equipmentSource.TryGetComp(out CompUniqueWeapon comp)) { foreach (WeaponTraitDef item in comp.TraitsListForReading) { if (item.damageDefOverride != null) { projectile2.damageDefOverride = item.damageDefOverride; } if (!item.extraDamages.NullOrEmpty()) { Projectile projectile3 = projectile2; if (projectile3.extraDamages == null) { projectile3.extraDamages = new List(); } projectile2.extraDamages.AddRange(item.extraDamages); } } } if (verbProps.ForcedMissRadius > 0.5f) { float num = verbProps.ForcedMissRadius; if (manningPawn is Pawn pawn) { num *= verbProps.GetForceMissFactorFor(equipmentSource, pawn); } float num2 = VerbUtility.CalculateAdjustedForcedMiss(num, currentTarget.Cell - caster.Position); if (num2 > 0.5f) { IntVec3 forcedMissTarget = GetForcedMissTarget(num2); if (forcedMissTarget != currentTarget.Cell) { ProjectileHitFlags projectileHitFlags = ProjectileHitFlags.NonTargetWorld; if (Rand.Chance(0.5f)) { projectileHitFlags = ProjectileHitFlags.All; } if (!canHitNonTargetPawnsNow) { projectileHitFlags &= ~ProjectileHitFlags.NonTargetPawns; } // 模拟发射成功,但不实际发射 bool shotResult = SimulateShotSuccess(drawPos, forcedMissTarget, currentTarget, projectileHitFlags, preventFriendlyFire, equipmentSource); if (shotResult) { UpdateTurretFocusTargets(); } return shotResult; } } } ShotReport shotReport = ShotReport.HitReportFor(caster, this, currentTarget); Thing randomCoverToMissInto = shotReport.GetRandomCoverToMissInto(); ThingDef targetCoverDef = randomCoverToMissInto?.def; if (verbProps.canGoWild && !Rand.Chance(shotReport.AimOnTargetChance_IgnoringPosture)) { bool flyOverhead = projectile2?.def?.projectile != null && projectile2.def.projectile.flyOverhead; resultingLine.ChangeDestToMissWild(shotReport.AimOnTargetChance_StandardTarget, flyOverhead, caster.Map); ProjectileHitFlags projectileHitFlags2 = ProjectileHitFlags.NonTargetWorld; if (Rand.Chance(0.5f) && canHitNonTargetPawnsNow) { projectileHitFlags2 |= ProjectileHitFlags.NonTargetPawns; } // 模拟发射成功,但不实际发射 bool shotResult = SimulateShotSuccess(drawPos, resultingLine.Dest, currentTarget, projectileHitFlags2, preventFriendlyFire, equipmentSource, targetCoverDef); if (shotResult) { UpdateTurretFocusTargets(); } return shotResult; } if (currentTarget.Thing != null && currentTarget.Thing.def.CanBenefitFromCover && !Rand.Chance(shotReport.PassCoverChance)) { ProjectileHitFlags projectileHitFlags3 = ProjectileHitFlags.NonTargetWorld; if (canHitNonTargetPawnsNow) { projectileHitFlags3 |= ProjectileHitFlags.NonTargetPawns; } // 模拟发射成功,但不实际发射 bool shotResult = SimulateShotSuccess(drawPos, randomCoverToMissInto, currentTarget, projectileHitFlags3, preventFriendlyFire, equipmentSource, targetCoverDef); if (shotResult) { UpdateTurretFocusTargets(); } return shotResult; } ProjectileHitFlags projectileHitFlags4 = ProjectileHitFlags.IntendedTarget; if (canHitNonTargetPawnsNow) { projectileHitFlags4 |= ProjectileHitFlags.NonTargetPawns; } if (!currentTarget.HasThing || currentTarget.Thing.def.Fillage == FillCategory.Full) { projectileHitFlags4 |= ProjectileHitFlags.NonTargetWorld; } // 模拟发射成功,但不实际发射 bool finalShotResult = SimulateFinalShotSuccess(drawPos, resultingLine.Dest, currentTarget, projectileHitFlags4, preventFriendlyFire, equipmentSource, targetCoverDef); if (finalShotResult) { UpdateTurretFocusTargets(); } return finalShotResult; } /// /// 模拟射击成功的情况 /// private bool SimulateShotSuccess(Vector3 drawPos, IntVec3 targetCell, LocalTargetInfo target, ProjectileHitFlags hitFlags, bool preventFriendlyFire, Thing equipmentSource, ThingDef targetCoverDef = null) { // 这里不实际发射射弹,只返回成功 // 销毁之前创建的射弹对象,因为我们不需要它 return true; } /// /// 模拟射击成功的情况(带目标) /// private bool SimulateShotSuccess(Vector3 drawPos, Thing target, LocalTargetInfo originalTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire, Thing equipmentSource, ThingDef targetCoverDef = null) { // 这里不实际发射射弹,只返回成功 // 销毁之前创建的射弹对象,因为我们不需要它 return true; } /// /// 模拟最终射击成功的情况 /// private bool SimulateFinalShotSuccess(Vector3 drawPos, IntVec3 targetCell, LocalTargetInfo target, ProjectileHitFlags hitFlags, bool preventFriendlyFire, Thing equipmentSource, ThingDef targetCoverDef = null) { // 这里不实际发射射弹,只返回成功 // 销毁之前创建的射弹对象,因为我们不需要它 return true; } /// /// 更新Pawn身上所有Comp_MultiTurretGun的focusTarget /// private void UpdateTurretFocusTargets() { if (caster is Pawn pawn && pawn.Spawned) { // 获取Pawn身上所有的Comp_MultiTurretGun组件 var turretComps = pawn.GetComps(); foreach (var turretComp in turretComps) { // 设置集中火力目标 Comp_MultiTurretGun.focusTarget = currentTarget; Comp_MultiTurretGun.lastFocusSetTick = Find.TickManager.TicksGame; Comp_MultiTurretGun.lastFocusPawn = pawn; // 强制炮塔立即重新索敌,以便它们能检测到新的集中火力目标 turretComp.TryAcquireTarget(); } } } } /// /// 用于距离判断的Verb属性 /// public class VerbProperties_RangeChecker : VerbProperties { public VerbProperties_RangeChecker() { verbClass = typeof(Verb_RangeChecker); // 默认设置为不发射射弹 defaultProjectile = null; } } }