diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index caddfe47..c09b2360 100644
Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ
diff --git a/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
index 01fecea4..c9469457 100644
--- a/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
+++ b/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
@@ -372,4 +372,75 @@
+
+
+ Wula_TerrainBlocked
+
+ 虽然乌拉族的大部分构装体采用反重力悬浮可以无视崎岖地表,但是其庞大的身躯依然会导致其在狭窄地形中难以行动。
+ HediffWithComps
+ 1
+ false
+
+
+ 0.1
+
+ 0.9
+
+
+
+ 0.2
+
+ 0.8
+
+
+
+ 0.3
+
+ 0.7
+
+
+
+ 0.4
+
+ 0.6
+
+
+
+ 0.5
+
+ 0.5
+
+
+
+ 0.6
+
+ 0.4
+
+
+
+ 0.7
+
+ 0.3
+
+
+
+ 0.8
+
+ 0.2
+
+
+
+ 0.9
+
+ 0.1
+
+
+
+
+
+ 0.75
+ 60
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
index 7752c73e..8fe1b576 100644
--- a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
+++ b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
@@ -204,10 +204,13 @@
99999~99999
0.7
+
+ Wula_AI_Heavy_Panzer_Weapon
+
Wula_AI_Rocket_Panzer
-
+
Wula_AI_Rocket_Panzer
500
false
@@ -239,7 +242,7 @@
0.7
- Wula_AI_Heavy_Panzer_Weapon
+ Wula_AI_Rocket_Panzer_Weapon
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
index 0577b16a..f93e5bba 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
@@ -438,14 +438,14 @@
WULA_RW_Handle_Cannon_Burn
40
130
- 1
+ 1.5
1
Wula_AI_Heavy_Panzer_Main_Weapon
-
- HAp-6"战车"车体正面的突击炮,射程很短并且只能在静止状态开火,但是威力巨大,专门用于对付坚固的工事和成片的人群。
+
+ HAp-6"巨戟"车体上的测距器,可以确保其炮塔在可以开火的最佳距离,被其瞄准的目标会成为炮塔的优先攻击目标。
Normal
Spacer
None
@@ -466,87 +466,43 @@
1
1
1
- 3.5
+ 0.1
- Verb_Shoot
+ WulaFallenEmpire.Verb_RangeChecker
true
- Bullet_Wula_AI_Heavy_Panzer_Main_Weapon
- 2
- 21
+ Bullet_ChargeRifle
+ 5.9
+ 60
+ 0.2
1
- 1
- RocketswarmLauncher_Fire
- GunTail_Heavy
+
true
- 200
- 12
+ 1
Wula_AI_Heavy_Panzer_Weapon
-
+
-
- Bullet_Wula_AI_Heavy_Panzer_Main_Weapon
-
- RealtimeOnly
-
- Wula/Projectile/WULA_Shrapnel
- Graphic_Single
- (2,2)
-
- WulaFallenEmpire.Projectile_NorthArcTrail
- Normal
- True
-
- WULA_GiantBomb
- 65
- 25
- 6
- 1.5
- true
- Artillery_HitThickRoof
- MortarBomb_Explode
- MortarRound_PreImpact
- MortarRound_Ambient
- 10
- Filth_BlastMark
-
-
-
- 5
- 1.0
- true
-
-
- WULA_Smoke_Tail
- 5
- 1
- 1~2
- 0.5~1.0
- 0.1~0.3
- -30~30
-
-
-
Wula_AI_Rocket_Panzer_Turret_Weapon
- HRp-3"喷火战车"的炮塔,可以一次性发射大量的火箭弹。
+ HRp-3"炎霖"的炮塔,可以一次性发射大量的火箭弹。
None
true
Ultra
@@ -565,7 +521,7 @@
- Verb_Shoot
+ WulaFallenEmpire.Verb_TurretOffestShoot
true
Bullet_Wula_AI_Rocket_Panzer_Turret_Weapon
0
@@ -581,6 +537,14 @@
18
+
+
+
+ (0.62, -4.1)
+ (-0.62, -4.1)
+
+
+
Bullet_Wula_AI_Rocket_Panzer_Turret_Weapon
@@ -610,7 +574,7 @@
- 6
+ 18
1.0
true
@@ -625,6 +589,64 @@
+
+ Wula_AI_Rocket_Panzer_Main_Weapon
+
+ HRp-3"炎霖"车体上的测距器,可以确保其炮塔在可以开火的最佳距离,被其瞄准的目标会成为炮塔的优先攻击目标。
+ Normal
+ Spacer
+ None
+ true
+ Wula/Projectile/WULA_Shrapnel
+
+ Wula/Weapon/WULA_Weapon_Empty
+ Graphic_Single
+ 1.35
+
+ Interact_Rifle
+
+
+ 2500
+
+ 8
+ 1
+ 1
+ 1
+ 1
+ 0.1
+
+
+
+ WulaFallenEmpire.Verb_RangeChecker
+ true
+ Bullet_ChargeRifle
+ 12
+ 79
+ 0.2
+ 1
+ false
+
+
+ true
+
+
+
+
+ 1
+
+
+ Wula_AI_Rocket_Panzer_Weapon
+
+
+
+
+
+ Wula_AI_Rocket_Panzer
+
+
+
+
Wula_Psi_Titan_Beam
diff --git a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
index be604906..87f7d407 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
@@ -81,6 +81,8 @@
1
1
2
+
+ 3
300
@@ -118,7 +120,7 @@
Wula_AI_Heavy_Panzer_Turret_Weapon
20
0
- 3
+ 6
true
1.2
@@ -328,6 +330,12 @@
PawnFlyer
PawnFlyerLand
+
+
+ true
+ 1
+ 60
+ Wula_TerrainBlocked
false
@@ -338,8 +346,8 @@
Wula_AI_Rocket_Panzer
-
- 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢。
+
+ 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,可以在远距离上使用火箭弹巢发射漫天的弹幕,用纯粹的火力淹没敌方集群。
2
2
@@ -351,6 +359,8 @@
1
1
2
+
+ 3
300
@@ -390,7 +400,7 @@
0
8
true
- 10
+ 12.2
@@ -463,7 +473,7 @@
ConstructMetal
- Wula_AI_Heavy_Panzer_Main_Weapon
+ Wula_AI_Rocket_Panzer_Main_Weapon
true
diff --git a/Source/WulaFallenEmpire/HediffComp/WULA_TerrainBlocked/HediffComp_TerrainBlocked.cs b/Source/WulaFallenEmpire/HediffComp/WULA_TerrainBlocked/HediffComp_TerrainBlocked.cs
new file mode 100644
index 00000000..069aef8b
--- /dev/null
+++ b/Source/WulaFallenEmpire/HediffComp/WULA_TerrainBlocked/HediffComp_TerrainBlocked.cs
@@ -0,0 +1,115 @@
+using RimWorld;
+using Verse;
+using UnityEngine;
+
+namespace WulaFallenEmpire
+{
+ ///
+ /// 地形阻挡Hediff组件,用于调整移动速度
+ ///
+ public class HediffComp_TerrainBlocked : HediffComp
+ {
+ public HediffCompProperties_TerrainBlocked Props => (HediffCompProperties_TerrainBlocked)props;
+
+ ///
+ /// 当前地形阻挡严重度(0-1之间)
+ ///
+ public float currentBlockSeverity = 0f;
+
+ ///
+ /// 上一次更新时间(ticks)
+ ///
+ private int lastUpdateTick = -1;
+
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ base.CompPostTick(ref severityAdjustment);
+
+ // 降低更新频率:每Props.checkIntervalTicks检查一次
+ if (Find.TickManager.TicksGame % Props.checkIntervalTicks != 0)
+ return;
+
+ // 如果Pawn已死亡或无法移动,清除效果
+ if (Pawn == null || Pawn.Dead || Pawn.Downed || !Pawn.Spawned)
+ {
+ currentBlockSeverity = 0f;
+ severityAdjustment = 0f;
+ return;
+ }
+
+ // 获取CompHighSpeedCollision组件
+ var collisionComp = Pawn.GetComp();
+ if (collisionComp == null)
+ {
+ currentBlockSeverity = 0f;
+ severityAdjustment = 0f;
+ return;
+ }
+
+ // 获取当前阻挡严重度
+ float newSeverity = collisionComp.GetCurrentTerrainBlockSeverity();
+
+ // 立即设置阻挡严重度(移除平滑过渡)
+ currentBlockSeverity = newSeverity;
+
+ // 更新Hediff严重度(立即变化)
+ severityAdjustment = currentBlockSeverity - Pawn.health.hediffSet.GetFirstHediffOfDef(parent.def).Severity;
+
+ lastUpdateTick = Find.TickManager.TicksGame;
+ }
+
+ ///
+ /// 获取移动速度乘数
+ ///
+ public float GetMoveSpeedMultiplier()
+ {
+ if (currentBlockSeverity <= 0f)
+ return 1f;
+
+ // 应用严重度对应的速度惩罚(线性)
+ return 1f - currentBlockSeverity * Props.maxSpeedPenalty;
+ }
+
+ public override string CompTipStringExtra
+ {
+ get
+ {
+ if (currentBlockSeverity > 0.01f)
+ {
+ float speedMultiplier = GetMoveSpeedMultiplier();
+ float speedPenalty = (1f - speedMultiplier) * 100f;
+ return $"地形阻挡: {currentBlockSeverity:P0}\n移动速度: -{speedPenalty:F0}%";
+ }
+ return null;
+ }
+ }
+
+ public override void CompExposeData()
+ {
+ base.CompExposeData();
+ Scribe_Values.Look(ref currentBlockSeverity, "currentBlockSeverity", 0f);
+ Scribe_Values.Look(ref lastUpdateTick, "lastUpdateTick", -1);
+ }
+ }
+
+ ///
+ /// 地形阻挡Hediff组件属性
+ ///
+ public class HediffCompProperties_TerrainBlocked : HediffCompProperties
+ {
+ ///
+ /// 最大速度惩罚(0-1之间)
+ ///
+ public float maxSpeedPenalty = 0.5f;
+
+ ///
+ /// 检查间隔(ticks) - 降低判断频率
+ ///
+ public int checkIntervalTicks = 60;
+
+ public HediffCompProperties_TerrainBlocked()
+ {
+ compClass = typeof(HediffComp_TerrainBlocked);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs b/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs
index 91ab5cce..fd80e26f 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs
@@ -36,7 +36,11 @@ namespace WulaFallenEmpire
// === 缓存 ===
private CellRect collisionAreaCache = default;
private int lastAreaRecalculationTick = -1;
-
+
+ // === 地形阻挡相关 ===
+ private float currentTerrainBlockSeverity = 0f;
+ private int lastTerrainCheckTick = -1;
+
public CompProperties_HighSpeedCollision Props => (CompProperties_HighSpeedCollision)props;
public override void PostSpawnSetup(bool respawningAfterLoad)
@@ -53,29 +57,169 @@ namespace WulaFallenEmpire
lastPosition = parent.Position;
lastPositionTick = Find.TickManager.TicksGame;
}
-
+
+
public override void CompTick()
{
base.CompTick();
-
+
if (!parent.Spawned || parent.Destroyed)
return;
-
+
Pawn pawn = parent as Pawn;
if (pawn == null || pawn.Dead || pawn.Downed)
- return;
-
- // 检查是否死亡或不能移动
- if (!CanMove(pawn))
{
ResetToStage0();
return;
}
-
+
// 每帧更新
ProcessFrame(pawn);
+
+ // 地形阻挡检查(降低频率)
+ if (Props.narrowTerrainBlocked &&
+ (Find.TickManager.TicksGame - lastTerrainCheckTick >= Props.terrainCheckInterval))
+ {
+ UpdateTerrainBlockStatus(pawn);
+ lastTerrainCheckTick = Find.TickManager.TicksGame;
+ }
}
-
+ ///
+ /// 更新地形阻挡状态
+ ///
+ private void UpdateTerrainBlockStatus(Pawn pawn)
+ {
+ if (!Props.narrowTerrainBlocked || Props.maxBlockPenalty <= 0f)
+ {
+ currentTerrainBlockSeverity = 0f;
+ UpdateBlockedHediff(pawn, 0f);
+ return;
+ }
+ // 获取碰撞区域
+ CellRect collisionArea = GetCollisionArea(pawn);
+ // 统计空闲格子和被占据格子
+ int totalCells = 0;
+ int occupiedCells = 0;
+ foreach (IntVec3 cell in collisionArea)
+ {
+ if (!cell.InBounds(pawn.Map))
+ continue;
+ totalCells++;
+ // 检查是否被不可通行建筑占据
+ if (IsCellBlockedByImpassable(cell, pawn.Map))
+ {
+ occupiedCells++;
+ }
+ }
+ // 计算阻挡严重度
+ float blockSeverity = CalculateBlockSeverity(totalCells, occupiedCells);
+ // 立即设置阻挡严重度(移除平滑过渡)
+ currentTerrainBlockSeverity = blockSeverity;
+ // 更新Hediff
+ UpdateBlockedHediff(pawn, currentTerrainBlockSeverity);
+ // 调试日志
+ if (Props.enableDebugLogging && currentTerrainBlockSeverity > 0.01f)
+ {
+ Log.Message($"[HighSpeedCollision] Terrain Block: {pawn.Label}, " +
+ $"Occupied: {occupiedCells}/{totalCells}, " +
+ $"Severity: {currentTerrainBlockSeverity:P0}");
+ }
+ }
+
+ ///
+ /// 检查单元格是否被不可通行建筑占据
+ ///
+ private bool IsCellBlockedByImpassable(IntVec3 cell, Map map)
+ {
+ // 获取单元格内的所有建筑
+ var things = cell.GetThingList(map);
+ foreach (var thing in things)
+ {
+ if (thing is Building building)
+ {
+ // 检查是否可通行
+ if (building.def.passability == Traversability.Impassable)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// 计算阻挡严重度
+ ///
+ private float CalculateBlockSeverity(int totalCells, int occupiedCells)
+ {
+ if (totalCells == 0 || occupiedCells == 0)
+ return 0f;
+
+ int freeCells = totalCells - occupiedCells;
+ float freeRatio = (float)freeCells / totalCells;
+
+ // 使用公式:(1 - maxBlockPenalty) + maxBlockPenalty * (空闲格子/(空闲格子+被占据格子))
+ // 简化后:1 - maxBlockPenalty + maxBlockPenalty * (freeCells / totalCells)
+ // 但实际上,我们应该计算减速比例,然后转换为严重度
+ float speedMultiplier = (1f - Props.maxBlockPenalty) +
+ Props.maxBlockPenalty * (freeRatio);
+
+ // 严重度 = 1 - 速度乘数
+ return 1f - speedMultiplier;
+ }
+
+ ///
+ /// 平滑过渡
+ ///
+ private float SmoothTransition(float current, float target, float speed)
+ {
+ if (Mathf.Abs(current - target) < 0.01f)
+ return target;
+
+ return Mathf.Lerp(current, target, speed);
+ }
+
+ ///
+ /// 更新阻挡Hediff
+ ///
+ private void UpdateBlockedHediff(Pawn pawn, float severity)
+ {
+ if (Props.blockedHediff == null)
+ return;
+
+ // 获取或添加Hediff
+ Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.blockedHediff);
+
+ if (severity <= 0.01f)
+ {
+ // 移除Hediff
+ if (hediff != null)
+ {
+ pawn.health.RemoveHediff(hediff);
+ }
+ return;
+ }
+
+ // 添加或更新Hediff
+ if (hediff == null)
+ {
+ hediff = HediffMaker.MakeHediff(Props.blockedHediff, pawn);
+ pawn.health.AddHediff(hediff);
+ }
+
+ // 更新严重度
+ hediff.Severity = severity;
+ }
+
+ ///
+ /// 获取当前地形阻挡严重度(供HediffComp使用)
+ ///
+ public float GetCurrentTerrainBlockSeverity()
+ {
+ return currentTerrainBlockSeverity;
+ }
+
///
/// 处理每帧逻辑
///
@@ -846,7 +990,28 @@ namespace WulaFallenEmpire
/// 绘制速度历史图
///
public bool debugDrawSpeedHistory = false;
-
+
+ // === 狭窄地形阻挡配置 ===
+ ///
+ /// 是否启用狭窄地形阻挡
+ ///
+ public bool narrowTerrainBlocked = false;
+
+ ///
+ /// 最高阻挡减益值(0-1之间)
+ ///
+ public float maxBlockPenalty = 0.5f;
+
+ ///
+ /// 地形检查间隔(ticks)
+ ///
+ public int terrainCheckInterval = 60;
+
+ ///
+ /// 阻挡减益Hediff定义
+ ///
+ public HediffDef blockedHediff;
+
public CompProperties_HighSpeedCollision()
{
compClass = typeof(CompHighSpeedCollision);
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs b/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs
index cb2077b4..ee05d3b1 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs
@@ -48,9 +48,9 @@ namespace WulaFallenEmpire
private int lastAttackTargetTick;
// 集中火力目标
- private static LocalTargetInfo focusTarget = LocalTargetInfo.Invalid;
- private static int lastFocusSetTick = 0;
- private static Thing lastFocusPawn = null;
+ public static LocalTargetInfo focusTarget = LocalTargetInfo.Invalid;
+ public static int lastFocusSetTick = 0;
+ public static Thing lastFocusPawn = null;
// Gizmo 缓存
private Command_Toggle cachedGizmo;
@@ -278,8 +278,8 @@ namespace WulaFallenEmpire
}
}
}
-
- private void TryAcquireTarget()
+
+ public void TryAcquireTarget()
{
// 1. 首先检查是否有集中火力目标且可以对其开火
if (focusTarget.IsValid && focusTarget.Thing != null && focusTarget.Thing.Spawned)
@@ -690,7 +690,7 @@ namespace WulaFallenEmpire
if (IsMasterTurret)
{
// 如果有集中火力目标,添加清除按钮
- if (focusTarget.IsValid && lastFocusPawn == parent)
+ if (focusTarget.IsValid && focusTarget != null && lastFocusPawn == parent)
{
cachedFocusGizmo.defaultLabel = "Wula_ClearFocus".Translate();
cachedFocusGizmo.defaultDesc = "Wula_ClearFocusDesc".Translate();
@@ -713,7 +713,7 @@ namespace WulaFallenEmpire
private void ShowTargetSelectMenu()
{
// 如果已经有集中火力目标,清除它
- if (focusTarget.IsValid && lastFocusPawn == parent)
+ if (focusTarget.IsValid && focusTarget != null && lastFocusPawn == parent)
{
focusTarget = LocalTargetInfo.Invalid;
return;
diff --git a/Source/WulaFallenEmpire/Verb/Verb_RangeChecker.cs b/Source/WulaFallenEmpire/Verb/Verb_RangeChecker.cs
new file mode 100644
index 00000000..a9632de3
--- /dev/null
+++ b/Source/WulaFallenEmpire/Verb/Verb_RangeChecker.cs
@@ -0,0 +1,237 @@
+// 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;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index 8f87a12f..c32753b3 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -97,6 +97,7 @@
+
@@ -105,6 +106,7 @@
+