This commit is contained in:
2026-02-26 12:00:12 +08:00
parent 991c746005
commit 9cebf0ed6a
4 changed files with 645 additions and 34 deletions

View File

@@ -194,7 +194,7 @@
<maskPath>Wula/Things/WULA_Cat/AllegianceOverlays/None</maskPath>
<shaderType>CutoutWithOverlay</shaderType>
<graphicClass>Graphic_Multi</graphicClass>
<drawSize>7</drawSize>
<drawSize>9</drawSize>
<shadowData>
<volume>(1.4, 1.8, 1.4)</volume>
</shadowData>
@@ -231,7 +231,7 @@
<maskPath>Wula/Things/WULA_Cat/AllegianceOverlays/None</maskPath>
<shaderType>CutoutWithOverlay</shaderType>
<graphicClass>Graphic_Multi</graphicClass>
<drawSize>7</drawSize>
<drawSize>9</drawSize>
<shadowData>
<volume>(1.4, 1.8, 1.4)</volume>
</shadowData>
@@ -261,7 +261,7 @@
<maskPath>Wula/Things/WULA_Cat/AllegianceOverlays/None</maskPath>
<shaderType>CutoutWithOverlay</shaderType>
<graphicClass>Graphic_Multi</graphicClass>
<drawSize>5</drawSize>
<drawSize>9</drawSize>
<shadowData>
<volume>(1.4, 1.8, 1.4)</volume>
</shadowData>
@@ -270,7 +270,6 @@
</lifeStages>
<controlGroupPortraitZoom>0.7</controlGroupPortraitZoom>
</PawnKindDef>
<PawnKindDef ParentName="HeavyMechanoidKind">
<defName>Wula_Mech_Mobile_Factory</defName> <!-- 修改了defName以避免冲突 -->
<label>MFm-2"陆行舰"</label>
@@ -297,7 +296,7 @@
<maskPath>Wula/Things/WULA_Cat/AllegianceOverlays/None</maskPath>
<shaderType>CutoutWithOverlay</shaderType>
<graphicClass>Graphic_Multi</graphicClass>
<drawSize>9</drawSize>
<drawSize>12</drawSize>
<shadowData>
<volume>(1.4, 1.8, 1.4)</volume>
</shadowData>

View File

@@ -116,13 +116,18 @@
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
<ID>0</ID>
<turretDef>Wula_AI_Heavy_Panzer_Turret_Weapon</turretDef>
<traverseSpeed>20</traverseSpeed>
<aimTicks>0</aimTicks>
<idleRotationSpeed>5</idleRotationSpeed>
<smoothRotation>true</smoothRotation>
<resetCooldownTicks>180</resetCooldownTicks>
<!-- <angleOffset>-90</angleOffset> -->
<renderNodeProperties>
<li>
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
<parentTagDef>Body</parentTagDef>
<overrideMeshSize>(7, 7)</overrideMeshSize>
<overrideMeshSize>(8, 8)</overrideMeshSize>
<baseLayer>20</baseLayer>
<pawnType>Any</pawnType>
<drawData>
@@ -300,48 +305,48 @@
</pawnKindHediffs>
</li> -->
<!-- <li Class="WulaFallenEmpire.CompProperties_HighSpeedCollision">
速度阈值
<minSpeedForStage1>4.0</minSpeedForStage1>
<minSpeedForStage2>8.0</minSpeedForStage2>
<li Class="WulaFallenEmpire.CompProperties_HighSpeedCollision">
<!-- 速度阈值 -->
<minSpeedForStage1>1.0</minSpeedForStage1>
<minSpeedForStage2>2.0</minSpeedForStage2>
<speedHistoryFrameCount>15</speedHistoryFrameCount>
<stageTransitionCooldownTicks>3</stageTransitionCooldownTicks>
碰撞区域
<collisionAreaRadius>2</collisionAreaRadius>
<!-- 碰撞区域 -->
<collisionAreaRadius>3</collisionAreaRadius>
目标过滤
<!-- 目标过滤 -->
<onlyAffectEnemies>true</onlyAffectEnemies>
<excludeAlliedPawns>true</excludeAlliedPawns>
阶段1效果
<!-- 阶段1效果 -->
<stage1DamageDef>Blunt</stage1DamageDef>
<stage1DamageAmount>8</stage1DamageAmount>
<stage1DamageAmount>1</stage1DamageAmount>
<armorPenetration>0.1</armorPenetration>
<stage1Hediff>Bruise</stage1Hediff>
<!-- <stage1Hediff>Bruise</stage1Hediff>
<stage1HediffDurationTicks>120</stage1HediffDurationTicks>
<stage1HediffPreventsDamage>true</stage1HediffPreventsDamage>
<stage1Effecter>SparkImpact</stage1Effecter>
<stage1Sound>MeleeHit_Punch</stage1Sound>
<stage1HediffPreventsDamage>true</stage1HediffPreventsDamage> -->
<!-- <stage1Effecter>SparkImpact</stage1Effecter> -->
<stage1Sound>MeleeHit_BladelinkZeusHammer</stage1Sound>
阶段2效果
<!-- 阶段2效果 -->
<stage2DamageDef>Blunt</stage2DamageDef>
<stage2DamageAmount>15</stage2DamageAmount>
<stage2KnockbackDistance>4</stage2KnockbackDistance>
<requireLineOfSightForKnockback>true</requireLineOfSightForKnockback>
<stage2Effecter>ExplosionFlash</stage2Effecter>
<stage2Sound>MeleeHit_Slash</stage2Sound>
<!-- <stage2Effecter>ExplosionFlash</stage2Effecter> -->
<stage2Sound>MeleeHit_BladelinkZeusHammer</stage2Sound>
击飞配置
<!-- 击飞配置 -->
<knockbackFlyerDef>PawnFlyer</knockbackFlyerDef>
<flightEffecterDef>FlyerTakeoff</flightEffecterDef>
<!-- <flightEffecterDef>FlyerTakeoff</flightEffecterDef> -->
<landingSound>PawnFlyerLand</landingSound>
调试
<!-- 调试 -->
<enableDebugLogging>false</enableDebugLogging>
<enableDebugVisuals>false</enableDebugVisuals>
<debugDrawSpeedHistory>false</debugDrawSpeedHistory>
</li> -->
</li>
</comps>
</ThingDef>
<ThingDef ParentName="Wula_MechunitBase">
@@ -394,13 +399,19 @@
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
<ID>0</ID>
<turretDef>Wula_AI_Rocket_Panzer_Turret_Weapon</turretDef>
<traverseSpeed>20</traverseSpeed>
<aimTicks>30</aimTicks>
<idleRotationSpeed>8</idleRotationSpeed>
<smoothRotation>true</smoothRotation>
<resetCooldownTicks>180</resetCooldownTicks>
<!-- <angleOffset>-90</angleOffset> -->
<!-- <angleOffset>-90</angleOffset> -->
<renderNodeProperties>
<li>
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
<parentTagDef>Body</parentTagDef>
<overrideMeshSize>(7, 7)</overrideMeshSize>
<overrideMeshSize>(8, 8)</overrideMeshSize>
<baseLayer>20</baseLayer>
<pawnType>Any</pawnType>
<drawData>
@@ -1232,6 +1243,48 @@
</li>
</pawnKindHediffs>
</li> -->
<li Class="WulaFallenEmpire.CompProperties_HighSpeedCollision">
<!-- 速度阈值 -->
<minSpeedForStage1>0.5</minSpeedForStage1>
<minSpeedForStage2>1</minSpeedForStage2>
<speedHistoryFrameCount>15</speedHistoryFrameCount>
<stageTransitionCooldownTicks>3</stageTransitionCooldownTicks>
<!-- 碰撞区域 -->
<collisionAreaRadius>5</collisionAreaRadius>
<!-- 目标过滤 -->
<onlyAffectEnemies>true</onlyAffectEnemies>
<excludeAlliedPawns>true</excludeAlliedPawns>
<!-- 阶段1效果 -->
<stage1DamageDef>Blunt</stage1DamageDef>
<stage1DamageAmount>5</stage1DamageAmount>
<armorPenetration>0.1</armorPenetration>
<!-- <stage1Hediff>Bruise</stage1Hediff>
<stage1HediffDurationTicks>120</stage1HediffDurationTicks>
<stage1HediffPreventsDamage>true</stage1HediffPreventsDamage> -->
<!-- <stage1Effecter>SparkImpact</stage1Effecter> -->
<stage1Sound>MeleeHit_BladelinkZeusHammer</stage1Sound>
<!-- 阶段2效果 -->
<stage2DamageDef>Blunt</stage2DamageDef>
<stage2DamageAmount>50</stage2DamageAmount>
<stage2KnockbackDistance>8</stage2KnockbackDistance>
<requireLineOfSightForKnockback>true</requireLineOfSightForKnockback>
<!-- <stage2Effecter>ExplosionFlash</stage2Effecter> -->
<stage2Sound>MeleeHit_BladelinkZeusHammer</stage2Sound>
<!-- 击飞配置 -->
<knockbackFlyerDef>PawnFlyer</knockbackFlyerDef>
<!-- <flightEffecterDef>FlyerTakeoff</flightEffecterDef> -->
<landingSound>PawnFlyerLand</landingSound>
<!-- 调试 -->
<enableDebugLogging>false</enableDebugLogging>
<enableDebugVisuals>false</enableDebugVisuals>
<debugDrawSpeedHistory>false</debugDrawSpeedHistory>
</li>
</comps>
</ThingDef>
</Defs>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Verse;
using Verse.AI;
@@ -10,29 +10,480 @@ namespace WulaFallenEmpire
public class CompProperties_MultiTurretGun : CompProperties_TurretGun
{
public int ID;
public float traverseSpeed = 30f; // 旋转速度(度/秒默认30度/秒
public float aimTicks = 15; // 瞄准所需tick数
public float idleRotationSpeed = 5f; // 空闲时的旋转速度(度/秒)
public bool smoothRotation = true; // 是否启用平滑旋转
public float minAimAngle = 10f; // 开始预热所需的最小瞄准角度差(度)
public int resetCooldownTicks = 120; // 开火后的复位冷却时间默认2秒
public CompProperties_MultiTurretGun()
{
compClass = typeof(Comp_MultiTurretGun);
}
}
public class Comp_MultiTurretGun : CompTurretGun
{
private bool fireAtWill = true;
private float currentRotationAngle; // 当前实际旋转角度
private float targetRotationAngle; // 目标旋转角度
private float rotationVelocity; // 旋转速度(用于平滑插值)
private int ticksWithoutTarget = 0; // 没有目标的tick计数
private bool isIdleRotating = false; // 是否处于空闲旋转状态
private float idleRotationDirection = 1f; // 空闲旋转方向
private bool isAiming = false; // 是否正在瞄准
private float lastBaseRotationAngle; // 上一次记录的基座角度
private float lastTargetAngle; // 最后一次目标角度
// 添加缺失的字段
private LocalTargetInfo lastAttackedTarget = LocalTargetInfo.Invalid;
private int lastAttackTargetTick;
// Gizmo相关静态字段
private static readonly CachedTexture ToggleTurretIcon = new CachedTexture("UI/Gizmos/ToggleTurret");
private static bool gizmoAdded = false; // 防止重复添加Gizmo
// 复位冷却相关
private int resetCooldownTicksLeft = 0;
private bool isInResetCooldown = false;
public new CompProperties_MultiTurretGun Props => (CompProperties_MultiTurretGun)props;
// 添加属性
private bool WarmingUp => burstWarmupTicksLeft > 0;
public override void Initialize(CompProperties props)
{
base.Initialize(props);
// 初始化旋转角度为建筑方向
currentRotationAngle = parent.Rotation.AsAngle + Props.angleOffset;
targetRotationAngle = currentRotationAngle;
lastBaseRotationAngle = parent.Rotation.AsAngle;
lastTargetAngle = currentRotationAngle;
}
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
if (!respawningAfterLoad)
{
currentRotationAngle = parent.Rotation.AsAngle + Props.angleOffset;
targetRotationAngle = currentRotationAngle;
lastBaseRotationAngle = parent.Rotation.AsAngle;
lastTargetAngle = currentRotationAngle;
}
gizmoAdded = false; // 重置Gizmo状态
}
private bool CanShoot
{
get
{
if (parent is Pawn pawn)
{
if (!pawn.Spawned || pawn.Downed || pawn.Dead || !pawn.Awake())
{
return false;
}
if (pawn.stances.stunner.Stunned)
{
return false;
}
if (TurretDestroyed)
{
return false;
}
if (pawn.IsColonyMechPlayerControlled && !fireAtWill)
{
return false;
}
}
CompCanBeDormant compCanBeDormant = parent.TryGetComp<CompCanBeDormant>();
if (compCanBeDormant != null && !compCanBeDormant.Awake)
{
return false;
}
return true;
}
}
public override void CompTick()
{
base.CompTick();
if (!currentTarget.IsValid && burstCooldownTicksLeft <= 0)
if (!CanShoot)
{
ResetCurrentTarget();
return;
}
// 检查Pawn是否转向
CheckPawnRotationChange();
// 更新炮塔旋转(必须在目标检查之前)
UpdateTurretRotation();
// 处理VerbTick
AttackVerb.VerbTick();
if (AttackVerb.state == VerbState.Bursting)
{
return;
}
// 更新复位冷却
UpdateResetCooldown();
// 如果正在预热
if (WarmingUp)
{
// 检查是否仍然瞄准目标
if (currentTarget.IsValid && IsAimingAtTarget())
{
burstWarmupTicksLeft--;
if (burstWarmupTicksLeft == 0)
{
// 确保炮塔已经瞄准目标
if (IsAimedAtTarget())
{
AttackVerb.TryStartCastOn(currentTarget, surpriseAttack: false, canHitNonTargetPawns: true, preventFriendlyFire: false, nonInterruptingSelfCast: true);
lastAttackTargetTick = Find.TickManager.TicksGame;
lastAttackedTarget = currentTarget;
// 开火后重置目标,并启动复位冷却
ResetCurrentTarget();
StartResetCooldown();
}
else
{
// 如果没有瞄准,重置预热
burstWarmupTicksLeft = 1;
}
}
}
else
{
// 失去目标或失去瞄准,重置预热
ResetCurrentTarget();
}
return;
}
// 冷却中
if (burstCooldownTicksLeft > 0)
{
burstCooldownTicksLeft--;
}
// 冷却结束且复位冷却结束,尝试寻找目标
if (burstCooldownTicksLeft <= 0 && !isInResetCooldown && parent.IsHashIntervalTick(10))
{
TryAcquireTarget();
}
// 更新空闲旋转
UpdateIdleRotation();
}
private void UpdateResetCooldown()
{
if (isInResetCooldown && resetCooldownTicksLeft > 0)
{
resetCooldownTicksLeft--;
if (resetCooldownTicksLeft <= 0)
{
isInResetCooldown = false;
resetCooldownTicksLeft = 0;
}
}
}
private void StartResetCooldown()
{
resetCooldownTicksLeft = Props.resetCooldownTicks;
isInResetCooldown = true;
ticksWithoutTarget = 0; // 重置无目标计数
}
private void CheckPawnRotationChange()
{
// 如果父物体是Pawn检查其朝向是否改变
if (parent is Pawn pawn)
{
float currentBaseRotation = pawn.Rotation.AsAngle;
// 如果朝向改变超过5度立即更新基座方向
if (Mathf.Abs(Mathf.DeltaAngle(currentBaseRotation, lastBaseRotationAngle)) > 5f)
{
// 立即调整炮塔角度跟上Pawn的转向
currentRotationAngle += Mathf.DeltaAngle(lastBaseRotationAngle, currentBaseRotation);
targetRotationAngle = currentRotationAngle;
lastBaseRotationAngle = currentBaseRotation;
// 如果有目标,重新计算目标角度
if (currentTarget.IsValid)
{
Vector3 targetPos = currentTarget.CenterVector3;
Vector3 turretPos = parent.DrawPos;
targetRotationAngle = (targetPos - turretPos).AngleFlat();
}
}
}
}
private void TryAcquireTarget()
{
// 如果正在复位冷却中,不寻找目标
if (isInResetCooldown)
return;
// 尝试寻找新目标
LocalTargetInfo newTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(
this,
TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable
);
if (newTarget.IsValid)
{
// 如果已经有目标并且是同一个目标,保持当前状态
if (currentTarget.IsValid && currentTarget.Thing == newTarget.Thing)
{
// 检查是否已经瞄准目标
if (IsAimedAtTarget())
{
// 如果已经瞄准,开始预热
if (burstWarmupTicksLeft <= 0)
{
burstWarmupTicksLeft = Mathf.Max(1, Mathf.RoundToInt(Props.aimTicks));
}
}
else if (IsAimingAtTarget())
{
// 如果正在瞄准但未完成,保持当前状态
// 什么也不做,继续旋转
}
else
{
// 需要重新瞄准
burstWarmupTicksLeft = 0;
}
}
else
{
// 新目标,重置状态
currentTarget = newTarget;
burstWarmupTicksLeft = 0;
isAiming = true;
// 计算目标角度
Vector3 targetPos = currentTarget.CenterVector3;
Vector3 turretPos = parent.DrawPos;
targetRotationAngle = (targetPos - turretPos).AngleFlat();
lastTargetAngle = targetRotationAngle;
}
}
else
{
// 没有目标
ResetCurrentTarget();
}
}
private bool IsAimingAtTarget()
{
if (!currentTarget.IsValid)
return false;
// 计算当前角度与目标角度的差值
float angleDiff = Mathf.Abs(Mathf.DeltaAngle(currentRotationAngle, targetRotationAngle));
// 如果角度差小于最小瞄准角度,认为正在瞄准
return angleDiff <= Props.minAimAngle;
}
private bool IsAimedAtTarget()
{
if (!currentTarget.IsValid)
return false;
// 计算当前角度与目标角度的差值
float angleDiff = Mathf.Abs(Mathf.DeltaAngle(currentRotationAngle, targetRotationAngle));
// 如果角度差小于2度认为已经瞄准
return angleDiff <= 2f;
}
private void UpdateTurretRotation()
{
if (!Props.smoothRotation)
{
// 非平滑旋转:直接设置角度
if (currentTarget.IsValid)
{
Vector3 targetPos = currentTarget.CenterVector3;
Vector3 turretPos = parent.DrawPos;
curRotation = (targetPos - turretPos).AngleFlat() + Props.angleOffset;
}
else
{
// 在其他情况下没有目标且冷却结束时也回正
curRotation = parent.Rotation.AsAngle + Props.angleOffset;
}
return;
}
// 平滑旋转逻辑
if (currentTarget.IsValid)
{
// 有目标时,计算朝向目标的角度
Vector3 targetPos = currentTarget.CenterVector3;
Vector3 turretPos = parent.DrawPos;
targetRotationAngle = (targetPos - turretPos).AngleFlat();
ticksWithoutTarget = 0;
isIdleRotating = false;
lastTargetAngle = targetRotationAngle;
}
else
{
// 没有目标时,朝向初始角度
targetRotationAngle = parent.Rotation.AsAngle + Props.angleOffset;
ticksWithoutTarget++;
lastTargetAngle = targetRotationAngle;
}
// 确保角度在0-360范围内
targetRotationAngle = targetRotationAngle % 360f;
if (targetRotationAngle < 0f)
targetRotationAngle += 360f;
// 计算角度差使用DeltaAngle处理360度循环
float angleDiff = Mathf.DeltaAngle(currentRotationAngle, targetRotationAngle);
// 如果角度差很小,直接设置到目标角度
if (Mathf.Abs(angleDiff) < 0.1f)
{
currentRotationAngle = targetRotationAngle;
curRotation = currentRotationAngle;
return;
}
// 计算最大旋转速度(度/秒)
float maxRotationSpeed = Props.traverseSpeed;
// 如果有目标且在预热,根据预热进度调整旋转速度
if (currentTarget.IsValid && burstWarmupTicksLeft > 0)
{
float warmupProgress = 1f - (float)burstWarmupTicksLeft / (float)Math.Max(Props.aimTicks, 1f);
// 预热初期快速旋转,接近完成时减速
if (warmupProgress < 0.3f)
{
maxRotationSpeed *= 1.8f; // 初期更快
}
else if (warmupProgress > 0.7f)
{
maxRotationSpeed *= 0.5f; // 后期更慢,精确瞄准
}
}
// 转换为每tick的旋转速度
float maxRotationPerTick = maxRotationSpeed / 60f;
// 根据角度差调整旋转速度
float rotationSpeedMultiplier = Mathf.Clamp(Mathf.Abs(angleDiff) / 45f, 0.5f, 1.5f);
maxRotationPerTick *= rotationSpeedMultiplier;
// 计算这一帧应该旋转的角度
float rotationThisTick = Mathf.Clamp(angleDiff, -maxRotationPerTick, maxRotationPerTick);
// 应用旋转
currentRotationAngle += rotationThisTick;
// 确保角度在0-360范围内
currentRotationAngle = currentRotationAngle % 360f;
if (currentRotationAngle < 0f)
currentRotationAngle += 360f;
// 更新基类的curRotation
curRotation = currentRotationAngle;
}
private void UpdateIdleRotation()
{
// 只在没有目标、冷却结束且复位冷却结束时执行空闲旋转
if (!currentTarget.IsValid && burstCooldownTicksLeft <= 0 && !isInResetCooldown && ticksWithoutTarget > 120)
{
if (!isIdleRotating)
{
isIdleRotating = true;
idleRotationDirection = Rand.Value > 0.5f ? 1f : -1f;
}
// 缓慢旋转
float idleRotationPerTick = Props.idleRotationSpeed / 60f * idleRotationDirection;
currentRotationAngle += idleRotationPerTick;
// 确保角度在0-360范围内
currentRotationAngle = currentRotationAngle % 360f;
if (currentRotationAngle < 0f)
currentRotationAngle += 360f;
// 更新基类的curRotation
curRotation = currentRotationAngle;
// 每30tick随机可能改变方向
if (Find.TickManager.TicksGame % 30 == 0 && Rand.Value < 0.1f)
{
idleRotationDirection *= -1f;
}
}
else
{
isIdleRotating = false;
}
}
private void ResetCurrentTarget()
{
currentTarget = LocalTargetInfo.Invalid;
burstWarmupTicksLeft = 0;
isAiming = false;
}
public override void PostDraw()
{
base.PostDraw();
// 如果有目标且正在预热,绘制瞄准线
if (currentTarget.IsValid && burstWarmupTicksLeft > 0)
{
DrawTargetingLine();
}
}
private void DrawTargetingLine()
{
Vector3 lineStart = parent.DrawPos;
lineStart.y = AltitudeLayer.MetaOverlays.AltitudeFor();
Vector3 lineEnd = currentTarget.CenterVector3;
lineEnd.y = AltitudeLayer.MetaOverlays.AltitudeFor();
// 计算瞄准精度
float aimAccuracy = 1f - Mathf.Abs(Mathf.DeltaAngle(currentRotationAngle, targetRotationAngle)) / 45f;
aimAccuracy = Mathf.Clamp01(aimAccuracy);
// 根据瞄准精度改变线条颜色
Color lineColor = Color.Lerp(Color.yellow, Color.red, aimAccuracy);
lineColor.a = 0.7f;
GenDraw.DrawLineBetween(lineStart, lineEnd);
}
private void MakeGun()
{
gun = ThingMaker.MakeThing(Props.turretDef);
UpdateGunVerbs();
}
private void UpdateGunVerbs()
{
List<Verb> allVerbs = gun.TryGetComp<CompEquippable>().AllVerbs;
@@ -46,13 +497,106 @@ namespace WulaFallenEmpire
};
}
}
// 添加Gizmo方法
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (Gizmo gizmo in base.CompGetGizmosExtra())
{
yield return gizmo;
}
// 只让第一个Comp_MultiTurretGun组件生成Gizmo
if (parent is Pawn pawn && pawn.IsColonyMechPlayerControlled)
{
// 获取所有Comp_MultiTurretGun组件
var allTurretComps = parent.GetComps<Comp_MultiTurretGun>();
// 检查当前组件是否是第一个
if (!gizmoAdded)
{
gizmoAdded = true;
// 检查所有炮塔是否都有相同的fireAtWill状态
bool allTurretsEnabled = true;
bool allTurretsDisabled = true;
foreach (var turretComp in allTurretComps)
{
if (turretComp.fireAtWill)
allTurretsDisabled = false;
else
allTurretsEnabled = false;
}
// 确定Gizmo的初始状态
bool mixedState = !(allTurretsEnabled || allTurretsDisabled);
Command_Toggle command = new Command_Toggle();
command.defaultLabel = "CommandToggleTurret".Translate();
command.defaultDesc = "CommandToggleTurretDesc".Translate();
command.icon = ToggleTurretIcon.Texture;
command.isActive = () =>
{
// 如果有混合状态显示为false但使用特殊图标
if (mixedState)
return false;
return allTurretsEnabled;
};
command.toggleAction = () =>
{
// 切换所有炮塔的状态
bool newState = !allTurretsEnabled;
foreach (var turretComp in allTurretComps)
{
turretComp.fireAtWill = newState;
// 如果关闭炮塔,重置当前目标
if (!newState)
{
turretComp.ResetCurrentTarget();
}
}
};
// 如果有混合状态,显示特殊图标
if (mixedState)
{
command.icon = ContentFinder<Texture2D>.Get("UI/Commands/MixedState");
}
yield return command;
}
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref burstCooldownTicksLeft, "burstCooldownTicksLeft", 0);
Scribe_Values.Look(ref burstWarmupTicksLeft, "burstWarmupTicksLeft", 0);
Scribe_TargetInfo.Look(ref currentTarget, "currentTarget_" + Props.ID);
Scribe_Deep.Look(ref gun, "gun_" + Props.ID);
Scribe_Values.Look(ref fireAtWill, "fireAtWill", defaultValue: true);
Scribe_Values.Look(ref currentRotationAngle, "currentRotationAngle", 0f);
Scribe_Values.Look(ref targetRotationAngle, "targetRotationAngle", 0f);
Scribe_Values.Look(ref rotationVelocity, "rotationVelocity", 0f);
Scribe_Values.Look(ref ticksWithoutTarget, "ticksWithoutTarget", 0);
Scribe_Values.Look(ref isIdleRotating, "isIdleRotating", false);
Scribe_Values.Look(ref idleRotationDirection, "idleRotationDirection", 1f);
Scribe_Values.Look(ref isAiming, "isAiming", false);
Scribe_Values.Look(ref lastBaseRotationAngle, "lastBaseRotationAngle", 0f);
Scribe_Values.Look(ref lastTargetAngle, "lastTargetAngle", 0f);
// 保存缺失的字段
Scribe_TargetInfo.Look(ref lastAttackedTarget, "lastAttackedTarget_" + Props.ID);
Scribe_Values.Look(ref lastAttackTargetTick, "lastAttackTargetTick_" + Props.ID, 0);
// 保存复位冷却相关字段
Scribe_Values.Look(ref resetCooldownTicksLeft, "resetCooldownTicksLeft", 0);
Scribe_Values.Look(ref isInResetCooldown, "isInResetCooldown", false);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
if (gun == null)
@@ -63,8 +607,23 @@ namespace WulaFallenEmpire
{
UpdateGunVerbs();
}
// 确保旋转角度有效
if (currentRotationAngle == 0f)
{
currentRotationAngle = parent.Rotation.AsAngle + Props.angleOffset;
targetRotationAngle = currentRotationAngle;
lastBaseRotationAngle = parent.Rotation.AsAngle;
lastTargetAngle = currentRotationAngle;
}
}
}
// 如果需要实现 IAttackTargetSearcher 接口
public new Thing Thing => parent;
public new LocalTargetInfo LastAttackedTarget => lastAttackedTarget;
public new int LastAttackTargetTick => lastAttackTargetTick;
}
}