This commit is contained in:
2025-11-20 12:05:07 +08:00
parent 44bea4dbb8
commit cf82707c8f
12 changed files with 1069 additions and 208 deletions

View File

@@ -87,6 +87,200 @@ namespace WulaFallenEmpire
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (!TurretEnabled)
{
ResetCurrentTarget();
return;
}
if (!this.CanShoot)
{
return;
}
// 优先处理手动目标
if (HasManualTarget && CanAttackManualTarget)
{
LocalTargetInfo manualTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
this.currentTarget = manualTarget;
this.curRotation = (manualTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
}
else if (this.currentTarget.IsValid)
{
this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
}
this.AttackVerb.VerbTick();
if (this.AttackVerb.state != VerbState.Bursting)
{
if (this.WarmingUp)
{
this.burstWarmupTicksLeft--;
if (this.burstWarmupTicksLeft == 0)
{
bool attackSuccess = this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
if (attackSuccess)
{
this.lastAttackTargetTick = Find.TickManager.TicksGame;
this.lastAttackedTarget = this.currentTarget;
}
else
{
// 如果手动攻击失败且目标无效,清除手动目标
if (HasManualTarget && !CanAttackManualTarget)
{
VolleyTargetManager.ClearVolleyTarget(Pawn);
}
}
return;
}
}
else
{
if (this.burstCooldownTicksLeft > 0)
{
this.burstCooldownTicksLeft--;
}
if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
{
// 如果手动目标无效,清除它
if (HasManualTarget && !CanAttackManualTarget)
{
VolleyTargetManager.ClearVolleyTarget(Pawn);
}
// 只有在没有有效的手动目标时才寻找新目标
if (!HasManualTarget || !CanAttackManualTarget)
{
this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
if (this.currentTarget.IsValid)
{
this.burstWarmupTicksLeft = 1;
return;
}
}
this.ResetCurrentTarget();
}
}
}
}
// 检查是否有手动目标
private bool HasManualTarget
{
get
{
LocalTargetInfo manualTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
return manualTarget.IsValid;
}
}
// 检查是否可以攻击手动目标
private bool CanAttackManualTarget
{
get
{
LocalTargetInfo manualTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
if (!manualTarget.IsValid)
return false;
// 检查目标是否在射程内
float distance = Pawn.Position.DistanceTo(manualTarget.Cell);
if (distance > AttackVerb.verbProps.range)
return false;
// 检查是否可以命中目标
if (!AttackVerb.CanHitTarget(manualTarget))
return false;
// 检查目标是否还活着(如果是生物)
if (manualTarget.Thing is Pawn targetPawn && (targetPawn.Dead || targetPawn.Downed))
return false;
// 检查目标是否被摧毁(如果是建筑)
if (manualTarget.Thing != null && manualTarget.Thing.Destroyed)
return false;
return true;
}
}
// 简化的Gizmos - 只有设置目标和清除目标按钮
public override IEnumerable<Gizmo> CompGetGizmos()
{
// 只有 pawn 被选中且是玩家派系时才显示按钮
if (this.Pawn.Faction == Faction.OfPlayer && Find.Selector.IsSelected(this.Pawn))
{
// 原有开关按钮
yield return new Command_Toggle
{
defaultLabel = "CommandToggleTurret".Translate(),
defaultDesc = "CommandToggleTurretDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ToggleTurret"),
isActive = () => TurretEnabled,
toggleAction = () => TurretEnabled = !TurretEnabled,
hotKey = KeyBindingDefOf.Misc1
};
// 设置目标按钮
yield return new Command_Action
{
defaultLabel = "CommandSetTarget".Translate(),
defaultDesc = "CommandSetTargetDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/SetTarget"),
action = () =>
{
Find.Targeter.BeginTargeting(
CreateTargetingParameters(),
delegate (LocalTargetInfo target)
{
VolleyTargetManager.SetVolleyTarget(Pawn, target);
},
Pawn, // caster 参数
null, // actionWhenFinished
null, // mouseAttachment
true // requiresCastedSelected
);
},
hotKey = KeyBindingDefOf.Misc2
};
// 清除目标按钮(只在有手动目标时显示)
LocalTargetInfo currentTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
if (currentTarget.IsValid)
{
yield return new Command_Action
{
defaultLabel = "CommandClearTarget".Translate(),
defaultDesc = "CommandClearTargetDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ClearTarget"),
action = () => VolleyTargetManager.ClearVolleyTarget(Pawn),
hotKey = KeyBindingDefOf.Misc3
};
}
}
}
// 创建目标参数
private TargetingParameters CreateTargetingParameters()
{
return TargetingParameters.ForThing();
}
// 在提示中显示目标状态
public override string CompTipStringExtra
{
get
{
string baseString = base.CompTipStringExtra;
string turretStatus = TurretEnabled ? "Turret: Active" : "Turret: Inactive";
string targetStatus = "Manual Target: ";
LocalTargetInfo manualTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
if (manualTarget.IsValid)
{
targetStatus += $"{manualTarget.Thing?.LabelCap ?? manualTarget.Cell.ToString()}";
if (!CanAttackManualTarget)
{
targetStatus += " (Unreachable)";
}
}
else
{
targetStatus += "None";
}
string result = turretStatus + "\n" + targetStatus;
return string.IsNullOrEmpty(baseString) ? result : baseString + "\n" + result;
}
}
// 新增:炮塔启用状态
public bool TurretEnabled
{
@@ -190,60 +384,6 @@ namespace WulaFallenEmpire
};
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
// 新增:只在启用状态下执行攻击逻辑
if (!TurretEnabled)
{
ResetCurrentTarget();
return;
}
if (!this.CanShoot)
{
return;
}
if (this.currentTarget.IsValid)
{
this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
}
this.AttackVerb.VerbTick();
if (this.AttackVerb.state != VerbState.Bursting)
{
if (this.WarmingUp)
{
this.burstWarmupTicksLeft--;
if (this.burstWarmupTicksLeft == 0)
{
this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
this.lastAttackTargetTick = Find.TickManager.TicksGame;
this.lastAttackedTarget = this.currentTarget;
return;
}
}
else
{
if (this.burstCooldownTicksLeft > 0)
{
this.burstCooldownTicksLeft--;
}
if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
{
this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
if (this.currentTarget.IsValid)
{
this.burstWarmupTicksLeft = 1;
return;
}
this.ResetCurrentTarget();
}
}
}
}
private void ResetCurrentTarget()
{
this.currentTarget = LocalTargetInfo.Invalid;
@@ -273,35 +413,6 @@ namespace WulaFallenEmpire
}
}
// 新增:实现 Gizmo 接口
public override IEnumerable<Gizmo> CompGetGizmos()
{
// 只有 pawn 被选中且是玩家派系时才显示按钮
if (this.Pawn.Faction == Faction.OfPlayer && Find.Selector.IsSelected(this.Pawn))
{
yield return new Command_Toggle
{
defaultLabel = "CommandToggleTurret".Translate(),
defaultDesc = "CommandToggleTurretDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ToggleTurret"),
isActive = () => TurretEnabled,
toggleAction = () => TurretEnabled = !TurretEnabled,
hotKey = KeyBindingDefOf.Misc1
};
}
}
// 新增:在绘制时显示状态
public override string CompTipStringExtra
{
get
{
string baseString = base.CompTipStringExtra;
string status = TurretEnabled ? "Turret: Active" : "Turret: Inactive";
return string.IsNullOrEmpty(baseString) ? status : baseString + "\n" + status;
}
}
private const int StartShootIntervalTicks = 10;
private static readonly CachedTexture ToggleTurretIcon = new CachedTexture("UI/Gizmos/ToggleTurret");

View File

@@ -15,6 +15,8 @@ namespace WulaFallenEmpire
volleyTargets[pawn] = target;
volleyEnabled[pawn] = target.IsValid;
Log.Message($"Set volley target for {pawn.Label}: {target.Thing?.Label ?? target.Cell.ToString()}");
}
public static void ClearVolleyTarget(Pawn pawn)
@@ -23,6 +25,8 @@ namespace WulaFallenEmpire
volleyTargets.Remove(pawn);
volleyEnabled.Remove(pawn);
Log.Message($"Cleared volley target for {pawn.Label}");
}
public static LocalTargetInfo GetVolleyTarget(Pawn pawn)
@@ -48,11 +52,36 @@ namespace WulaFallenEmpire
bool current = IsVolleyEnabled(pawn);
volleyEnabled[pawn] = !current;
Log.Message($"Toggled volley for {pawn.Label}: {!current}");
// 如果禁用齐射,清除目标
if (!volleyEnabled[pawn])
{
ClearVolleyTarget(pawn);
}
}
// 新增:检查齐射目标是否仍然有效
public static bool IsVolleyTargetValid(Pawn pawn)
{
if (!IsVolleyEnabled(pawn))
return false;
LocalTargetInfo target = GetVolleyTarget(pawn);
if (!target.IsValid)
return false;
// 检查目标是否还活着/存在
if (target.Thing != null)
{
if (target.Thing.Destroyed)
return false;
if (target.Thing is Pawn targetPawn && (targetPawn.Dead || targetPawn.Downed))
return false;
}
return true;
}
}
}