环形轰炸,区域监视,光矛扫射
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using UnityEngine;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompAbilityEffect_EnergyLance : CompAbilityEffect_WithDest
|
||||
{
|
||||
public new CompProperties_EnergyLance Props => (CompProperties_EnergyLance)props;
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
|
||||
// 计算光束的起点和方向
|
||||
IntVec3 startPos = target.Cell;
|
||||
IntVec3 endPos = dest.Cell;
|
||||
|
||||
// 如果使用固定距离,则从起点向终点方向移动固定距离
|
||||
if (Props.useFixedDistance)
|
||||
{
|
||||
Vector3 direction = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
Vector3 offset = direction * Props.moveDistance;
|
||||
endPos = startPos + new IntVec3(Mathf.RoundToInt(offset.x), 0, Mathf.RoundToInt(offset.z));
|
||||
}
|
||||
|
||||
// 创建移动的能量光束
|
||||
EnergyLance obj = (EnergyLance)GenSpawn.Spawn(ThingDef.Named("EnergyLance"), startPos, parent.pawn.Map);
|
||||
obj.duration = Props.durationTicks;
|
||||
obj.instigator = parent.pawn;
|
||||
obj.startPos = startPos;
|
||||
obj.endPos = endPos;
|
||||
obj.moveDistance = Props.moveDistance;
|
||||
obj.useFixedDistance = Props.useFixedDistance;
|
||||
obj.firesPerTick = Props.firesPerTick;
|
||||
// 不再需要传递伤害范围,因为现在从ModExtension读取
|
||||
obj.StartStrike();
|
||||
|
||||
Log.Message($"[EnergyLance] Created energy lance from {startPos} to {endPos}, distance: {Props.moveDistance}");
|
||||
}
|
||||
|
||||
// 绘制预览效果
|
||||
public override void DrawEffectPreview(LocalTargetInfo target)
|
||||
{
|
||||
base.DrawEffectPreview(target);
|
||||
|
||||
if (parent.pawn == null || parent.pawn.Map == null || !target.IsValid)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// 绘制起点预览
|
||||
GenDraw.DrawTargetHighlight(target.Cell);
|
||||
|
||||
// 如果选择了终点,绘制移动路径预览
|
||||
if (selectedTarget.IsValid)
|
||||
{
|
||||
DrawMovePathPreview(target.Cell, selectedTarget.Cell);
|
||||
}
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// 忽略预览绘制错误
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMovePathPreview(IntVec3 startPos, IntVec3 endPos)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算实际终点
|
||||
IntVec3 actualEndPos = endPos;
|
||||
if (Props.useFixedDistance)
|
||||
{
|
||||
Vector3 direction = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
Vector3 offset = direction * Props.moveDistance;
|
||||
actualEndPos = startPos + new IntVec3(Mathf.RoundToInt(offset.x), 0, Mathf.RoundToInt(offset.z));
|
||||
}
|
||||
|
||||
// 绘制移动路径
|
||||
Vector3 startVec = startPos.ToVector3Shifted();
|
||||
Vector3 endVec = actualEndPos.ToVector3Shifted();
|
||||
|
||||
GenDraw.DrawLineBetween(startVec, endVec, SimpleColor.Yellow, 0.2f);
|
||||
|
||||
// 绘制终点预览
|
||||
GenDraw.DrawTargetHighlight(actualEndPos);
|
||||
|
||||
// 绘制作用范围预览(在移动路径上)
|
||||
DrawEffectRangePreview(startPos, actualEndPos);
|
||||
}
|
||||
|
||||
private void DrawEffectRangePreview(IntVec3 startPos, IntVec3 endPos)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 沿着移动路径绘制作用范围
|
||||
Vector3 currentPos = startPos.ToVector3();
|
||||
Vector3 direction = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
float totalDistance = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
|
||||
float step = 1f; // 每格绘制
|
||||
|
||||
for (float distance = 0; distance <= totalDistance; distance += step)
|
||||
{
|
||||
Vector3 checkPos = startPos.ToVector3() + direction * distance;
|
||||
IntVec3 checkCell = new IntVec3(Mathf.RoundToInt(checkPos.x), 0, Mathf.RoundToInt(checkPos.z));
|
||||
|
||||
if (checkCell.InBounds(map))
|
||||
{
|
||||
// 绘制作用范围指示
|
||||
GenDraw.DrawRadiusRing(checkCell, 1.5f, Color.red, (c) => true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ExtraLabelMouseAttachment(LocalTargetInfo target)
|
||||
{
|
||||
string baseInfo = $"能量长矛: 持续{Props.durationTicks}刻";
|
||||
|
||||
if (Props.useFixedDistance)
|
||||
{
|
||||
baseInfo += $"\n移动距离: {Props.moveDistance}格";
|
||||
}
|
||||
|
||||
baseInfo += $"\n选择起点后,再选择移动方向";
|
||||
|
||||
return baseInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompProperties_EnergyLance : CompProperties_EffectWithDest
|
||||
{
|
||||
public int durationTicks = 600; // 光束持续时间
|
||||
public float moveDistance = 15f; // 光束移动距离
|
||||
public bool useFixedDistance = true; // 是否使用固定距离
|
||||
|
||||
// 伤害配置
|
||||
public int firesPerTick = 4; // 每刻产生的火焰数量
|
||||
public IntRange flameDamageRange = new IntRange(65, 100); // 火焰伤害范围
|
||||
public IntRange corpseFlameDamageRange = new IntRange(5, 10); // 尸体火焰伤害范围
|
||||
|
||||
public CompProperties_EnergyLance()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_EnergyLance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class EnergyLance : OrbitalStrike
|
||||
{
|
||||
// 移动相关属性
|
||||
public IntVec3 startPos;
|
||||
public IntVec3 endPos;
|
||||
public float moveDistance;
|
||||
public bool useFixedDistance;
|
||||
|
||||
// 伤害配置
|
||||
public int firesPerTick = 4;
|
||||
|
||||
// ModExtension引用
|
||||
private EnergyLanceExtension extension;
|
||||
|
||||
// 移动状态
|
||||
private Vector3 currentPos;
|
||||
private Vector3 moveDirection;
|
||||
private float moveSpeed;
|
||||
private float traveledDistance;
|
||||
private const float effectRadius = 3f; // 作用半径
|
||||
|
||||
private static List<Thing> tmpThings = new List<Thing>();
|
||||
|
||||
public override void StartStrike()
|
||||
{
|
||||
base.StartStrike();
|
||||
|
||||
// 获取ModExtension
|
||||
extension = def.GetModExtension<EnergyLanceExtension>();
|
||||
if (extension == null)
|
||||
{
|
||||
Log.Error($"[EnergyLance] No EnergyLanceExtension found on {def.defName}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化移动参数
|
||||
currentPos = startPos.ToVector3();
|
||||
|
||||
if (useFixedDistance)
|
||||
{
|
||||
// 从起点向终点方向移动固定距离
|
||||
Vector3 direction = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
moveDirection = direction;
|
||||
moveSpeed = moveDistance / duration; // 根据持续时间计算移动速度
|
||||
}
|
||||
else
|
||||
{
|
||||
// 直接从起点移动到终点
|
||||
Vector3 direction = (endPos.ToVector3() - startPos.ToVector3());
|
||||
moveDirection = direction.normalized;
|
||||
moveSpeed = direction.magnitude / duration;
|
||||
}
|
||||
|
||||
traveledDistance = 0f;
|
||||
|
||||
// 创建视觉效果
|
||||
CreateVisualEffect();
|
||||
|
||||
Log.Message($"[EnergyLance] Strike started from {startPos} to {endPos}, " +
|
||||
$"damage: {extension.damageDef.defName}, speed: {moveSpeed}");
|
||||
}
|
||||
|
||||
private void CreateVisualEffect()
|
||||
{
|
||||
// 使用ModExtension中定义的Mote,如果没有则使用默认的PowerBeam
|
||||
if (extension.moteDef != null)
|
||||
{
|
||||
Mote mote = MoteMaker.MakeStaticMote(base.Position, base.Map, extension.moteDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 使用原版PowerBeam的视觉效果
|
||||
MoteMaker.MakePowerBeamMote(base.Position, base.Map);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
|
||||
if (!base.Destroyed && extension != null)
|
||||
{
|
||||
// 移动光束
|
||||
MoveBeam();
|
||||
|
||||
// 造成伤害
|
||||
for (int i = 0; i < firesPerTick; i++)
|
||||
{
|
||||
DoBeamDamage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveBeam()
|
||||
{
|
||||
// 计算移动距离
|
||||
float moveThisTick = moveSpeed;
|
||||
|
||||
// 更新位置
|
||||
currentPos += moveDirection * moveThisTick;
|
||||
traveledDistance += moveThisTick;
|
||||
|
||||
// 更新光束的实际位置
|
||||
IntVec3 newCell = new IntVec3(Mathf.RoundToInt(currentPos.x), 0, Mathf.RoundToInt(currentPos.z));
|
||||
if (newCell != base.Position && newCell.InBounds(base.Map))
|
||||
{
|
||||
base.Position = newCell;
|
||||
}
|
||||
|
||||
// 检查是否到达终点
|
||||
if (useFixedDistance && traveledDistance >= moveDistance)
|
||||
{
|
||||
// 固定距离模式:移动指定距离后结束
|
||||
Destroy();
|
||||
Log.Message($"[EnergyLance] Reached fixed distance, destroying");
|
||||
}
|
||||
else if (!useFixedDistance && traveledDistance >= Vector3.Distance(startPos.ToVector3(), endPos.ToVector3()))
|
||||
{
|
||||
// 终点模式:到达终点后结束
|
||||
Destroy();
|
||||
Log.Message($"[EnergyLance] Reached end position, destroying");
|
||||
}
|
||||
}
|
||||
|
||||
private void DoBeamDamage()
|
||||
{
|
||||
if (extension == null) return;
|
||||
|
||||
// 在当前光束位置周围随机选择一个单元格
|
||||
IntVec3 targetCell = (from x in GenRadial.RadialCellsAround(base.Position, effectRadius, useCenter: true)
|
||||
where x.InBounds(base.Map)
|
||||
select x).RandomElementByWeight((IntVec3 x) => 1f - Mathf.Min(x.DistanceTo(base.Position) / effectRadius, 1f) + 0.05f);
|
||||
|
||||
// 尝试在该单元格点火(如果配置了点火)
|
||||
if (extension.igniteFires)
|
||||
{
|
||||
FireUtility.TryStartFireIn(targetCell, base.Map, Rand.Range(0.1f, extension.fireIgniteChance), instigator);
|
||||
}
|
||||
|
||||
// 对该单元格内的物体造成伤害
|
||||
tmpThings.Clear();
|
||||
tmpThings.AddRange(targetCell.GetThingList(base.Map));
|
||||
|
||||
for (int i = 0; i < tmpThings.Count; i++)
|
||||
{
|
||||
Thing thing = tmpThings[i];
|
||||
|
||||
// 检查是否对尸体造成伤害
|
||||
if (!extension.applyDamageToCorpses && thing is Corpse)
|
||||
continue;
|
||||
|
||||
// 计算伤害量
|
||||
int damageAmount = (thing is Corpse) ?
|
||||
extension.corpseDamageAmountRange.RandomInRange :
|
||||
extension.damageAmountRange.RandomInRange;
|
||||
|
||||
Pawn pawn = thing as Pawn;
|
||||
BattleLogEntry_DamageTaken battleLogEntry = null;
|
||||
|
||||
if (pawn != null)
|
||||
{
|
||||
battleLogEntry = new BattleLogEntry_DamageTaken(pawn, RulePackDefOf.DamageEvent_PowerBeam, instigator as Pawn);
|
||||
Find.BattleLog.Add(battleLogEntry);
|
||||
}
|
||||
|
||||
// 使用ModExtension中定义的伤害类型
|
||||
DamageInfo damageInfo = new DamageInfo(extension.damageDef, damageAmount, 0f, -1f, instigator, null, weaponDef);
|
||||
thing.TakeDamage(damageInfo).AssociateWithLog(battleLogEntry);
|
||||
|
||||
Log.Message($"[EnergyLance] Applied {extension.damageDef.defName} damage {damageAmount} to {thing.Label}");
|
||||
}
|
||||
|
||||
tmpThings.Clear();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Values.Look(ref startPos, "startPos");
|
||||
Scribe_Values.Look(ref endPos, "endPos");
|
||||
Scribe_Values.Look(ref moveDistance, "moveDistance");
|
||||
Scribe_Values.Look(ref useFixedDistance, "useFixedDistance");
|
||||
Scribe_Values.Look(ref firesPerTick, "firesPerTick", 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class EnergyLanceExtension : DefModExtension
|
||||
{
|
||||
// 伤害类型配置
|
||||
public DamageDef damageDef = DamageDefOf.Flame; // 伤害类型,默认为火焰伤害
|
||||
public bool applyDamageToCorpses = true; // 是否对尸体造成伤害
|
||||
public bool igniteFires = true; // 是否点燃火焰
|
||||
public float fireIgniteChance = 0.8f; // 点燃火焰的概率
|
||||
|
||||
// 伤害量配置
|
||||
public IntRange damageAmountRange = new IntRange(65, 100); // 对生物的伤害范围
|
||||
public IntRange corpseDamageAmountRange = new IntRange(5, 10); // 对尸体的伤害范围
|
||||
|
||||
// 视觉效果配置
|
||||
public ThingDef moteDef; // 使用的Mote类型
|
||||
public SoundDef impactSound; // 撞击音效
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user