diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index f5d0010..183e09f 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/Thing_Misc/Weapons/ARA_Weapon_Laser.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Laser.xml
new file mode 100644
index 0000000..b13fbe2
--- /dev/null
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Laser.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+ WULA_RW_DM_AR_Arc
+
+ 乌拉帝国一线部队所使用的由暗物质驱动的常规步枪的改造版。现在它发射的能量束会在命中后寻找并跳跃到附近的其他敌人身上,形成致命的能量链。
+ Ultra
+
+ Wula/Weapon/WULA_RW_DM_AR
+ Graphic_Single
+ 1.2
+
+
+ Wula_Ranged_Weapon_T4
+
+ 0.9
+ Interact_ChargeRifle
+
+
+ WULA_Cube_Productor_Energy
+
+ WULA_Synth_Weapon_4_DM_Base_Technology
+ UnfinishedWeapon
+
+
+ 400
+ 200
+ 4
+
+
+ 40000
+ 4.5
+ 1
+ 1
+ 1
+ 1
+ 1.25
+
+
+
+ ArachnaeSwarm.Verb_ShootBeamArc
+
+
+ true
+ 1
+ 36
+ 6
+ 10
+ Wula_Dark_Matter_Beam
+ 90
+
+
+ 0
+ BeamGraser_Shooting
+ Fleck_BeamBurn
+ 0.32
+ Mote_Wula_Dark_Matter_Beam
+ GraserBeam_End
+ 0.35
+
+
+ 0.6
+ 0.6
+ 0.25
+
+
+
+ true
+
+
+
+ 4
+ 30
+ 0.7
+ Mote_Wula_Dark_Matter_Beam
+
+
+ None
+
+ RewardStandardQualitySuper
+
+
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 06637fc..a0be073 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -233,6 +233,7 @@
+
diff --git a/Source/ArachnaeSwarm/Verbs/Verb_ShootBeamArc.cs b/Source/ArachnaeSwarm/Verbs/Verb_ShootBeamArc.cs
new file mode 100644
index 0000000..a0f5bc1
--- /dev/null
+++ b/Source/ArachnaeSwarm/Verbs/Verb_ShootBeamArc.cs
@@ -0,0 +1,193 @@
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+using Verse.Sound;
+using System.Linq;
+
+namespace ArachnaeSwarm
+{
+ public class VerbProperties_BeamArc : VerbProperties
+ {
+ public int conductNum;
+ public float conductRange;
+ public float secondaryDamageFactor = 0.5f;
+ public ThingDef chainMoteDef;
+
+ public VerbProperties_BeamArc()
+ {
+ this.verbClass = typeof(Verb_ShootBeamArc);
+ }
+ }
+
+ // This class is a modified copy of Verb_ShootBeam to implement chain-lightning functionality.
+ public class Verb_ShootBeamArc : Verb
+ {
+ // --- Fields from original Verb_ShootBeam ---
+ private int ticksToNextPathStep;
+ private MoteDualAttached mote; // This will be the main beam
+ private Effecter endEffecter;
+ private Sustainer sustainer;
+
+ // --- Custom fields for chain logic ---
+ protected List chainedTargets = new List();
+ protected List chainMotes = new List();
+ private VerbProperties_BeamArc Props => this.verbProps as VerbProperties_BeamArc;
+
+ protected override int ShotsPerBurst => base.BurstShotCount;
+
+ public override void WarmupComplete()
+ {
+ // --- Chain Target Finding Logic ---
+ chainedTargets.Clear();
+ foreach (MoteDualAttached m in chainMotes) { m.Destroy(); }
+ chainMotes.Clear();
+
+ if (this.Props != null && this.Props.conductNum > 0 && this.currentTarget.HasThing)
+ {
+ Thing currentTargetThing = this.currentTarget.Thing;
+ chainedTargets.Add(currentTargetThing);
+
+ Thing lastTarget = currentTargetThing;
+ for (int i = 0; i < this.Props.conductNum; i++)
+ {
+ Thing nextTarget = AttackTargetFinder.BestAttackTarget(lastTarget as Pawn, TargetScanFlags.NeedLOSToAll, (Thing t) =>
+ t is Pawn p && !p.Downed && !chainedTargets.Contains(t) && t.Position.InHorDistOf(lastTarget.Position, this.Props.conductRange) && this.Caster.HostileTo(t),
+ 0f, 9999f, default(IntVec3), this.Props.conductRange) as Thing;
+
+ if (nextTarget != null)
+ {
+ chainedTargets.Add(nextTarget);
+ lastTarget = nextTarget;
+ }
+ else { break; }
+ }
+ }
+
+ // --- Original Verb_ShootBeam Logic (simplified) ---
+ burstShotsLeft = ShotsPerBurst;
+ state = VerbState.Bursting;
+
+ // Create main beam mote
+ if (verbProps.beamMoteDef != null && this.currentTarget.Thing != null)
+ {
+ mote = MoteMaker.MakeInteractionOverlay(verbProps.beamMoteDef, caster, this.currentTarget.Thing);
+ }
+
+ // Create chain motes
+ if (chainedTargets.Count > 1)
+ {
+ for (int i = 0; i < chainedTargets.Count - 1; i++)
+ {
+ ThingDef moteDef = this.Props.chainMoteDef ?? this.verbProps.beamMoteDef;
+ if (moteDef != null)
+ {
+ MoteDualAttached chainLinkMote = MoteMaker.MakeInteractionOverlay(moteDef, chainedTargets[i], chainedTargets[i + 1]);
+ chainMotes.Add(chainLinkMote);
+ }
+ }
+ }
+
+ TryCastNextBurstShot();
+ ticksToNextPathStep = verbProps.ticksBetweenBurstShots;
+ endEffecter?.Cleanup();
+ if (verbProps.soundCastBeam != null)
+ {
+ sustainer = verbProps.soundCastBeam.TrySpawnSustainer(SoundInfo.InMap(caster, MaintenanceType.PerTick));
+ }
+ }
+
+ public override void BurstingTick()
+ {
+ // --- Update Visuals ---
+ mote?.Maintain();
+ foreach (MoteDualAttached m in chainMotes) { m.Maintain(); }
+
+ // --- Original ground/end effect logic (simplified to target) ---
+ if (this.currentTarget.Thing != null)
+ {
+ Vector3 endPoint = this.currentTarget.Thing.DrawPos;
+ IntVec3 endCell = this.currentTarget.Cell;
+
+ if (verbProps.beamGroundFleckDef != null && Rand.Chance(verbProps.beamFleckChancePerTick))
+ {
+ FleckMaker.Static(endPoint, caster.Map, verbProps.beamGroundFleckDef);
+ }
+ if (endEffecter == null && verbProps.beamEndEffecterDef != null)
+ {
+ endEffecter = verbProps.beamEndEffecterDef.Spawn(endCell, caster.Map, Vector3.zero);
+ }
+ if (endEffecter != null)
+ {
+ endEffecter.EffectTick(new TargetInfo(endCell, caster.Map), TargetInfo.Invalid);
+ endEffecter.ticksLeft--;
+ }
+ }
+ sustainer?.Maintain();
+ }
+
+ protected override bool TryCastShot()
+ {
+ if (this.currentTarget.HasThing && this.currentTarget.Thing.Map != this.caster.Map) { return false; }
+
+ if (base.EquipmentSource != null)
+ {
+ base.EquipmentSource.GetComp()?.Notify_ProjectileLaunched();
+ base.EquipmentSource.GetComp()?.UsedOnce();
+ }
+
+ // --- Apply Damage to Chain ---
+ if (this.chainedTargets.Any())
+ {
+ this.ApplyChainDamage(this.chainedTargets[0], 1.0f);
+ for (int i = 1; i < this.chainedTargets.Count; i++)
+ {
+ this.ApplyChainDamage(this.chainedTargets[i], this.Props.secondaryDamageFactor);
+ }
+ }
+ else if(this.currentTarget.Thing != null)
+ {
+ this.ApplyChainDamage(this.currentTarget.Thing, 1.0f);
+ }
+
+ return true;
+ }
+
+ private void ApplyChainDamage(Thing thing, float damageFactor)
+ {
+ Map map = this.caster.Map;
+ if (thing == null || this.verbProps.beamDamageDef == null) { return; }
+
+ float angleFlat = (this.currentTarget.Cell - this.caster.Position).AngleFlat;
+ BattleLogEntry_RangedImpact log = new BattleLogEntry_RangedImpact(this.caster, thing, this.currentTarget.Thing, base.EquipmentSource.def, null, null);
+
+ DamageInfo dinfo;
+ if (this.verbProps.beamTotalDamage > 0f)
+ {
+ float damagePerShot = this.verbProps.beamTotalDamage / (float)this.ShotsPerBurst;
+ dinfo = new DamageInfo(this.verbProps.beamDamageDef, damagePerShot * damageFactor, this.verbProps.beamDamageDef.defaultArmorPenetration, angleFlat, this.caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing);
+ }
+ else
+ {
+ float amount = (float)this.verbProps.beamDamageDef.defaultDamage * damageFactor;
+ dinfo = new DamageInfo(this.verbProps.beamDamageDef, amount, this.verbProps.beamDamageDef.defaultArmorPenetration, angleFlat, this.caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing);
+ }
+
+ thing.TakeDamage(dinfo).AssociateWithLog(log);
+
+ if (thing.CanEverAttachFire())
+ {
+ float chance = this.verbProps.flammabilityAttachFireChanceCurve?.Evaluate(thing.GetStatValue(StatDefOf.Flammability)) ?? this.verbProps.beamChanceToAttachFire;
+ if (Rand.Chance(chance))
+ {
+ thing.TryAttachFire(this.verbProps.beamFireSizeRange.RandomInRange, this.caster);
+ }
+ }
+ else if (Rand.Chance(this.verbProps.beamChanceToStartFire))
+ {
+ FireUtility.TryStartFireIn(thing.Position, map, this.verbProps.beamFireSizeRange.RandomInRange, this.caster, this.verbProps.flammabilityAttachFireChanceCurve);
+ }
+ }
+ }
+}
\ No newline at end of file