diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index edfa580..df51e23 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/ARA_Abilities.xml b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
index 47443bc..aeea6af 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -658,7 +658,7 @@
15
1.5
6
- Blunt
+ Demolish
ARA_Flyer_TrackingCharge
1.5
Pawn_Melee_BigBash_HitPawn
diff --git a/1.6/1.6/Defs/TrainableDefs/ARA_TrainableDef.xml b/1.6/1.6/Defs/TrainableDefs/ARA_TrainableDef.xml
index 1b1236d..2d9ef0e 100644
--- a/1.6/1.6/Defs/TrainableDefs/ARA_TrainableDef.xml
+++ b/1.6/1.6/Defs/TrainableDefs/ARA_TrainableDef.xml
@@ -78,7 +78,7 @@
50
3
15
- Blunt
+ Demolish
ARA_Flyer_TrackingCharge
3.5
Pawn_Melee_BigBash_HitPawn
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 1558f91..b73f03f 100644
Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
index 39b610e..70d7dba 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -7,16 +7,16 @@
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\pawnflyer_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\trackingcharge\\verb_castabilitytrackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\trackingcharge\\verb_castabilitytrackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\verb_castabilitytrackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\trackingcharge\\compproperties_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\trackingcharge\\compproperties_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\compproperties_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -34,7 +34,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 1,
+ "DocumentIndex": 2,
"Title": "Verb_CastAbilityTrackingCharge.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
@@ -42,8 +42,7 @@
"RelativeToolTip": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:14.205Z",
- "EditorCaption": ""
+ "WhenOpened": "2025-12-31T03:34:14.205Z"
},
{
"$type": "Document",
@@ -53,14 +52,14 @@
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
"RelativeToolTip": "Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAABAAAAAAAAAA==",
+ "ViewState": "AgIAAIwBAAAAAAAAAAAAAKMBAAA3AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-31T03:34:13.727Z",
"EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 3,
"Title": "CompProperties_TrackingCharge.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
@@ -68,18 +67,17 @@
"RelativeToolTip": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:13.26Z",
- "EditorCaption": ""
+ "WhenOpened": "2025-12-31T03:34:13.26Z"
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 1,
"Title": "CompAbilityEffect_TrackingCharge.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
"RelativeToolTip": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-31T03:34:12.758Z",
"EditorCaption": ""
diff --git a/Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs
index e2f361e..2a4bed7 100644
--- a/Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs
+++ b/Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs
@@ -30,6 +30,9 @@ namespace ArachnaeSwarm
private IntVec3? desiredLandingCell = null; // 新增:期望的降落位置
private bool isLanding = false; // 新增:标记是否正在降落
private bool positionAdjusted = false; // 新增:标记是否已调整位置
+ private HashSet alreadyDamaged = new HashSet(); // 新增:记录已经造成伤害的目标
+ private int lastPathDamageTick = 0; // 新增:上次路径伤害的tick
+ private const int PATH_DAMAGE_INTERVAL = 2; // 新增:路径伤害间隔(每2帧检查一次)
// --- Reflection Fields ---
private static FieldInfo TicksFlyingInfo;
@@ -79,6 +82,8 @@ namespace ArachnaeSwarm
if (!respawningAfterLoad)
{
this.exactPosition = base.DrawPos;
+ alreadyDamaged.Clear();
+ lastPathDamageTick = 0;
}
}
@@ -100,6 +105,9 @@ namespace ArachnaeSwarm
DestCellInfo.SetValue(this, primaryTarget.Thing.Position);
}
+ // --- 路径伤害逻辑:飞行过程中持续造成伤害 ---
+ ApplyPathDamage();
+
// --- 主目标碰撞检测 ---
if (!hasHitPrimaryTarget && primaryTarget.HasThing && primaryTarget.Thing.Spawned)
{
@@ -113,9 +121,6 @@ namespace ArachnaeSwarm
}
}
- // --- AOE伤害逻辑 ---
- ApplyAoeDamage();
-
// --- 基础Tick逻辑 ---
base.Tick();
@@ -126,7 +131,100 @@ namespace ArachnaeSwarm
}
}
- // 新增:处理主目标碰撞
+ // 修改:应用路径伤害(飞行过程中持续造成伤害)
+ private void ApplyPathDamage()
+ {
+ int ticksFlying = (int)TicksFlyingInfo.GetValue(this);
+
+ // 限制检查频率
+ if (ticksFlying - lastPathDamageTick < PATH_DAMAGE_INTERVAL)
+ return;
+
+ lastPathDamageTick = ticksFlying;
+
+ // 计算当前伤害值
+ Vector3 startPosition = (Vector3)StartVecInfo.GetValue(this);
+ float distanceTravelled = (this.DrawPos - startPosition).magnitude;
+ float currentDamage = this.initialDamage + (distanceTravelled * this.damagePerTile);
+
+ // 获取当前位置周围的所有物体
+ var thingsInRadius = GenRadial.RadialDistinctThingsAround(this.Position, this.Map, this.collisionRadius, false).ToList();
+
+ foreach (var thing in thingsInRadius)
+ {
+ // 跳过自己、飞行器和已经被伤害过的目标
+ if (thing == this.FlyingPawn || thing == this || alreadyDamaged.Contains(thing))
+ continue;
+
+ // 如果是主目标,跳过(主目标有专门的碰撞检测)
+ if (primaryTarget.HasThing && thing == primaryTarget.Thing && !hasHitPrimaryTarget)
+ continue;
+
+ // 检查是否需要伤害
+ if (ShouldDamageThing(thing))
+ {
+ // 创建伤害信息
+ var dinfo = new DamageInfo(this.collisionDamageDef, currentDamage, 1f, -1, this.FlyingPawn);
+
+ // 应用伤害
+ thing.TakeDamage(dinfo);
+
+ // 记录已经伤害过的目标
+ alreadyDamaged.Add(thing);
+
+ // 播放音效(可选)
+ if (this.impactSound != null && thing is Pawn)
+ {
+ SoundStarter.PlayOneShot(this.impactSound, new TargetInfo(thing.Position, this.Map));
+ }
+
+ if (Prefs.DevMode)
+ {
+ ArachnaeLog.Debug($"TrackingCharge path damage: {thing.LabelCap} took {currentDamage} damage");
+ }
+ }
+ }
+
+ // 可选:添加视觉效果
+ if (ticksFlying % 10 == 0 && Prefs.DevMode)
+ {
+ FleckMaker.ThrowDustPuff(this.DrawPos + Gen.RandomHorizontalVector(0.5f), this.Map, 0.5f);
+ }
+ }
+
+ // 新增:判断是否应该伤害物体
+ private bool ShouldDamageThing(Thing thing)
+ {
+ if (thing == null || thing.Destroyed)
+ return false;
+
+ // 如果是生物
+ if (thing is Pawn pawn)
+ {
+ if (pawn.Downed || pawn.Dead)
+ return false;
+
+ // 检查是否只伤害敌对目标
+ if (this.damageHostileOnly && !pawn.HostileTo(this.FlyingPawn))
+ return false;
+
+ return true;
+ }
+ // 如果是建筑
+ else if (thing.def.destroyable && thing.def.building != null)
+ {
+ return true;
+ }
+ // 如果是门或其他障碍物
+ else if (thing.def.passability == Traversability.PassThroughOnly)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ // 修改:处理主目标碰撞
private void ImpactPrimaryTarget()
{
// 播放音效
@@ -144,6 +242,12 @@ namespace ArachnaeSwarm
primaryTarget.Thing.TakeDamage(dinfo);
hasHitPrimaryTarget = true;
+ // 将主目标添加到已伤害列表,避免后续路径伤害重复伤害
+ if (!alreadyDamaged.Contains(primaryTarget.Thing))
+ {
+ alreadyDamaged.Add(primaryTarget.Thing);
+ }
+
homing = false;
// 计算期望的降落位置(目标身后一格)
@@ -312,42 +416,6 @@ namespace ArachnaeSwarm
}
}
- // 新增:应用AOE伤害
- private void ApplyAoeDamage()
- {
- if (!hasHitPrimaryTarget)
- return;
-
- Vector3 startPosition = (Vector3)StartVecInfo.GetValue(this);
- float distanceTravelled = (this.DrawPos - startPosition).magnitude;
- float currentAOEDamage = this.initialDamage + (distanceTravelled * this.damagePerTile);
-
- // 只应用一次AOE伤害,避免每帧都造成伤害
- int ticksFlying = (int)TicksFlyingInfo.GetValue(this);
- if (ticksFlying % 5 != 0) // 每5帧检查一次
- return;
-
- foreach (var thing in GenRadial.RadialDistinctThingsAround(this.Position, this.Map, this.collisionRadius, false))
- {
- if (thing != this.FlyingPawn && thing != this && thing != primaryTarget.Thing)
- {
- if (thing is Pawn pawn && !pawn.Downed)
- {
- if (!this.damageHostileOnly || pawn.HostileTo(this.FlyingPawn))
- {
- var aoeDinfo = new DamageInfo(this.collisionDamageDef, currentAOEDamage, 1f, -1, this.FlyingPawn);
- pawn.TakeDamage(aoeDinfo);
- }
- }
- else if (thing.def.destroyable && thing.def.building != null)
- {
- var aoeDinfo = new DamageInfo(this.collisionDamageDef, currentAOEDamage, 1f, -1, this.FlyingPawn);
- thing.TakeDamage(aoeDinfo);
- }
- }
- }
- }
-
// 新增:在飞行器销毁前调整位置
protected override void TickInterval(int delta)
{
@@ -415,9 +483,14 @@ namespace ArachnaeSwarm
Scribe_Values.Look(ref hasHitPrimaryTarget, "hasHitPrimaryTarget", false);
Scribe_Values.Look(ref isLanding, "isLanding", false);
Scribe_Values.Look(ref positionAdjusted, "positionAdjusted", false);
+ Scribe_Values.Look(ref lastPathDamageTick, "lastPathDamageTick", 0);
+ // 保存已伤害的目标列表
if (Scribe.mode == LoadSaveMode.Saving)
{
+ List damagedThingsList = alreadyDamaged.ToList();
+ Scribe_Collections.Look(ref damagedThingsList, "damagedThings", LookMode.Reference);
+
if (desiredLandingCell.HasValue)
{
IntVec3 cell = desiredLandingCell.Value;
@@ -426,6 +499,13 @@ namespace ArachnaeSwarm
}
else if (Scribe.mode == LoadSaveMode.LoadingVars)
{
+ List damagedThingsList = null;
+ Scribe_Collections.Look(ref damagedThingsList, "damagedThings", LookMode.Reference);
+ if (damagedThingsList != null)
+ {
+ alreadyDamaged = new HashSet(damagedThingsList);
+ }
+
IntVec3 cell = IntVec3.Invalid;
Scribe_Values.Look(ref cell, "desiredLandingCell");
if (cell.IsValid)