diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 54e8aea..7cdd6ef 100644
Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ
diff --git a/1.6/1.6/Defs/AbilityDefs/Abilities_TrackingCharge.xml b/1.6/1.6/Defs/AbilityDefs/Abilities_TrackingCharge.xml
index b8db240..bd9904e 100644
--- a/1.6/1.6/Defs/AbilityDefs/Abilities_TrackingCharge.xml
+++ b/1.6/1.6/Defs/AbilityDefs/Abilities_TrackingCharge.xml
@@ -6,8 +6,8 @@
ARA_Flyer_TrackingCharge
ArachnaeSwarm.PawnFlyer_TrackingCharge
- 0.1
- 0.1
+ 0.5
+ 0
@@ -16,7 +16,7 @@
ARA_Ability_TrackingCharge
阿拉克涅盾头种对目标发起蓄势冲撞,对路径上的一切造成伤害。飞行的距离越远,伤害越高。
- UI/Abilities/Charge
+ UI/Commands/WarTrumpet
600
ArachnaeSwarm.Verb_CastAbilityTrackingCharge
@@ -36,8 +36,8 @@
1.5
15
2
- 4
- Crush
+ 6
+ Blunt
ARA_Flyer_TrackingCharge
diff --git a/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs
index d15706d..de8bea8 100644
--- a/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs
+++ b/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs
@@ -17,6 +17,7 @@ namespace ArachnaeSwarm
public float inertiaDistance;
public DamageDef collisionDamageDef;
public LocalTargetInfo primaryTarget;
+ public int maxFlightTicks;
// --- Internal state ---
private Vector3 currentSpeed;
@@ -24,6 +25,7 @@ namespace ArachnaeSwarm
private bool homing = true;
private int inertiaTicks = -1;
private Vector3 exactPosition;
+ private bool hasHitPrimaryTarget = false;
// --- Reflection Fields ---
private static FieldInfo TicksFlyingInfo;
@@ -112,8 +114,9 @@ namespace ArachnaeSwarm
float calculatedDamage = this.initialDamage + (this.distanceTraveled * this.damagePerTile);
var dinfo = new DamageInfo(this.collisionDamageDef, calculatedDamage, 1f, -1, this.FlyingPawn);
- if (homing && primaryTarget.HasThing && (this.exactPosition - primaryTarget.Thing.DrawPos).sqrMagnitude < 1.5f * 1.5f)
+ if (!hasHitPrimaryTarget && homing && primaryTarget.HasThing && primaryTarget.Thing.Spawned && (this.exactPosition - primaryTarget.Thing.DrawPos).sqrMagnitude < 1.5f * 1.5f)
{
+ hasHitPrimaryTarget = true; // Mark as hit to prevent re-triggering
primaryTarget.Thing.TakeDamage(dinfo);
homing = false;
this.inertiaTicks = (int)(this.inertiaDistance / this.currentSpeed.magnitude);
@@ -121,7 +124,9 @@ namespace ArachnaeSwarm
foreach (var thing in GenRadial.RadialDistinctThingsAround(this.exactPosition.ToIntVec3(), this.Map, 1.0f, false))
{
- if (thing == this.FlyingPawn || thing == this || thing == primaryTarget.Thing) continue;
+ // Avoid damaging self or the primary target (which is handled above)
+ if (thing == this.FlyingPawn || thing == this || (hasHitPrimaryTarget && thing == primaryTarget.Thing)) continue;
+
if (thing is Pawn pawn && !pawn.Downed && pawn.HostileTo(this.FlyingPawn)) pawn.TakeDamage(dinfo);
else if (thing.def.destroyable && thing.def.building != null) thing.TakeDamage(dinfo);
}
@@ -129,8 +134,10 @@ namespace ArachnaeSwarm
try
{
+ // We still need to update the destination for the base flyer logic to work correctly
DestCellInfo.SetValue(this, this.exactPosition.ToIntVec3());
- TicksFlightTimeInfo.SetValue(this, ticksFlying + 2);
+ // --- FIX for infinite flight ---
+ // The old TicksFlightTimeInfo update logic is removed.
}
catch (System.Exception ex)
{
@@ -138,9 +145,9 @@ namespace ArachnaeSwarm
}
TicksFlyingInfo.SetValue(this, ticksFlying + 1);
-
- int flightTime = (int)TicksFlightTimeInfo.GetValue(this);
- if (!this.exactPosition.ToIntVec3().InBounds(this.Map) || ticksFlying > flightTime * 2)
+
+ // --- RELIABLE TIMEOUT & BOUNDS CHECK ---
+ if (ticksFlying > this.maxFlightTicks || !this.exactPosition.ToIntVec3().InBounds(this.Map))
{
Land();
}
diff --git a/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs
index 0cb816c..71f2a6f 100644
--- a/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs
+++ b/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs
@@ -21,11 +21,21 @@ namespace ArachnaeSwarm
return false;
}
+ // --- Best Practice: Cache Map and Position FIRST ---
+ // Per MCP analysis, Caster.Map is the most reliable source.
+ // Cache this before ANY other logic.
+ Map map = this.Caster.Map;
+ if (map == null)
+ {
+ Log.Error($"Verb_CastAbilityTrackingCharge: Caster {this.Caster.LabelCap} has a null map. Cannot cast.");
+ return false;
+ }
+
if (this.CasterPawn == null || !this.CasterPawn.Spawned)
{
return false;
}
-
+
// --- This is now a fully custom Thing, so we spawn it directly ---
var trackingCharge = (PawnFlyer_TrackingCharge)ThingMaker.MakeThing(props.flyerDef);
@@ -37,9 +47,20 @@ namespace ArachnaeSwarm
trackingCharge.collisionDamageDef = props.collisionDamageDef;
trackingCharge.primaryTarget = this.currentTarget;
+ // --- Dynamic Timeout Calculation ---
+ float flightSpeed = props.flyerDef.pawnFlyer.flightSpeed;
+ if (flightSpeed <= 0)
+ {
+ Log.Error("flyerDef has no flightSpeed, cannot calculate timeout.");
+ return false;
+ }
+ // Timeout is twice the time it would take to fly the max range in a straight line
+ int maxTicks = (int)((this.verbProps.range / flightSpeed) * 2.0f);
+ trackingCharge.maxFlightTicks = maxTicks;
+
// Setup and spawn
trackingCharge.StartFlight(this.CasterPawn, this.currentTarget.Cell);
- GenSpawn.Spawn(trackingCharge, this.CasterPawn.Position, this.CasterPawn.Map);
+ GenSpawn.Spawn(trackingCharge, this.CasterPawn.Position, map); // Use the cached map
return true;
}