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)