From 6e53b19e201d14bf1772b70aaf74ba3f5503a865 Mon Sep 17 00:00:00 2001 From: "ProjectKoi-Kalo\\Kalo" Date: Sun, 7 Sep 2025 15:28:24 +0800 Subject: [PATCH] =?UTF-8?q?zz=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.6/1.6/Assemblies/ArachnaeSwarm.dll | Bin 88064 -> 93184 bytes .../AbilityDefs/Abilities_TrackingCharge.xml | 46 ++++++ .../CompAbilityEffect_TrackingCharge.cs | 10 ++ .../CompProperties_TrackingCharge.cs | 20 +++ .../Abilities/PawnFlyer_TrackingCharge.cs | 156 ++++++++++++++++++ .../Verb_CastAbilityTrackingCharge.cs | 47 ++++++ Source/ArachnaeSwarm/ArachnaeSwarm.csproj | 6 + .../Documents/design_doc_tracking_charge.md | 97 +++++++++++ 8 files changed, 382 insertions(+) create mode 100644 1.6/Defs/AbilityDefs/Abilities_TrackingCharge.xml create mode 100644 Source/ArachnaeSwarm/Abilities/CompAbilityEffect_TrackingCharge.cs create mode 100644 Source/ArachnaeSwarm/Abilities/CompProperties_TrackingCharge.cs create mode 100644 Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs create mode 100644 Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs create mode 100644 Source/Documents/design_doc_tracking_charge.md diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 8dfdd792d3e3e45d429bd46467e43e5d40264abd..54e8aea1ef660515e91e662296188a35106edc14 100644 GIT binary patch delta 29940 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 + + + + + ARA_Flyer_TrackingCharge + ArachnaeSwarm.PawnFlyer_TrackingCharge + + 0.5 + 2.0 + + + + + + ARA_Ability_TrackingCharge + + Launch yourself towards a target, dealing damage to everything in your path. The damage increases the further you travel. + UI/Abilities/Charge + 600 + + ArachnaeSwarm.Verb_CastAbilityTrackingCharge + + + true + false + true + true + false + + 30 + 1.0 + + +
  • + 1.5 + 15 + 2 + 4 + Blunt + ARA_Flyer_TrackingCharge +
  • +
    +
    + +
    \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_TrackingCharge.cs new file mode 100644 index 0000000..4ad20ec --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_TrackingCharge.cs @@ -0,0 +1,10 @@ +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public class CompAbilityEffect_TrackingCharge : CompAbilityEffect + { + public new CompProperties_TrackingCharge Props => (CompProperties_TrackingCharge)this.props; + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Abilities/CompProperties_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/CompProperties_TrackingCharge.cs new file mode 100644 index 0000000..db76cb4 --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/CompProperties_TrackingCharge.cs @@ -0,0 +1,20 @@ +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public class CompProperties_TrackingCharge : CompProperties_AbilityEffect + { + public float homingSpeed = 1.0f; + public float initialDamage = 10f; + public float damagePerTile = 2f; + public float inertiaDistance = 3f; + public DamageDef collisionDamageDef; + public ThingDef flyerDef; + + public CompProperties_TrackingCharge() + { + this.compClass = typeof(CompAbilityEffect_TrackingCharge); + } + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs new file mode 100644 index 0000000..d15706d --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/PawnFlyer_TrackingCharge.cs @@ -0,0 +1,156 @@ +using RimWorld; +using UnityEngine; +using Verse; +using System.Reflection; +using System.Linq; +using Verse.AI; +using System.Collections.Generic; + +namespace ArachnaeSwarm +{ + public class PawnFlyer_TrackingCharge : PawnFlyer + { + // --- Public fields to be set by the Verb --- + public float homingSpeed; + public float initialDamage; + public float damagePerTile; + public float inertiaDistance; + public DamageDef collisionDamageDef; + public LocalTargetInfo primaryTarget; + + // --- Internal state --- + private Vector3 currentSpeed; + private float distanceTraveled = 0f; + private bool homing = true; + private int inertiaTicks = -1; + private Vector3 exactPosition; + + // --- Reflection Fields --- + private static FieldInfo TicksFlyingInfo; + private static FieldInfo TicksFlightTimeInfo; + private static FieldInfo StartVecInfo; + private static FieldInfo DestCellInfo; + private static FieldInfo PawnWasDraftedInfo; + private static FieldInfo PawnCanFireAtWillInfo; + private static FieldInfo JobQueueInfo; + private static FieldInfo InnerContainerInfo; + + static PawnFlyer_TrackingCharge() + { + TicksFlyingInfo = typeof(PawnFlyer).GetField("ticksFlying", BindingFlags.Instance | BindingFlags.NonPublic); + TicksFlightTimeInfo = typeof(PawnFlyer).GetField("ticksFlightTime", BindingFlags.Instance | BindingFlags.NonPublic); + StartVecInfo = typeof(PawnFlyer).GetField("startVec", BindingFlags.Instance | BindingFlags.NonPublic); + DestCellInfo = typeof(PawnFlyer).GetField("destCell", BindingFlags.Instance | BindingFlags.NonPublic); + PawnWasDraftedInfo = typeof(PawnFlyer).GetField("pawnWasDrafted", BindingFlags.NonPublic | BindingFlags.Instance); + PawnCanFireAtWillInfo = typeof(PawnFlyer).GetField("pawnCanFireAtWill", BindingFlags.NonPublic | BindingFlags.Instance); + JobQueueInfo = typeof(PawnFlyer).GetField("jobQueue", BindingFlags.NonPublic | BindingFlags.Instance); + InnerContainerInfo = typeof(PawnFlyer).GetField("innerContainer", BindingFlags.NonPublic | BindingFlags.Instance); + } + + // Custom initializer called by the Verb + public void StartFlight(Pawn pawn, IntVec3 finalDest) + { + var innerContainer = (ThingOwner)InnerContainerInfo.GetValue(this); + + StartVecInfo.SetValue(this, pawn.TrueCenter()); + DestCellInfo.SetValue(this, finalDest); + PawnWasDraftedInfo.SetValue(this, pawn.Drafted); + if (pawn.drafter != null) PawnCanFireAtWillInfo.SetValue(this, pawn.drafter.FireAtWill); + if (pawn.CurJob != null) pawn.jobs.SuspendCurrentJob(JobCondition.InterruptForced); + JobQueueInfo.SetValue(this, pawn.jobs.CaptureAndClearJobQueue()); + + if (pawn.Spawned) pawn.DeSpawn(DestroyMode.WillReplace); + if (!innerContainer.TryAdd(pawn)) + { + Log.Error("Could not add pawn to tracking flyer."); + pawn.Destroy(); + } + } + + public override void SpawnSetup(Map map, bool respawningAfterLoad) + { + base.SpawnSetup(map, respawningAfterLoad); + if (!respawningAfterLoad) + { + this.exactPosition = base.DrawPos; + } + } + + protected override void Tick() + { + int ticksFlying = (int)TicksFlyingInfo.GetValue(this); + + if (ticksFlying == 0) + { + Vector3 startVec = (Vector3)StartVecInfo.GetValue(this); + IntVec3 destCell = (IntVec3)DestCellInfo.GetValue(this); + Vector3 destinationPos = GenThing.TrueCenter(destCell, Rot4.North, this.FlyingThing.def.size, this.def.Altitude); + Vector3 direction = (destinationPos - startVec).normalized; + this.currentSpeed = direction * this.def.pawnFlyer.flightSpeed; + } + + this.exactPosition += this.currentSpeed; + this.distanceTraveled += this.currentSpeed.magnitude; + + if (inertiaTicks > 0) + { + inertiaTicks--; + if (inertiaTicks <= 0) { Land(); return; } + } + else + { + if (homing && primaryTarget.HasThing && primaryTarget.Thing.Spawned) + { + Vector3 desiredDirection = (primaryTarget.Thing.DrawPos - this.exactPosition).normalized; + this.currentSpeed = Vector3.RotateTowards(this.currentSpeed, desiredDirection, this.homingSpeed * 0.017f, 999f).normalized * this.def.pawnFlyer.flightSpeed; + } + else + { + homing = false; + } + + 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) + { + primaryTarget.Thing.TakeDamage(dinfo); + homing = false; + this.inertiaTicks = (int)(this.inertiaDistance / this.currentSpeed.magnitude); + } + + foreach (var thing in GenRadial.RadialDistinctThingsAround(this.exactPosition.ToIntVec3(), this.Map, 1.0f, false)) + { + if (thing == this.FlyingPawn || thing == this || 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); + } + } + + try + { + DestCellInfo.SetValue(this, this.exactPosition.ToIntVec3()); + TicksFlightTimeInfo.SetValue(this, ticksFlying + 2); + } + catch (System.Exception ex) + { + Log.ErrorOnce($"Exception during reflection in PawnFlyer_TrackingCharge: {ex}", this.thingIDNumber); + } + + TicksFlyingInfo.SetValue(this, ticksFlying + 1); + + int flightTime = (int)TicksFlightTimeInfo.GetValue(this); + if (!this.exactPosition.ToIntVec3().InBounds(this.Map) || ticksFlying > flightTime * 2) + { + Land(); + } + } + + private void Land() + { + if (this.Destroyed) return; + base.RespawnPawn(); + this.Destroy(); + } + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs new file mode 100644 index 0000000..0cb816c --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/Verb_CastAbilityTrackingCharge.cs @@ -0,0 +1,47 @@ +using RimWorld; +using Verse; +using System.Linq; + +namespace ArachnaeSwarm +{ + public class Verb_CastAbilityTrackingCharge : Verb_CastAbility + { + protected override bool TryCastShot() + { + var props = this.ability.def.comps?.OfType().FirstOrDefault(); + if (props == null) + { + Log.Error("Verb_CastAbilityTrackingCharge requires CompProperties_TrackingCharge on the ability def."); + return false; + } + + if (props.flyerDef == null) + { + Log.Error("CompProperties_TrackingCharge requires a flyerDef."); + 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); + + // Inject properties + trackingCharge.homingSpeed = props.homingSpeed; + trackingCharge.initialDamage = props.initialDamage; + trackingCharge.damagePerTile = props.damagePerTile; + trackingCharge.inertiaDistance = props.inertiaDistance; + trackingCharge.collisionDamageDef = props.collisionDamageDef; + trackingCharge.primaryTarget = this.currentTarget; + + // Setup and spawn + trackingCharge.StartFlight(this.CasterPawn, this.currentTarget.Cell); + GenSpawn.Spawn(trackingCharge, this.CasterPawn.Position, this.CasterPawn.Map); + + return true; + } + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index abfe60a..78f4b07 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -133,6 +133,12 @@ + + + + + + diff --git a/Source/Documents/design_doc_tracking_charge.md b/Source/Documents/design_doc_tracking_charge.md new file mode 100644 index 0000000..e0d56a0 --- /dev/null +++ b/Source/Documents/design_doc_tracking_charge.md @@ -0,0 +1,97 @@ +# 设计文档:跟踪冲撞技能 (Tracking Charge) + +**版本:** 0.1 + +## 1. 概述 + +本文档旨在详细说明一个新的 RimWorld 技能:“跟踪冲撞”。该技能允许一个 Pawn(施法者)像制导导弹一样冲向一个目标 Pawn。在飞行过程中,它会对路径上接触到的所有敌对单位和可破坏建筑造成伤害。伤害值会随着飞行距离的增加而累积。当撞击到主目标后,施法者会因惯性继续向前滑行一小段距离。 + +## 2. 核心功能需求 + +* **技能类型**: 主动施放的 targeted ability。 +* **移动方式**: 动态追踪曲线移动,而非直线或抛物线。 +* **伤害机制**: + * **路径伤害**: 对飞行路径上碰撞到的所有有效目标(敌方、中立、可破坏建筑)造成伤害。 + * **累积伤害**: 总伤害 = 基础伤害 + (飞行距离 * 每米伤害增量)。 + * **主目标伤害**: 与路径伤害计算方式相同。 +* **最终效果**: 撞击主目标后,追踪停止,施法者沿最后的方向继续滑行一小段距离后停下。 + +## 3. 技术架构 + +我们将采用基于自定义 `PawnFlyer` 的核心架构。这种方法将移动和效果逻辑封装在一个临时的 `Thing` 中,而施法者 Pawn 本身在技能持续期间会从地图上暂时移除。 + +### 3.1. 核心组件 + +| 组件名称 (C# Class) | 类型 | 职责 | +| ---------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | +| `Verb_CastAbilityTrackingCharge` | `Verb` | **技能启动器**: 验证目标,从 `CompProperties` 读取配置,创建并初始化 `PawnFlyer_TrackingCharge`。 | +| `PawnFlyer_TrackingCharge` | `PawnFlyer` | **核心逻辑处理器**: 接收来自 `Verb` 的参数,实现追踪、碰撞、伤害、惯性等所有动态逻辑。 | +| `CompProperties_TrackingCharge` | `CompProperties_AbilityEffect` | **XML配置接口**: 在 `AbilityDef` 的 `` 中定义技能的所有可调参数,如伤害、速度、惯性等。 | +| `CompAbilityEffect_TrackingCharge` | `CompAbilityEffect` | **数据容器**: 作为一个轻量级的组件,其主要作用是让 `CompProperties_TrackingCharge` 能被游戏正确加载。它本身不执行复杂逻辑。 | + +### 3.2. 设计决策:配置的分层与传递 + +* **采纳的方案 (混合模式)**: 我们将采用一种既符合直觉又技术稳健的混合模式。 + 1. **配置集中在 `AbilityDef`**: 使用 `CompProperties_TrackingCharge` (继承自 `CompProperties_AbilityEffect`) 来存放所有技能参数。这使得 Mod 用户可以在 `AbilityDef` 的 `` 节点中方便地调整一切,符合 RimWorld 的标准实践。 + 2. **`Verb` 作为数据中介**: `Verb_CastAbilityTrackingCharge` 在施法时,会从 `this.ability.def` 中轻松获取到 `CompProperties_TrackingCharge` 的实例,读取所有配置参数。 + 3. **`PawnFlyer` 接收参数**: `Verb` 在创建 `PawnFlyer_TrackingCharge` 实例后,会通过一个自定义的初始化方法(例如 `Initialize(...)`),将所有读取到的参数“注入”到 `PawnFlyer` 实例中。 +* **优点**: 这个方案完美地解决了您的顾虑。配置的**易用性**(在 `AbilityDef` 中)和逻辑的**清晰性**(`PawnFlyer` 负责执行)都得到了保证。 + +### 3.3. 数据流与交互 + +```mermaid +graph TD + subgraph Player Action + A[玩家选择目标并施放技能] --> B(AbilityDef); + end + + subgraph XML Definitions + B -- contains --> E[CompProperties_TrackingCharge]; + B -- uses --> C(VerbDef); + C -- verbClass --> D[Verb_CastAbilityTrackingCharge]; + F(ThingDef for Flyer) -- thingClass --> G[PawnFlyer_TrackingCharge]; + end + + subgraph C# Logic + D -- 1. Reads Params from --> E; + D -- 2. Creates --> G; + D -- 3. Injects Params into --> G; + G -- 4. Executes Tick Logic --> H{追踪 & 碰撞}; + H -- 5. Applies Damage to --> I[Things on Path]; + G -- 6. Handles Inertia & Self-Destructs --> J[Final Position]; + end + + PlayerInput([施法者 Pawn]) -- temporarily removed --> G; + G -- places back --> PlayerInput; +``` + +## 4. 详细实现步骤 + +### 步骤 1: 创建 C# 类骨架 (最终版) + +* **文件**: `CompProperties_TrackingCharge.cs` + * **继承**: `Verse.CompProperties_AbilityEffect` + * **职责**: 定义所有可在 XML 中配置的技能参数。 + * **示例字段**: `public float homingSpeed;`, `public float initialDamage;`, `public float damagePerTile;`, `public float inertiaDistance;`, `public DamageDef collisionDamageDef;`, `public ThingDef flyerDef;` (用于指定飞行器的ThingDef)。 + +* **文件**: `CompAbilityEffect_TrackingCharge.cs` + * **继承**: `Verse.CompAbilityEffect` + * **职责**: 轻量级组件,其存在是为了让 `CompProperties_TrackingCharge` 能被游戏正确加载和访问。 + +* **文件**: `Verb_CastAbilityTrackingCharge.cs` + * **继承**: `Verse.Verb_CastAbility` + * **职责**: + 1. 在 `TryCastShot()` 中,从 `this.ability.GetComp().Props` 获取配置。 + 2. 调用 `PawnFlyer.MakeFlyer(Props.flyerDef, ...)` 创建 `PawnFlyer_TrackingCharge` 实例。 + 3. **将配置参数设置到 `PawnFlyer` 的公共字段上**。 + 4. 调用 `flyer.Launch()` 启动。 + +* **文件**: `PawnFlyer_TrackingCharge.cs` + * **继承**: `Verse.PawnFlyer` + * **职责**: + 1. 定义一系列**公共字段** (`public float homingSpeed;` 等) 来接收来自 `Verb` 的参数。 + 2. 在 `Tick()` 中实现所有核心的追踪、碰撞和伤害逻辑。 + * **注意**: **不**创建自定义的 `Initialize()` 方法,也**不**重写 `Launch()` 来接收参数,以保持设计的简洁和标准。 + +--- +> **下一步**: 设计文档已最终确定。我将开始实施 **步骤 1**,为您创建这四个 C# 类的代码框架。 \ No newline at end of file