This commit is contained in:
2025-12-31 14:33:49 +08:00
parent bb0f3d281c
commit 299be12bd2
6 changed files with 135 additions and 57 deletions

Binary file not shown.

View File

@@ -658,7 +658,7 @@
<initialDamage>15</initialDamage>
<damagePerTile>1.5</damagePerTile>
<inertiaDistance>6</inertiaDistance>
<collisionDamageDef>Blunt</collisionDamageDef>
<collisionDamageDef>Demolish</collisionDamageDef>
<flyerDef>ARA_Flyer_TrackingCharge</flyerDef>
<collisionRadius>1.5</collisionRadius> <!-- Larger collision radius -->
<impactSound>Pawn_Melee_BigBash_HitPawn</impactSound>

View File

@@ -78,7 +78,7 @@
<initialDamage>50</initialDamage>
<damagePerTile>3</damagePerTile>
<inertiaDistance>15</inertiaDistance>
<collisionDamageDef>Blunt</collisionDamageDef>
<collisionDamageDef>Demolish</collisionDamageDef>
<flyerDef>ARA_Flyer_TrackingCharge</flyerDef>
<collisionRadius>3.5</collisionRadius> <!-- Larger collision radius -->
<impactSound>Pawn_Melee_BigBash_HitPawn</impactSound>

View File

@@ -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": ""

View File

@@ -30,6 +30,9 @@ namespace ArachnaeSwarm
private IntVec3? desiredLandingCell = null; // 新增:期望的降落位置
private bool isLanding = false; // 新增:标记是否正在降落
private bool positionAdjusted = false; // 新增:标记是否已调整位置
private HashSet<Thing> alreadyDamaged = new HashSet<Thing>(); // 新增:记录已经造成伤害的目标
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<Thing> 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<Thing> damagedThingsList = null;
Scribe_Collections.Look(ref damagedThingsList, "damagedThings", LookMode.Reference);
if (damagedThingsList != null)
{
alreadyDamaged = new HashSet<Thing>(damagedThingsList);
}
IntVec3 cell = IntVec3.Invalid;
Scribe_Values.Look(ref cell, "desiredLandingCell");
if (cell.IsValid)