暂存z
This commit is contained in:
Binary file not shown.
86
1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Laser.xml
Normal file
86
1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Laser.xml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<!-- 暗物质步枪 (已修改为电弧链式攻击) -->
|
||||||
|
<ThingDef ParentName="BaseHumanMakeableGun">
|
||||||
|
<defName>WULA_RW_DM_AR_Arc</defName>
|
||||||
|
<label>DMa-8 "陨硫" (电弧型)</label>
|
||||||
|
<description>乌拉帝国一线部队所使用的由暗物质驱动的常规步枪的改造版。现在它发射的能量束会在命中后寻找并跳跃到附近的其他敌人身上,形成致命的能量链。</description>
|
||||||
|
<techLevel>Ultra</techLevel>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Wula/Weapon/WULA_RW_DM_AR</texPath>
|
||||||
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<drawSize>1.2</drawSize>
|
||||||
|
</graphicData>
|
||||||
|
<weaponTags>
|
||||||
|
<li>Wula_Ranged_Weapon_T4</li>
|
||||||
|
</weaponTags>
|
||||||
|
<uiIconScale>0.9</uiIconScale>
|
||||||
|
<soundInteract>Interact_ChargeRifle</soundInteract>
|
||||||
|
<recipeMaker>
|
||||||
|
<recipeUsers Inherit="False">
|
||||||
|
<li>WULA_Cube_Productor_Energy</li>
|
||||||
|
</recipeUsers>
|
||||||
|
<researchPrerequisite>WULA_Synth_Weapon_4_DM_Base_Technology</researchPrerequisite>
|
||||||
|
<unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef>
|
||||||
|
</recipeMaker>
|
||||||
|
<costList Inherit="False">
|
||||||
|
<Steel>400</Steel>
|
||||||
|
<Plasteel>200</Plasteel>
|
||||||
|
<WULA_Dark_Matter_Item>4</WULA_Dark_Matter_Item>
|
||||||
|
</costList>
|
||||||
|
<statBases>
|
||||||
|
<WorkToMake>40000</WorkToMake>
|
||||||
|
<Mass>4.5</Mass>
|
||||||
|
<AccuracyTouch>1</AccuracyTouch>
|
||||||
|
<AccuracyShort>1</AccuracyShort>
|
||||||
|
<AccuracyMedium>1</AccuracyMedium>
|
||||||
|
<AccuracyLong>1</AccuracyLong>
|
||||||
|
<RangedWeapon_Cooldown>1.25</RangedWeapon_Cooldown>
|
||||||
|
</statBases>
|
||||||
|
<verbs>
|
||||||
|
<li Class="ArachnaeSwarm.VerbProperties_BeamArc">
|
||||||
|
<verbClass>ArachnaeSwarm.Verb_ShootBeamArc</verbClass>
|
||||||
|
|
||||||
|
<!-- 基础射线参数 -->
|
||||||
|
<hasStandardCommand>true</hasStandardCommand>
|
||||||
|
<warmupTime>1</warmupTime>
|
||||||
|
<range>36</range>
|
||||||
|
<burstShotCount>6</burstShotCount>
|
||||||
|
<ticksBetweenBurstShots>10</ticksBetweenBurstShots>
|
||||||
|
<beamDamageDef>Wula_Dark_Matter_Beam</beamDamageDef>
|
||||||
|
<beamTotalDamage>90</beamTotalDamage>
|
||||||
|
|
||||||
|
<!-- 视觉和音效 -->
|
||||||
|
<muzzleFlashScale>0</muzzleFlashScale>
|
||||||
|
<soundCastBeam>BeamGraser_Shooting</soundCastBeam>
|
||||||
|
<beamGroundFleckDef>Fleck_BeamBurn</beamGroundFleckDef>
|
||||||
|
<beamFleckChancePerTick>0.32</beamFleckChancePerTick>
|
||||||
|
<beamMoteDef>Mote_Wula_Dark_Matter_Beam</beamMoteDef>
|
||||||
|
<beamEndEffecterDef>GraserBeam_End</beamEndEffecterDef>
|
||||||
|
<screenShakeFactor>0.35</screenShakeFactor>
|
||||||
|
|
||||||
|
<!-- 火焰效果 -->
|
||||||
|
<beamChanceToStartFire>0.6</beamChanceToStartFire>
|
||||||
|
<beamChanceToAttachFire>0.6</beamChanceToAttachFire>
|
||||||
|
<beamFireSizeRange>0.25</beamFireSizeRange>
|
||||||
|
|
||||||
|
<!-- 攻击目标设置 -->
|
||||||
|
<targetParams>
|
||||||
|
<canTargetLocations>true</canTargetLocations>
|
||||||
|
</targetParams>
|
||||||
|
|
||||||
|
<!-- 电弧链属性 -->
|
||||||
|
<conductNum>4</conductNum>
|
||||||
|
<conductRange>30</conductRange>
|
||||||
|
<secondaryDamageFactor>0.7</secondaryDamageFactor>
|
||||||
|
<chainMoteDef>Mote_Wula_Dark_Matter_Beam</chainMoteDef>
|
||||||
|
</li>
|
||||||
|
</verbs>
|
||||||
|
<tradeability>None</tradeability>
|
||||||
|
<thingSetMakerTags>
|
||||||
|
<li>RewardStandardQualitySuper</li>
|
||||||
|
</thingSetMakerTags>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
</Defs>
|
||||||
@@ -233,6 +233,7 @@
|
|||||||
<Compile Include="Verbs\Projectiles\Projectile_WulaPenetratingBullet.cs" />
|
<Compile Include="Verbs\Projectiles\Projectile_WulaPenetratingBullet.cs" />
|
||||||
<Compile Include="Verbs\Projectiles\TrackingBulletDef.cs" />
|
<Compile Include="Verbs\Projectiles\TrackingBulletDef.cs" />
|
||||||
<Compile Include="Verbs\Verb_ShootArc.cs" />
|
<Compile Include="Verbs\Verb_ShootArc.cs" />
|
||||||
|
<Compile Include="Verbs\Verb_ShootBeamArc.cs" />
|
||||||
<Compile Include="Verbs\Verb_ShootMeltBeam.cs" />
|
<Compile Include="Verbs\Verb_ShootMeltBeam.cs" />
|
||||||
<Compile Include="Verbs\Verb_ShootShotgun.cs" />
|
<Compile Include="Verbs\Verb_ShootShotgun.cs" />
|
||||||
<Compile Include="Verbs\Verb_ShootShotgunWithOffset.cs" />
|
<Compile Include="Verbs\Verb_ShootShotgunWithOffset.cs" />
|
||||||
|
|||||||
193
Source/ArachnaeSwarm/Verbs/Verb_ShootBeamArc.cs
Normal file
193
Source/ArachnaeSwarm/Verbs/Verb_ShootBeamArc.cs
Normal file
@@ -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<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();
|
||||||
|
|
||||||
|
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<CompChangeableProjectile>()?.Notify_ProjectileLaunched();
|
||||||
|
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[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user