This commit is contained in:
2025-09-07 17:11:53 +08:00
parent b6f9e6193a
commit 7a6d5380e1
4 changed files with 41 additions and 13 deletions

Binary file not shown.

View File

@@ -6,8 +6,8 @@
<defName>ARA_Flyer_TrackingCharge</defName>
<thingClass>ArachnaeSwarm.PawnFlyer_TrackingCharge</thingClass>
<pawnFlyer>
<flightSpeed>0.1</flightSpeed>
<heightFactor>0.1</heightFactor>
<flightSpeed>0.5</flightSpeed>
<heightFactor>0</heightFactor>
</pawnFlyer>
</ThingDef>
@@ -16,7 +16,7 @@
<defName>ARA_Ability_TrackingCharge</defName>
<label>追踪冲撞</label>
<description>阿拉克涅盾头种对目标发起蓄势冲撞,对路径上的一切造成伤害。飞行的距离越远,伤害越高。</description>
<iconPath>UI/Abilities/Charge</iconPath> <!-- Placeholder Icon -->
<iconPath>UI/Commands/WarTrumpet</iconPath> <!-- Placeholder Icon -->
<cooldownTicksRange>600</cooldownTicksRange>
<verbProperties>
<verbClass>ArachnaeSwarm.Verb_CastAbilityTrackingCharge</verbClass>
@@ -36,8 +36,8 @@
<homingSpeed>1.5</homingSpeed>
<initialDamage>15</initialDamage>
<damagePerTile>2</damagePerTile>
<inertiaDistance>4</inertiaDistance>
<collisionDamageDef>Crush</collisionDamageDef>
<inertiaDistance>6</inertiaDistance>
<collisionDamageDef>Blunt</collisionDamageDef>
<flyerDef>ARA_Flyer_TrackingCharge</flyerDef>
</li>
</comps>

View File

@@ -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)
{
@@ -139,8 +146,8 @@ 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();
}

View File

@@ -21,6 +21,16 @@ 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;
@@ -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;
}