diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 426b9e4..59b7d73 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 1b2d358..b9dc14f 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -22,16 +22,46 @@
-
- ARA_Proj_StrongSludgeSpray
- 18
- AcidSpray_Directional
-
ARA_Proj_EggSac
+
+
+ ARA_AcidSprayBurst
+
+ 快速连续喷射多次腐蚀性酸液,覆盖一片区域。
+ UI/Abilities/AcidSpray
+ 5000
+ true
+ 300
+ true
+ false
+ AcidSpray_Warmup
+
+ Verb_CastAbility
+ 14.9
+ 0.25
+ AcidSpray_Resolve
+
+ true
+
+
+
+
+
+ ARA_Proj_StrongSludgeSpray
+ 18
+ AcidSpray_Directional
+
+
+ 32
+ 12
+
+
+
+
ARA_Proj_StrongSludgeSpray
diff --git a/1.6/1.6/Defs/DamageDefs/ARA_Damages.xml b/1.6/1.6/Defs/DamageDefs/ARA_Damages.xml
new file mode 100644
index 0000000..0456014
--- /dev/null
+++ b/1.6/1.6/Defs/DamageDefs/ARA_Damages.xml
@@ -0,0 +1,17 @@
+
+
+
+ ARA_AcidBurn
+
+
+
+ ARA_AcidCoverd
+ 0.01
+
+
+ DamageWorker_AddInjury
+ Sharp
+ AcidBurn
+ false
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs.xml
new file mode 100644
index 0000000..e7e4cdb
--- /dev/null
+++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs.xml
@@ -0,0 +1,89 @@
+
+
+
+
+ ARA_AcidCoverd
+
+ 你的身上沾上了虫族强酸,可能会痛一会。
+ (1, 1, 0.8)
+ ArachnaeSwarm.HediffCurseFlame
+
+
+ -4
+
+
+ 1800
+
+
+
+
+
+ ARA_AcidBurn
+ 1~5
+ 40
+
+
+
+
+
+ true
+
+
+
+ 0.2
+
+ 1.25
+
+
+ -0.15
+ -0.1
+
+
+
+
+ 0.35
+
+ 1.75
+
+
+ -0.35
+ -0.3
+
+
+
+
+ 0.5
+
+ 2.35
+
+
+ -0.65
+ -0.6
+
+
+
+
+ 0.65
+
+ 2.85
+
+
+ -0.8
+ -0.75
+
+
+
+
+ 0.85
+
+ 3.25
+
+
+ -2
+ -2
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
index bb11623..bafb722 100644
--- a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
+++ b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
@@ -16,6 +16,7 @@
false
ARA_EggSpew
+ ARA_AcidSprayBurst
diff --git a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
index d9ba36b..efd5b1b 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
@@ -7,9 +7,11 @@
一个黏滑的囊状物,可以通过交互来孵化特定的昆虫。
Building
Building
+ (1,1)
Things/Building/EggSac
Graphic_Random
+ (1.5,1.5)
Building
PassThroughOnly
@@ -18,7 +20,7 @@
Normal
Light
- 20
+ 200
0.4
-6
diff --git a/Source/ARA.code-workspace b/Source/ARA.code-workspace
new file mode 100644
index 0000000..40c75ee
--- /dev/null
+++ b/Source/ARA.code-workspace
@@ -0,0 +1,13 @@
+{
+ "folders": [
+ {
+ "name": "ArachnaeSwarm",
+ "path": ".."
+ },
+ {
+ "name": "Data",
+ "path": "../../../Data"
+ }
+ ],
+ "settings": {}
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 943fcf2..1ee6c58 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -71,6 +71,9 @@
+
+
+
diff --git a/Source/ArachnaeSwarm/CompAbilityEffect_SprayLiquidMulti.cs b/Source/ArachnaeSwarm/CompAbilityEffect_SprayLiquidMulti.cs
new file mode 100644
index 0000000..b20154f
--- /dev/null
+++ b/Source/ArachnaeSwarm/CompAbilityEffect_SprayLiquidMulti.cs
@@ -0,0 +1,177 @@
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompAbilityEffect_SprayLiquidMulti : CompAbilityEffect
+ {
+ private enum State
+ {
+ Ready,
+ Shooting
+ }
+
+ private State state = State.Ready;
+ private int ticksUntilNextShot;
+ private int shotsLeft;
+ private List currentAffectedCells;
+
+ private new CompProperties_AbilitySprayLiquidMulti Props => (CompProperties_AbilitySprayLiquidMulti)props;
+ private Pawn Pawn => parent.pawn;
+
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+
+ if (state == State.Ready)
+ {
+ currentAffectedCells = AffectedCells(target);
+ if (currentAffectedCells.Count > 0)
+ {
+ Fire(currentAffectedCells);
+
+ shotsLeft = Props.shotCount - 1;
+ if (shotsLeft > 0)
+ {
+ state = State.Shooting;
+ ticksUntilNextShot = Props.ticksBetweenShots;
+ }
+ }
+ }
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ if (state == State.Shooting)
+ {
+ if (ticksUntilNextShot > 0)
+ {
+ ticksUntilNextShot--;
+ }
+ else
+ {
+ if (shotsLeft > 0)
+ {
+ Fire(currentAffectedCells);
+ shotsLeft--;
+ ticksUntilNextShot = Props.ticksBetweenShots;
+ }
+
+ if (shotsLeft <= 0)
+ {
+ state = State.Ready;
+ currentAffectedCells = null;
+ }
+ }
+ }
+ }
+
+ private void Fire(List cells)
+ {
+ if (Pawn == null || !Pawn.Spawned || Props.projectileDef == null || cells == null)
+ {
+ state = State.Ready;
+ return;
+ }
+
+ if (Props.sprayEffecter != null)
+ {
+ Effecter eff = Props.sprayEffecter.Spawn(Pawn.Position, Pawn.Map);
+ eff.Cleanup();
+ }
+
+ foreach (var cell in cells)
+ {
+ if (Pawn.Position.IsValid && cell.IsValid)
+ {
+ Projectile projectile = (Projectile)GenSpawn.Spawn(Props.projectileDef, Pawn.Position, Pawn.Map);
+ projectile.Launch(Pawn, Pawn.DrawPos, cell, cell, ProjectileHitFlags.IntendedTarget);
+ }
+ }
+ }
+
+ public override void DrawEffectPreview(LocalTargetInfo target)
+ {
+ GenDraw.DrawFieldEdges(AffectedCells(target));
+ }
+
+ public override bool AICanTargetNow(LocalTargetInfo target)
+ {
+ if (Pawn.Faction != null)
+ {
+ foreach (IntVec3 item in AffectedCells(target))
+ {
+ List thingList = item.GetThingList(Pawn.Map);
+ for (int i = 0; i < thingList.Count; i++)
+ {
+ if (thingList[i].Faction == Pawn.Faction)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private List AffectedCells(LocalTargetInfo target)
+ {
+ List> tmpCellDots = new List>();
+ List tmpCells = new List();
+
+ tmpCellDots.Clear();
+ tmpCells.Clear();
+ tmpCellDots.Add(new Pair(target.Cell, 999f));
+
+ if (Props.numCellsToHit > 1)
+ {
+ Vector3 vector = Pawn.Position.ToVector3Shifted().Yto0();
+ Vector3 vector2 = target.Cell.ToVector3Shifted().Yto0();
+ IntVec3[] array;
+ int num;
+ if (Props.numCellsToHit < 10)
+ {
+ array = GenAdj.AdjacentCells;
+ num = 8;
+ }
+ else
+ {
+ array = GenRadial.RadialPattern;
+ num = Props.numCellsToHit + 5;
+ }
+ for (int i = 0; i < num; i++)
+ {
+ IntVec3 first = target.Cell + array[i];
+ Vector3 vector3 = first.ToVector3Shifted().Yto0();
+ float second = Vector3.Dot((vector3 - vector).normalized, (vector3 - vector2).normalized);
+ tmpCellDots.Add(new Pair(first, second));
+ }
+ tmpCellDots.SortByDescending(x => x.Second);
+ }
+
+ Map map = Pawn.Map;
+ int num2 = Mathf.Min(tmpCellDots.Count, Props.numCellsToHit);
+ for (int j = 0; j < num2; j++)
+ {
+ IntVec3 first2 = tmpCellDots[j].First;
+ if (!first2.InBounds(map)) continue;
+
+ if (first2.Filled(map))
+ {
+ Building_Door door = first2.GetDoor(map);
+ if (door == null || !door.Open) continue;
+ }
+
+ if (parent.verb.TryFindShootLineFromTo(Pawn.Position, first2, out var _, ignoreRange: true))
+ {
+ tmpCells.Add(first2);
+ }
+ }
+ return tmpCells;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompProperties_AbilitySprayLiquidMulti.cs b/Source/ArachnaeSwarm/CompProperties_AbilitySprayLiquidMulti.cs
new file mode 100644
index 0000000..8c62c43
--- /dev/null
+++ b/Source/ArachnaeSwarm/CompProperties_AbilitySprayLiquidMulti.cs
@@ -0,0 +1,17 @@
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_AbilitySprayLiquidMulti : CompProperties_AbilitySprayLiquid
+ {
+ public int shotCount = 1;
+
+ public int ticksBetweenShots = 10;
+
+ public CompProperties_AbilitySprayLiquidMulti()
+ {
+ compClass = typeof(CompAbilityEffect_SprayLiquidMulti);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/Hediff_CurseFlame.cs b/Source/ArachnaeSwarm/Hediffs/Hediff_CurseFlame.cs
new file mode 100644
index 0000000..90baad3
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/Hediff_CurseFlame.cs
@@ -0,0 +1,197 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CurseFlameModExt : DefModExtension
+ {
+ // XML 配置字段
+ public string damageDefName = "AcidBurn"; // 默认 AcidBurn
+ public FloatRange damageRange = new FloatRange(1f, 3f);
+ public int damageIntervalTicks = 40;
+
+ // 延迟加载的 DamageDef
+ private DamageDef _resolvedDamageDef;
+ public DamageDef ResolvedDamageDef
+ {
+ get
+ {
+ if (_resolvedDamageDef == null)
+ {
+ // 从 DefDatabase 解析 DamageDef
+ _resolvedDamageDef = DefDatabase.GetNamedSilentFail(damageDefName);
+
+ // 回退逻辑:如果配置的 DefName 无效,使用 AcidBurn
+ if (_resolvedDamageDef == null)
+ {
+ Log.Error($"[DragonianMix] 未找到 DamageDef: {damageDefName}, 已回退到 AcidBurn");
+ _resolvedDamageDef = DamageDefOf.AcidBurn;
+ }
+ }
+ return _resolvedDamageDef;
+ }
+ }
+ }
+ public class HediffCurseFlame : HediffWithComps
+ {
+ public override void Tick()
+ {
+ base.Tick();
+
+ // 1. 获取 ModExtension 配置
+ var modExt = def.GetModExtension();
+ if (modExt == null || pawn == null) return;
+
+ // 2. 解析 DamageDef(此时 DefOf 已初始化)
+ DamageDef damageDef = modExt.ResolvedDamageDef;
+ if (damageDef == null) return;
+
+ // 3. 触发伤害逻辑
+ if (pawn.Spawned && !pawn.Dead && pawn.IsHashIntervalTick(modExt.damageIntervalTicks))
+ {
+ var hittableParts = HittablePartsViolence(pawn.health.hediffSet).ToList();
+ if (hittableParts.Any())
+ {
+ DamageInfo damage = new DamageInfo(
+ def: damageDef,
+ amount: modExt.damageRange.RandomInRange,
+ armorPenetration: 999f,
+ hitPart: hittableParts.RandomElement(),
+ instigator: null
+ );
+ pawn.TakeDamage(damage);
+ }
+ }
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_References.Look(ref parent, "parent", false);
+ }
+
+ private static IEnumerable HittablePartsViolence(HediffSet bodyModel)
+ {
+ return bodyModel.GetNotMissingParts()
+ .Where(part =>
+ part.coverageAbs > 0 && // 关键过滤:只选可被击中的部位
+ (part.depth == BodyPartDepth.Outside ||
+ (part.depth == BodyPartDepth.Inside && part.def.IsSolid(part, bodyModel.hediffs)))
+ );
+ }
+
+ public Pawn parent;
+ }
+ public class HediffComp_ContinuousDamage : HediffComp
+ {
+ // Token: 0x1700000E RID: 14
+ // (get) Token: 0x0600004F RID: 79 RVA: 0x00003885 File Offset: 0x00001A85
+ public HediffCompProperties_ContinuousDamage Props
+ {
+ get
+ {
+ return (HediffCompProperties_ContinuousDamage)this.props;
+ }
+ }
+
+ // Token: 0x1700000F RID: 15
+ // (get) Token: 0x06000050 RID: 80 RVA: 0x00003892 File Offset: 0x00001A92
+ public override bool CompShouldRemove
+ {
+ get
+ {
+ return this.partMissing || base.CompShouldRemove;
+ }
+ }
+
+ // Token: 0x06000051 RID: 81 RVA: 0x000038A4 File Offset: 0x00001AA4
+ public override void CompPostMake()
+ {
+ base.CompPostMake();
+ this.ticksToDamage = this.Props.ticksPerDamage;
+ }
+
+ // Token: 0x06000052 RID: 82 RVA: 0x000038C0 File Offset: 0x00001AC0
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ if (this.parent.IsTended() || this.parent.IsPermanent() || this.Props.endTicks <= (float)this.ticksNullify)
+ {
+ return;
+ }
+ this.ticksToDamage--;
+ this.ticksNullify++;
+ if (this.ticksToDamage <= 0)
+ {
+ this.ticksToDamage = this.Props.ticksPerDamage;
+ DamageDef damageDef = this.Props.damageDef;
+ DamageInfo dinfo = new DamageInfo(damageDef, this.Props.damageAmount, 0f, 0f, null, this.parent.Part, null, DamageInfo.SourceCategory.ThingOrUnknown, base.Pawn, true, true, QualityCategory.Normal, true);
+ dinfo.SetIgnoreArmor(true);
+ base.Pawn.TakeDamage(dinfo);
+ if (base.Pawn.health.hediffSet.PartIsMissing(this.parent.Part))
+ {
+ this.partMissing = true;
+ }
+ }
+ }
+
+ // Token: 0x06000053 RID: 83 RVA: 0x000039B4 File Offset: 0x00001BB4
+ public override void CompPostMerged(Hediff other)
+ {
+ base.CompPostMerged(other);
+ HediffComp_ContinuousDamage hediffComp_ContinuousDamage = other.TryGetComp();
+ if (hediffComp_ContinuousDamage != null)
+ {
+ this.ticksNullify = Mathf.Min(hediffComp_ContinuousDamage.ticksNullify, this.ticksNullify);
+ }
+ }
+
+ // Token: 0x06000054 RID: 84 RVA: 0x000039E9 File Offset: 0x00001BE9
+ public override void CompExposeData()
+ {
+ Scribe_Values.Look(ref this.ticksNullify, "ticksNullify", 0, false);
+ Scribe_Values.Look(ref this.ticksToDamage, "ticksToDamage", 0, false);
+ Scribe_Values.Look(ref this.partMissing, "HCPD_partMissing", false, false);
+ }
+
+ // Token: 0x06000055 RID: 85 RVA: 0x00003A21 File Offset: 0x00001C21
+ public override string CompDebugString()
+ {
+ return "ticksToDamage: " + this.ticksToDamage.ToString();
+ }
+
+ // Token: 0x0400002C RID: 44
+ public int ticksNullify;
+
+ // Token: 0x0400002D RID: 45
+ public int ticksToDamage;
+
+ // Token: 0x0400002E RID: 46
+ public bool partMissing;
+ }
+ public class HediffCompProperties_ContinuousDamage : HediffCompProperties
+ {
+ // Token: 0x0600004E RID: 78 RVA: 0x0000384F File Offset: 0x00001A4F
+ public HediffCompProperties_ContinuousDamage()
+ {
+ this.compClass = typeof(HediffComp_ContinuousDamage);
+ }
+
+ // Token: 0x04000028 RID: 40
+ public DamageDef damageDef;
+
+ // Token: 0x04000029 RID: 41
+ public int ticksPerDamage = 100;
+
+ // Token: 0x0400002A RID: 42
+ public float endTicks = -1f;
+
+ // Token: 0x0400002B RID: 43
+ public float damageAmount = 1f;
+ }
+}
\ No newline at end of file