This commit is contained in:
Tourswen
2025-08-04 23:26:48 +08:00
5 changed files with 360 additions and 0 deletions

Binary file not shown.

View File

@@ -1,4 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<AbilityDef>
<defName>WULA_LightningBombardment</defName>
<label>LightningStorm</label>
<description>Summon a LightningStorm.</description>
<iconPath>UI/Abilities/Flashstorm</iconPath>
<cooldownTicksRange>60000</cooldownTicksRange>
<sendMessageOnCooldownComplete>true</sendMessageOnCooldownComplete>
<aiCanUse>true</aiCanUse>
<casterMustBeCapableOfViolence>false</casterMustBeCapableOfViolence>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<label>Summon LightningStorm</label>
<drawAimPie>true</drawAimPie>
<warmupTime>1</warmupTime>
<range>29.9</range>
<targetParams>
<canTargetPawns>False</canTargetPawns>
<canTargetLocations>True</canTargetLocations>
</targetParams>
</verbProperties>
<comps>
<li Class="WulaFallenEmpire.CompProperties_AbilityDRM_LightningBombardment">
<impactAreaRadius>12</impactAreaRadius>
<explosionRadiusRange>3~4</explosionRadiusRange>
<bombIntervalTicks>30</bombIntervalTicks>
<explosionCount>20</explosionCount>
<damageDef>Wula_Psi_Damage</damageDef>
<damageAmount>45</damageAmount>
<armorPenetration>1.0</armorPenetration>
</li>
</comps>
</AbilityDef>
</Defs>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<HediffDef>
<defName>WULA_SwiftHunterBlessing</defName>
<label>迅捷猎手加护</label>
<description>受到一种神秘力量的加护,身体变得更加轻盈,感官更加敏锐。</description>
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.8, 1.0)</defaultLabelColor>
<isBad>false</isBad>
<stages>
<li>
<statOffsets>
<MoveSpeed>1.0</MoveSpeed>
<GlobalWorkSpeed>0.25</GlobalWorkSpeed>
</statOffsets>
<statFactors>
<AimingTime>0.8</AimingTime>
<MeleeWeapon_CooldownMultiplier>0.8</MeleeWeapon_CooldownMultiplier>
</statFactors>
</li>
</stages>
</HediffDef>
</Defs>

View File

@@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace WulaFallenEmpire
{
public class CompAbilityEffect_DRM_LightningBombardment : CompAbilityEffect
{
public new CompProperties_AbilityDRM_LightningBombardment Props
{
get => (CompProperties_AbilityDRM_LightningBombardment)props;
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Map map = parent.pawn.MapHeld;
// 获取或创建地图组件
MapComponent_LightningBombardment comp = GetOrCreateMapComponent(map);
// 启动轰炸任务
comp.StartBombardment(
target: target.Cell,
instigator: parent.pawn,
explosionCount: Props.explosionCount,
bombIntervalTicks: Props.bombIntervalTicks,
impactAreaRadius: Props.impactAreaRadius,
explosionRadiusRange: Props.explosionRadiusRange,
damageDef: Props.damageDef,
damageAmount: Props.damageAmount,
armorPenetration: Props.armorPenetration,
postExplosionSpawnThingDef: Props.postExplosionSpawnThingDef,
postExplosionSpawnChance: Props.postExplosionSpawnChance,
postExplosionSpawnThingCount: Props.postExplosionSpawnThingCount
);
// 播放启动音效
SoundDefOf.Thunder_OffMap.PlayOneShotOnCamera(map);
}
private MapComponent_LightningBombardment GetOrCreateMapComponent(Map map)
{
MapComponent_LightningBombardment comp = map.GetComponent<MapComponent_LightningBombardment>();
if (comp == null)
{
comp = new MapComponent_LightningBombardment(map);
map.components.Add(comp);
}
return comp;
}
public override void DrawEffectPreview(LocalTargetInfo target)
{
// 显示施法范围
float castingRange = parent.verb.verbProps.range;
GenDraw.DrawRadiusRing(parent.pawn.Position, castingRange, Color.white);
// 显示爆炸作用范围
GenDraw.DrawRadiusRing(target.Cell, Props.impactAreaRadius, Color.white);
if (target.IsValid) GenDraw.DrawTargetHighlight(target);
}
}
public class CompProperties_AbilityDRM_LightningBombardment : CompProperties_AbilityEffect
{
public CompProperties_AbilityDRM_LightningBombardment()
{
compClass = typeof(CompAbilityEffect_DRM_LightningBombardment);
}
public float impactAreaRadius = 10f;
public FloatRange explosionRadiusRange = new FloatRange(3f, 4f);
public int bombIntervalTicks = 30;
public int explosionCount = 3;
public DamageDef damageDef;
public int damageAmount = 30;
public float armorPenetration = 0.8f;
public ThingDef postExplosionSpawnThingDef;
public float postExplosionSpawnChance;
public int postExplosionSpawnThingCount;
}
// 地图组件管理轰炸任务
public class MapComponent_LightningBombardment : MapComponent
{
private readonly List<BombardmentCoroutine> activeCoroutines = new List<BombardmentCoroutine>();
private const int MAX_CONCURRENT_BOMBARDMENTS = 5;
public MapComponent_LightningBombardment(Map map) : base(map) { }
public void StartBombardment(
IntVec3 target,
Pawn instigator,
int explosionCount,
int bombIntervalTicks,
float impactAreaRadius,
FloatRange explosionRadiusRange,
DamageDef damageDef,
int damageAmount,
float armorPenetration,
ThingDef postExplosionSpawnThingDef,
float postExplosionSpawnChance,
int postExplosionSpawnThingCount)
{
// 防止过多任务影响性能
if (activeCoroutines.Count >= MAX_CONCURRENT_BOMBARDMENTS)
{
Log.Warning($"Too many concurrent bombardments on map {map}, max is {MAX_CONCURRENT_BOMBARDMENTS}");
return;
}
activeCoroutines.Add(new BombardmentCoroutine(
target: target,
map: map,
instigator: instigator,
explosionCount: explosionCount,
bombIntervalTicks: bombIntervalTicks,
impactAreaRadius: impactAreaRadius,
explosionRadiusRange: explosionRadiusRange,
damageDef: damageDef,
damageAmount: damageAmount,
armorPenetration: armorPenetration,
postExplosionSpawnThingDef: postExplosionSpawnThingDef,
postExplosionSpawnChance: postExplosionSpawnChance,
postExplosionSpawnThingCount: postExplosionSpawnThingCount
));
}
public override void MapComponentTick()
{
try
{
for (int i = activeCoroutines.Count - 1; i >= 0; i--)
{
if (!activeCoroutines[i].Tick())
{
activeCoroutines.RemoveAt(i);
}
}
}
catch (Exception ex)
{
Log.Error($"Lightning bombardment error: {ex}");
activeCoroutines.Clear();
}
}
}
[StaticConstructorOnStartup]
// 轰炸任务协程
public class BombardmentCoroutine
{
private readonly IntVec3 target;
private readonly Map map;
private readonly Pawn instigator;
private readonly int explosionCount;
private readonly FloatRange explosionRadiusRange;
private readonly float impactAreaRadius;
private readonly int bombIntervalTicks;
public DamageDef damageDef;
public int damageAmount;
public float armorPenetration;
public ThingDef postExplosionSpawnThingDef;
public float postExplosionSpawnChance;
public int postExplosionSpawnThingCount;
private int nextBombTick;
private int explosionsRemaining;
private static readonly Material LightningMat = MatLoader.LoadMat("Weather/LightningBolt", -1);
public BombardmentCoroutine(
IntVec3 target,
Map map,
Pawn instigator,
int explosionCount,
int bombIntervalTicks,
float impactAreaRadius,
FloatRange explosionRadiusRange,
DamageDef damageDef,
int damageAmount,
float armorPenetration,
ThingDef postExplosionSpawnThingDef,
float postExplosionSpawnChance,
int postExplosionSpawnThingCount)
{
this.target = target;
this.map = map;
this.instigator = instigator;
this.explosionCount = explosionCount;
this.bombIntervalTicks = bombIntervalTicks;
this.impactAreaRadius = impactAreaRadius;
this.explosionRadiusRange = explosionRadiusRange;
this.damageDef = damageDef;
this.damageAmount = damageAmount;
this.armorPenetration = armorPenetration;
this.postExplosionSpawnThingDef = postExplosionSpawnThingDef;
this.postExplosionSpawnChance = postExplosionSpawnChance;
this.postExplosionSpawnThingCount = postExplosionSpawnThingCount;
explosionsRemaining = explosionCount;
nextBombTick = Find.TickManager.TicksGame + bombIntervalTicks;
}
public bool Tick()
{
if (Find.TickManager.TicksGame >= nextBombTick)
{
ExecuteBomb();
explosionsRemaining--;
if (explosionsRemaining > 0)
{
nextBombTick += bombIntervalTicks;
}
}
return explosionsRemaining > 0;
}
private void ExecuteBomb()
{
// 在轰炸区域内随机选择目标点
IntVec3 bombTarget = GetRandomCellInRadius(target, map, impactAreaRadius);
// 创建闪电视觉效果
CreateLightningEffect(bombTarget);
// 执行爆炸
GenExplosion.DoExplosion(
center: bombTarget,
map: map,
radius: explosionRadiusRange.RandomInRange,
damType: damageDef,
instigator: instigator,
damAmount: damageAmount,
armorPenetration: armorPenetration,
postExplosionSpawnThingDef: postExplosionSpawnThingDef,
postExplosionSpawnChance: postExplosionSpawnChance,
postExplosionSpawnThingCount: postExplosionSpawnThingCount,
applyDamageToExplosionCellsNeighbors: true,
chanceToStartFire: 0.4f,
damageFalloff: true
);
}
private IntVec3 GetRandomCellInRadius(IntVec3 center, Map map, float radius)
{
if (radius <= 0.0f) return center;
if (CellFinder.TryFindRandomCellNear(
center,
map,
Mathf.CeilToInt(radius),
c => c.DistanceTo(center) <= radius && c.Standable(map),
out IntVec3 result))
{
return result;
}
return center; // 备用方案
}
private void CreateLightningEffect(IntVec3 strikeLoc)
{
if (strikeLoc.Fogged(map)) return;
Vector3 position = strikeLoc.ToVector3Shifted();
// 1. 播放声音
SoundDefOf.Thunder_OffMap.PlayOneShotOnCamera(map);
// 2. 生成粒子效果
for (int i = 0; i < 4; i++)
{
FleckMaker.ThrowSmoke(position, map, 1.5f);
FleckMaker.ThrowMicroSparks(position, map);
FleckMaker.ThrowLightningGlow(position, map, 1.5f);
}
// 3. 绘制闪电网格
Mesh boltMesh = LightningBoltMeshPool.RandomBoltMesh;
Graphics.DrawMesh(
boltMesh,
strikeLoc.ToVector3ShiftedWithAltitude(AltitudeLayer.Weather),
Quaternion.identity,
FadedMaterialPool.FadedVersionOf(LightningMat, 1f),
0
);
// 4. 播放局部雷声
SoundInfo soundInfo = SoundInfo.InMap(new TargetInfo(strikeLoc, map));
SoundDefOf.Thunder_OnMap.PlayOneShot(soundInfo);
}
}
}

View File

@@ -101,6 +101,7 @@
<Compile Include="JobGiver_WulaGetEnergy.cs" />
<Compile Include="JobGiver_WulaPackEnergy.cs" />
<Compile Include="JobGiverDefExtension_WulaPackEnergy.cs" />
<Compile Include="LightningBombardment.cs" />
<Compile Include="MechanitorPatch.cs" />
<Compile Include="MentalBreakWorker_BrokenPersonality.cs" />
<Compile Include="MentalState_BrokenPersonality.cs" />