暂存
This commit is contained in:
@@ -234,6 +234,7 @@
|
||||
<Compile Include="Verbs\Projectiles\TrackingBulletDef.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootArc.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootBeamArc.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootBeamSplitAndChain.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootMeltBeam.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootShotgun.cs" />
|
||||
<Compile Include="Verbs\Verb_ShootShotgunWithOffset.cs" />
|
||||
@@ -265,6 +266,9 @@
|
||||
<Compile Include="Buildings\Wormhole\TravelingWormhole.cs" />
|
||||
<Compile Include="Buildings\Wormhole\DefModExtension_TravelingWormhole.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Utils\BezierUtil.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||
|
||||
30
Source/ArachnaeSwarm/Utils/BezierUtil.cs
Normal file
30
Source/ArachnaeSwarm/Utils/BezierUtil.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ArachnaeSwarm.Utils
|
||||
{
|
||||
public static class BezierUtil
|
||||
{
|
||||
// Generates points for a quadratic Bezier curve.
|
||||
public static List<Vector3> GenerateQuadraticPoints(Vector3 start, Vector3 control, Vector3 end, int segments)
|
||||
{
|
||||
List<Vector3> points = new List<Vector3>();
|
||||
if (segments <= 0) segments = 1;
|
||||
|
||||
for (int i = 0; i <= segments; i++)
|
||||
{
|
||||
float t = (float)i / segments;
|
||||
float u = 1f - t;
|
||||
float tt = t * t;
|
||||
float uu = u * u;
|
||||
|
||||
Vector3 p = uu * start; // (1-t)^2 * P0
|
||||
p += 2 * u * t * control; // 2(1-t)t * P1
|
||||
p += tt * end; // t^2 * P2
|
||||
|
||||
points.Add(p);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace ArachnaeSwarm
|
||||
public float conductRange;
|
||||
public float secondaryDamageFactor = 0.5f;
|
||||
public ThingDef chainMoteDef;
|
||||
public float beamArmorPenetration = 0f; // Add missing property
|
||||
|
||||
public VerbProperties_BeamArc()
|
||||
{
|
||||
@@ -21,70 +22,83 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Thing> chainedTargets = new List<Thing>();
|
||||
protected List<MoteDualAttached> chainMotes = new List<MoteDualAttached>();
|
||||
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();
|
||||
this.Cleanup();
|
||||
|
||||
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 primaryTarget = this.currentTarget.Thing;
|
||||
if (primaryTarget is Pawn p && (p.Dead || p.Downed))
|
||||
{
|
||||
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;
|
||||
// Do not start a chain on an invalid primary target.
|
||||
}
|
||||
else
|
||||
{
|
||||
chainedTargets.Add(primaryTarget);
|
||||
Thing lastTarget = primaryTarget;
|
||||
|
||||
if (nextTarget != null)
|
||||
for (int i = 0; i < this.Props.conductNum; i++)
|
||||
{
|
||||
chainedTargets.Add(nextTarget);
|
||||
lastTarget = nextTarget;
|
||||
// MCP Suggested Fix: Manual search for the NEAREST valid target.
|
||||
Thing nextTarget = GenRadial.RadialDistinctThingsAround(lastTarget.Position, this.caster.Map, this.Props.conductRange, false)
|
||||
.OfType<Pawn>()
|
||||
.Where(pawn =>
|
||||
!pawn.Dead &&
|
||||
!pawn.Downed &&
|
||||
!chainedTargets.Contains(pawn) &&
|
||||
this.Caster.HostileTo(pawn) &&
|
||||
GenSight.LineOfSight(lastTarget.Position, pawn.Position, this.caster.Map, true)
|
||||
)
|
||||
.OrderBy(pawn => pawn.Position.DistanceToSquared(lastTarget.Position))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (nextTarget != null)
|
||||
{
|
||||
chainedTargets.Add(nextTarget);
|
||||
lastTarget = nextTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { break; }
|
||||
}
|
||||
}
|
||||
|
||||
// --- Original Verb_ShootBeam Logic (simplified) ---
|
||||
burstShotsLeft = ShotsPerBurst;
|
||||
state = VerbState.Bursting;
|
||||
|
||||
// Create main beam mote
|
||||
if (verbProps.beamMoteDef != null && this.currentTarget.Thing != null)
|
||||
// Unified visual creation
|
||||
if (chainedTargets.Any())
|
||||
{
|
||||
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++)
|
||||
// First link: Caster -> Primary Target
|
||||
if (verbProps.beamMoteDef != null)
|
||||
{
|
||||
ThingDef moteDef = this.Props.chainMoteDef ?? this.verbProps.beamMoteDef;
|
||||
if (moteDef != null)
|
||||
MoteDualAttached firstLink = MoteMaker.MakeInteractionOverlay(verbProps.beamMoteDef, this.caster, chainedTargets[0]);
|
||||
chainMotes.Add(firstLink);
|
||||
}
|
||||
|
||||
// Subsequent links: Target -> Next Target
|
||||
if (chainedTargets.Count > 1)
|
||||
{
|
||||
ThingDef chainMoteDef = this.Props.chainMoteDef ?? this.verbProps.beamMoteDef;
|
||||
for (int i = 0; i < chainedTargets.Count - 1; i++)
|
||||
{
|
||||
MoteDualAttached chainLinkMote = MoteMaker.MakeInteractionOverlay(moteDef, chainedTargets[i], chainedTargets[i + 1]);
|
||||
chainMotes.Add(chainLinkMote);
|
||||
MoteDualAttached chainLink = MoteMaker.MakeInteractionOverlay(chainMoteDef, chainedTargets[i], chainedTargets[i + 1]);
|
||||
chainMotes.Add(chainLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,28 +114,26 @@ namespace ArachnaeSwarm
|
||||
|
||||
public override void BurstingTick()
|
||||
{
|
||||
// --- Update Visuals ---
|
||||
mote?.Maintain();
|
||||
if (this.burstShotsLeft <= 0)
|
||||
{
|
||||
this.Cleanup();
|
||||
base.BurstingTick(); // Must be called to properly end the verb state.
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (MoteDualAttached m in chainMotes) { m.Maintain(); }
|
||||
|
||||
// --- Original ground/end effect logic (simplified to target) ---
|
||||
if (this.currentTarget.Thing != null)
|
||||
// Simplified end effecter logic on the last known target.
|
||||
Thing lastTarget = chainedTargets.LastOrDefault();
|
||||
if (lastTarget != null)
|
||||
{
|
||||
Vector3 endPoint = this.currentTarget.Thing.DrawPos;
|
||||
IntVec3 endCell = this.currentTarget.Cell;
|
||||
|
||||
if (verbProps.beamGroundFleckDef != null && Rand.Chance(verbProps.beamFleckChancePerTick))
|
||||
if (endEffecter == null && verbProps.beamEndEffecterDef != null)
|
||||
{
|
||||
FleckMaker.Static(endPoint, caster.Map, verbProps.beamGroundFleckDef);
|
||||
}
|
||||
if (endEffecter == null && verbProps.beamEndEffecterDef != null)
|
||||
{
|
||||
endEffecter = verbProps.beamEndEffecterDef.Spawn(endCell, caster.Map, Vector3.zero);
|
||||
endEffecter = verbProps.beamEndEffecterDef.Spawn(lastTarget.Position, caster.Map, Vector3.zero);
|
||||
}
|
||||
if (endEffecter != null)
|
||||
{
|
||||
endEffecter.EffectTick(new TargetInfo(endCell, caster.Map), TargetInfo.Invalid);
|
||||
endEffecter.ticksLeft--;
|
||||
endEffecter.EffectTick(new TargetInfo(lastTarget), TargetInfo.Invalid);
|
||||
}
|
||||
}
|
||||
sustainer?.Maintain();
|
||||
@@ -129,7 +141,7 @@ namespace ArachnaeSwarm
|
||||
|
||||
protected override bool TryCastShot()
|
||||
{
|
||||
if (this.currentTarget.HasThing && this.currentTarget.Thing.Map != this.caster.Map) { return false; }
|
||||
if (!this.chainedTargets.Any()) return false;
|
||||
|
||||
if (base.EquipmentSource != null)
|
||||
{
|
||||
@@ -137,41 +149,44 @@ namespace ArachnaeSwarm
|
||||
base.EquipmentSource.GetComp<CompApparelReloadable>()?.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[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);
|
||||
this.ApplyChainDamage(this.chainedTargets[i], this.Props.secondaryDamageFactor);
|
||||
}
|
||||
|
||||
this.ticksToNextPathStep = this.verbProps.ticksBetweenBurstShots;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
foreach (MoteDualAttached m in chainMotes) { m.Destroy(); }
|
||||
chainMotes.Clear();
|
||||
endEffecter?.Cleanup();
|
||||
endEffecter = null;
|
||||
sustainer?.End();
|
||||
sustainer = null;
|
||||
chainedTargets.Clear();
|
||||
}
|
||||
|
||||
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;
|
||||
float angleFlat = (thing.Position - 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);
|
||||
dinfo = new DamageInfo(this.verbProps.beamDamageDef, damagePerShot * damageFactor, this.Props.beamArmorPenetration, 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);
|
||||
dinfo = new DamageInfo(this.verbProps.beamDamageDef, amount, this.Props.beamArmorPenetration, angleFlat, this.caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing);
|
||||
}
|
||||
|
||||
thing.TakeDamage(dinfo).AssociateWithLog(log);
|
||||
@@ -186,7 +201,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
else if (Rand.Chance(this.verbProps.beamChanceToStartFire))
|
||||
{
|
||||
FireUtility.TryStartFireIn(thing.Position, map, this.verbProps.beamFireSizeRange.RandomInRange, this.caster, this.verbProps.flammabilityAttachFireChanceCurve);
|
||||
FireUtility.TryStartFireIn(thing.Position, this.caster.Map, this.verbProps.beamFireSizeRange.RandomInRange, this.caster, this.verbProps.flammabilityAttachFireChanceCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
218
Source/ArachnaeSwarm/Verbs/Verb_ShootBeamSplitAndChain.cs
Normal file
218
Source/ArachnaeSwarm/Verbs/Verb_ShootBeamSplitAndChain.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
using Verse.Sound;
|
||||
using ArachnaeSwarm.Utils;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class VerbProperties_SplitAndChain : VerbProperties
|
||||
{
|
||||
public bool isSplit = false;
|
||||
public int splitNum;
|
||||
public float splitRange;
|
||||
public int conductNum;
|
||||
public float conductRange;
|
||||
public float splitDamageFactor = 0.8f;
|
||||
public float conductDamageFactor = 0.6f;
|
||||
public float beamArmorPenetration = 0f;
|
||||
public int beamPathSteps = 15;
|
||||
public float flecksPerCell = 2f; // Flecks per cell to control beam density
|
||||
|
||||
public FleckDef splitMoteDef;
|
||||
public FleckDef chainMoteDef;
|
||||
|
||||
public VerbProperties_SplitAndChain()
|
||||
{
|
||||
this.verbClass = typeof(Verb_ShootBeamSplitAndChain);
|
||||
}
|
||||
}
|
||||
|
||||
public class Verb_ShootBeamSplitAndChain : Verb
|
||||
{
|
||||
private VerbProperties_SplitAndChain Props => this.verbProps as VerbProperties_SplitAndChain;
|
||||
private Dictionary<Thing, List<Thing>> attackChains = new Dictionary<Thing, List<Thing>>();
|
||||
private Dictionary<Thing, Effecter> endEffecters = new Dictionary<Thing, Effecter>();
|
||||
private Sustainer sustainer;
|
||||
private int ticksToNextPathStep;
|
||||
|
||||
public override void WarmupComplete()
|
||||
{
|
||||
this.Cleanup();
|
||||
|
||||
List<Thing> mainTargets = new List<Thing>();
|
||||
if (!this.currentTarget.HasThing) { base.WarmupComplete(); return; }
|
||||
|
||||
Thing primaryTarget = this.currentTarget.Thing;
|
||||
if (primaryTarget is Pawn p_primary && (p_primary.Dead || p_primary.Downed)) return;
|
||||
|
||||
mainTargets.Add(primaryTarget);
|
||||
|
||||
if (this.Props.isSplit && this.Props.splitNum > 0)
|
||||
{
|
||||
var potentialTargets = GenRadial.RadialDistinctThingsAround(primaryTarget.Position, this.caster.Map, this.Props.splitRange, false)
|
||||
.OfType<Pawn>()
|
||||
.Where(p => !p.Dead && !p.Downed && p.HostileTo(this.caster.Faction) && !mainTargets.Contains(p) && GenSight.LineOfSight(primaryTarget.Position, p.Position, this.caster.Map, true))
|
||||
.OrderBy(p => p.Position.DistanceToSquared(primaryTarget.Position))
|
||||
.Take(this.Props.splitNum);
|
||||
|
||||
mainTargets.AddRange(potentialTargets);
|
||||
}
|
||||
|
||||
foreach (Thing mainTarget in mainTargets)
|
||||
{
|
||||
List<Thing> currentChain = new List<Thing>();
|
||||
currentChain.Add(mainTarget);
|
||||
|
||||
Thing lastTargetInChain = mainTarget;
|
||||
for (int i = 0; i < this.Props.conductNum; i++)
|
||||
{
|
||||
Thing nextInChain = GenRadial.RadialDistinctThingsAround(lastTargetInChain.Position, this.caster.Map, this.Props.conductRange, false)
|
||||
.OfType<Pawn>()
|
||||
.Where(p => !p.Dead && !p.Downed && !currentChain.Contains(p) && !mainTargets.Except(new[]{mainTarget}).Contains(p) && this.Caster.HostileTo(p) && GenSight.LineOfSight(lastTargetInChain.Position, p.Position, this.caster.Map, true))
|
||||
.OrderBy(p => p.Position.DistanceToSquared(lastTargetInChain.Position))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (nextInChain != null)
|
||||
{
|
||||
currentChain.Add(nextInChain);
|
||||
lastTargetInChain = nextInChain;
|
||||
}
|
||||
else { break; }
|
||||
}
|
||||
attackChains[mainTarget] = currentChain;
|
||||
}
|
||||
|
||||
this.burstShotsLeft = this.verbProps.burstShotCount;
|
||||
this.state = VerbState.Bursting;
|
||||
if (this.Props.soundCastBeam != null)
|
||||
{
|
||||
this.sustainer = this.Props.soundCastBeam.TrySpawnSustainer(SoundInfo.InMap(this.caster, MaintenanceType.PerTick));
|
||||
}
|
||||
base.TryCastNextBurstShot();
|
||||
}
|
||||
|
||||
public override void BurstingTick()
|
||||
{
|
||||
if (this.burstShotsLeft <= 0)
|
||||
{
|
||||
this.Cleanup();
|
||||
base.BurstingTick();
|
||||
return;
|
||||
}
|
||||
|
||||
List<Thing> deadOrInvalidChains = attackChains.Keys.Where(t => t == null || !t.Spawned).ToList();
|
||||
foreach (var key in deadOrInvalidChains)
|
||||
{
|
||||
if(endEffecters.ContainsKey(key))
|
||||
{
|
||||
endEffecters[key].Cleanup();
|
||||
endEffecters.Remove(key);
|
||||
}
|
||||
attackChains.Remove(key);
|
||||
}
|
||||
|
||||
Vector3 casterPos = this.caster.DrawPos;
|
||||
foreach (var chainEntry in attackChains)
|
||||
{
|
||||
Thing mainTarget = chainEntry.Key;
|
||||
List<Thing> conductTargets = chainEntry.Value;
|
||||
|
||||
DrawCurvedBeam(casterPos, mainTarget.DrawPos, Props.splitMoteDef ?? verbProps.beamLineFleckDef);
|
||||
|
||||
for (int i = 0; i < conductTargets.Count - 1; i++)
|
||||
{
|
||||
DrawCurvedBeam(conductTargets[i].DrawPos, conductTargets[i+1].DrawPos, Props.chainMoteDef ?? verbProps.beamLineFleckDef);
|
||||
}
|
||||
|
||||
foreach (Thing target in conductTargets)
|
||||
{
|
||||
if (!endEffecters.ContainsKey(target) || endEffecters[target] == null)
|
||||
{
|
||||
endEffecters[target] = verbProps.beamEndEffecterDef?.Spawn(target.Position, target.Map, Vector3.zero);
|
||||
}
|
||||
endEffecters[target]?.EffectTick(new TargetInfo(target), TargetInfo.Invalid);
|
||||
}
|
||||
}
|
||||
sustainer?.Maintain();
|
||||
}
|
||||
|
||||
protected override bool TryCastShot()
|
||||
{
|
||||
if (this.attackChains.NullOrEmpty()) return false;
|
||||
|
||||
bool anyDamaged = false;
|
||||
foreach (var chainEntry in attackChains)
|
||||
{
|
||||
Thing mainTarget = chainEntry.Key;
|
||||
List<Thing> conductTargets = chainEntry.Value;
|
||||
|
||||
ApplyDamage(mainTarget, Props.splitDamageFactor);
|
||||
anyDamaged = true;
|
||||
|
||||
for (int i = 1; i < conductTargets.Count; i++)
|
||||
{
|
||||
ApplyDamage(conductTargets[i], Props.conductDamageFactor);
|
||||
}
|
||||
}
|
||||
|
||||
this.ticksToNextPathStep = this.verbProps.ticksBetweenBurstShots;
|
||||
return anyDamaged;
|
||||
}
|
||||
|
||||
private void DrawCurvedBeam(Vector3 start, Vector3 end, FleckDef fleckDef)
|
||||
{
|
||||
if (fleckDef == null) return;
|
||||
|
||||
float magnitude = (end - start).MagnitudeHorizontal();
|
||||
if (magnitude <= 0) return;
|
||||
|
||||
// 1. Generate Bezier curve points
|
||||
int segments = Mathf.Max(3, Mathf.CeilToInt(magnitude * Props.flecksPerCell));
|
||||
|
||||
Vector3 controlPoint = Vector3.Lerp(start, end, 0.5f) + new Vector3(0, -magnitude * Props.beamCurvature, 0);
|
||||
var path = BezierUtil.GenerateQuadraticPoints(start, controlPoint, end, segments);
|
||||
// 2. Check if there are enough points to connect
|
||||
if (path.Count < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Iterate through adjacent point pairs and draw connecting lines
|
||||
for (int i = 0; i < path.Count - 1; i++)
|
||||
{
|
||||
Vector3 pointA = path[i];
|
||||
Vector3 pointB = path[i + 1];
|
||||
FleckMaker.ConnectingLine(pointA, pointB, fleckDef, this.caster.Map, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyDamage(Thing thing, float damageFactor)
|
||||
{
|
||||
if (thing == null || verbProps.beamDamageDef == null) return;
|
||||
|
||||
float totalDamage = verbProps.beamTotalDamage > 0 ? verbProps.beamTotalDamage / verbProps.burstShotCount : verbProps.beamDamageDef.defaultDamage;
|
||||
float finalDamage = totalDamage * damageFactor;
|
||||
|
||||
var dinfo = new DamageInfo(verbProps.beamDamageDef, finalDamage, Props.beamArmorPenetration, -1, this.caster, null, base.EquipmentSource.def);
|
||||
thing.TakeDamage(dinfo);
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
attackChains.Clear();
|
||||
foreach (var effecter in endEffecters.Values) effecter.Cleanup();
|
||||
endEffecters.Clear();
|
||||
sustainer?.End();
|
||||
sustainer = null;
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user