1
This commit is contained in:
@@ -15,22 +15,22 @@ namespace WulaFallenEmpire
|
||||
public IntVec3 endPosition;
|
||||
public float moveDistance;
|
||||
public bool useFixedDistance;
|
||||
public float flightSpeed = 1f;
|
||||
public float flightSpeed = 0.5f; // 提高移动速度
|
||||
public float currentProgress = 0f;
|
||||
public float altitude = 20f;
|
||||
|
||||
|
||||
// 伤害配置
|
||||
public int firesPerTick = 4;
|
||||
public float effectRadius = 15f;
|
||||
public int durationTicks = 600;
|
||||
private int ticksPassed = 0;
|
||||
|
||||
|
||||
// 移动状态
|
||||
private Vector3 exactPosition;
|
||||
private Vector3 moveDirection;
|
||||
private bool hasStarted = false;
|
||||
private bool hasCompleted = false;
|
||||
|
||||
|
||||
// 视觉效果
|
||||
private CompOrbitalBeam orbitalBeamComp;
|
||||
private Sustainer sustainer;
|
||||
@@ -42,11 +42,194 @@ namespace WulaFallenEmpire
|
||||
public Thing instigator;
|
||||
public ThingDef weaponDef;
|
||||
|
||||
// 精确位置计算(基于FlyOver的逻辑)
|
||||
// 动态目标追踪支持
|
||||
private IntVec3 currentTargetPosition = IntVec3.Invalid;
|
||||
private bool hasValidTarget = false;
|
||||
private int lastTargetUpdateTick = 0;
|
||||
private int maxIdleTicks = 180; // 3秒无目标更新后自毁
|
||||
|
||||
// 移动模式
|
||||
private bool useDynamicMovement = true; // 使用动态追踪模式
|
||||
|
||||
// 更新目标位置
|
||||
public void UpdateTargetPosition(IntVec3 targetPos)
|
||||
{
|
||||
if (targetPos.IsValid)
|
||||
{
|
||||
currentTargetPosition = targetPos;
|
||||
hasValidTarget = true;
|
||||
lastTargetUpdateTick = Find.TickManager.TicksGame;
|
||||
|
||||
// 如果是首次设置目标,立即移动到目标位置
|
||||
if (!hasStarted)
|
||||
{
|
||||
exactPosition = targetPos.ToVector3();
|
||||
exactPosition.y = altitude;
|
||||
base.Position = targetPos;
|
||||
hasStarted = true;
|
||||
}
|
||||
|
||||
Log.Message($"[EnergyLance] Target updated to: {targetPos}, current position: {base.Position}");
|
||||
}
|
||||
else
|
||||
{
|
||||
hasValidTarget = false;
|
||||
Log.Message("[EnergyLance] Target cleared");
|
||||
}
|
||||
}
|
||||
|
||||
// 动态移动逻辑 - 直接追踪目标
|
||||
private void UpdateDynamicMovement()
|
||||
{
|
||||
if (hasValidTarget && currentTargetPosition.IsValid)
|
||||
{
|
||||
Vector3 targetVector = currentTargetPosition.ToVector3();
|
||||
targetVector.y = altitude; // 保持高度
|
||||
|
||||
Vector3 currentVector = exactPosition;
|
||||
|
||||
// 计算移动方向
|
||||
Vector3 direction = (targetVector - currentVector).normalized;
|
||||
|
||||
// 计算移动距离(基于速度)
|
||||
float moveThisTick = flightSpeed * 0.1f;
|
||||
|
||||
// 更新位置
|
||||
exactPosition += direction * moveThisTick;
|
||||
|
||||
// 更新格子位置
|
||||
IntVec3 newCell = new IntVec3(
|
||||
Mathf.RoundToInt(exactPosition.x),
|
||||
Mathf.RoundToInt(exactPosition.y),
|
||||
Mathf.RoundToInt(exactPosition.z)
|
||||
);
|
||||
|
||||
if (newCell != base.Position && newCell.InBounds(base.Map))
|
||||
{
|
||||
base.Position = newCell;
|
||||
Log.Message($"[EnergyLance] Moved to new cell: {newCell}");
|
||||
}
|
||||
|
||||
// 检查是否接近目标
|
||||
float distanceToTarget = Vector3.Distance(currentVector, targetVector);
|
||||
if (distanceToTarget < 0.5f)
|
||||
{
|
||||
// 非常接近目标,直接设置到目标位置
|
||||
exactPosition = targetVector;
|
||||
base.Position = currentTargetPosition;
|
||||
Log.Message($"[EnergyLance] Reached target position: {currentTargetPosition}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有有效目标,使用原始移动逻辑
|
||||
UpdateOriginalMovement();
|
||||
}
|
||||
}
|
||||
|
||||
// 原始移动逻辑(从起点到终点的线性移动)
|
||||
private void UpdateOriginalMovement()
|
||||
{
|
||||
float totalDistance = useFixedDistance ? moveDistance : Vector3.Distance(startPosition.ToVector3(), endPosition.ToVector3());
|
||||
float progressPerTick = 1f / durationTicks;
|
||||
currentProgress += progressPerTick;
|
||||
currentProgress = Mathf.Clamp01(currentProgress);
|
||||
|
||||
exactPosition = Vector3.Lerp(startPosition.ToVector3(), CalculateEndPosition(), currentProgress);
|
||||
exactPosition.y = altitude;
|
||||
|
||||
IntVec3 newCell = new IntVec3(
|
||||
Mathf.RoundToInt(exactPosition.x),
|
||||
Mathf.RoundToInt(exactPosition.y),
|
||||
Mathf.RoundToInt(exactPosition.z)
|
||||
);
|
||||
|
||||
if (newCell != base.Position && newCell.InBounds(base.Map))
|
||||
{
|
||||
base.Position = newCell;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
|
||||
if (!hasStarted || hasCompleted)
|
||||
return;
|
||||
|
||||
ticksPassed++;
|
||||
|
||||
// 添加保护期检查 - 防止光束立即销毁
|
||||
if (ticksPassed < 5)
|
||||
{
|
||||
// 只更新移动,不检查销毁
|
||||
UpdateDynamicMovement();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否长时间没有收到目标更新
|
||||
if (hasValidTarget && Find.TickManager.TicksGame - lastTargetUpdateTick > maxIdleTicks)
|
||||
{
|
||||
Log.Message("[EnergyLance] No target updates received, self-destructing");
|
||||
CompleteEnergyLance();
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新移动
|
||||
UpdateDynamicMovement();
|
||||
|
||||
// 造成伤害
|
||||
for (int i = 0; i < firesPerTick; i++)
|
||||
{
|
||||
StartRandomFireAndDoFlameDamage();
|
||||
}
|
||||
|
||||
// 更新音效
|
||||
sustainer?.Maintain();
|
||||
|
||||
// 检查是否完成
|
||||
if (ticksPassed >= durationTicks || (!hasValidTarget && currentProgress >= 1f))
|
||||
{
|
||||
CompleteEnergyLance();
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteEnergyLance()
|
||||
{
|
||||
hasCompleted = true;
|
||||
|
||||
// 停止音效
|
||||
sustainer?.End();
|
||||
sustainer = null;
|
||||
|
||||
Log.Message($"[EnergyLance] 光束完成 at position {base.Position}, ticksPassed: {ticksPassed}, durationTicks: {durationTicks}");
|
||||
|
||||
// 销毁自身
|
||||
Destroy();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Values.Look(ref currentTargetPosition, "currentTargetPosition");
|
||||
Scribe_Values.Look(ref hasValidTarget, "hasValidTarget", false);
|
||||
Scribe_Values.Look(ref lastTargetUpdateTick, "lastTargetUpdateTick", 0);
|
||||
Scribe_Values.Look(ref maxIdleTicks, "maxIdleTicks", 180);
|
||||
Scribe_Values.Look(ref useDynamicMovement, "useDynamicMovement", true);
|
||||
}
|
||||
|
||||
// 精确位置计算
|
||||
public override Vector3 DrawPos
|
||||
{
|
||||
get
|
||||
{
|
||||
if (exactPosition != Vector3.zero)
|
||||
{
|
||||
return exactPosition;
|
||||
}
|
||||
|
||||
// 备用计算
|
||||
Vector3 start = startPosition.ToVector3();
|
||||
Vector3 end = CalculateEndPosition();
|
||||
Vector3 basePos = Vector3.Lerp(start, end, currentProgress);
|
||||
@@ -74,7 +257,15 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 direction = (CalculateEndPosition() - startPosition.ToVector3()).normalized;
|
||||
Vector3 direction;
|
||||
if (hasValidTarget && currentTargetPosition.IsValid)
|
||||
{
|
||||
direction = (currentTargetPosition.ToVector3() - exactPosition).normalized;
|
||||
}
|
||||
else
|
||||
{
|
||||
direction = (CalculateEndPosition() - startPosition.ToVector3()).normalized;
|
||||
}
|
||||
return Quaternion.LookRotation(direction.Yto0());
|
||||
}
|
||||
}
|
||||
@@ -82,30 +273,42 @@ namespace WulaFallenEmpire
|
||||
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||
{
|
||||
base.SpawnSetup(map, respawningAfterLoad);
|
||||
|
||||
|
||||
orbitalBeamComp = GetComp<CompOrbitalBeam>();
|
||||
|
||||
|
||||
if (!respawningAfterLoad)
|
||||
{
|
||||
base.Position = startPosition;
|
||||
// 初始位置设置为目标位置(如果有效),否则使用起始位置
|
||||
if (endPosition.IsValid)
|
||||
{
|
||||
base.Position = endPosition;
|
||||
exactPosition = endPosition.ToVector3();
|
||||
exactPosition.y = altitude;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Position = startPosition;
|
||||
exactPosition = startPosition.ToVector3();
|
||||
exactPosition.y = altitude;
|
||||
}
|
||||
|
||||
hasStarted = true;
|
||||
|
||||
|
||||
// 计算移动方向
|
||||
Vector3 endPos = CalculateEndPosition();
|
||||
moveDirection = (endPos - startPosition.ToVector3()).normalized;
|
||||
|
||||
|
||||
// 初始化光束组件
|
||||
if (orbitalBeamComp != null)
|
||||
{
|
||||
// 使用反射调用StartAnimation方法
|
||||
StartOrbitalBeamAnimation();
|
||||
}
|
||||
|
||||
|
||||
// 开始音效
|
||||
StartSound();
|
||||
|
||||
Log.Message($"[EnergyLance] Spawned at {startPosition}, moving to {endPosition}, " +
|
||||
$"distance: {moveDistance}, fixed: {useFixedDistance}");
|
||||
|
||||
Log.Message($"[EnergyLance] Spawned at {base.Position}, target: {endPosition}, " +
|
||||
$"exact position: {exactPosition}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,102 +344,34 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
|
||||
if (!hasStarted || hasCompleted)
|
||||
return;
|
||||
|
||||
ticksPassed++;
|
||||
|
||||
// 更新移动进度
|
||||
UpdateMovement();
|
||||
|
||||
// 造成伤害
|
||||
for (int i = 0; i < firesPerTick; i++)
|
||||
{
|
||||
StartRandomFireAndDoFlameDamage();
|
||||
}
|
||||
|
||||
// 更新音效
|
||||
sustainer?.Maintain();
|
||||
|
||||
// 检查是否完成
|
||||
if (ticksPassed >= durationTicks || currentProgress >= 1f)
|
||||
{
|
||||
CompleteEnergyLance();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMovement()
|
||||
{
|
||||
// 计算总距离
|
||||
float totalDistance = useFixedDistance ? moveDistance : Vector3.Distance(startPosition.ToVector3(), endPosition.ToVector3());
|
||||
|
||||
// 计算移动速度(基于持续时间和总距离)
|
||||
float progressPerTick = 1f / durationTicks;
|
||||
currentProgress += progressPerTick;
|
||||
currentProgress = Mathf.Clamp01(currentProgress);
|
||||
|
||||
// 更新精确位置
|
||||
exactPosition = Vector3.Lerp(startPosition.ToVector3(), CalculateEndPosition(), currentProgress);
|
||||
|
||||
// 更新格子位置
|
||||
IntVec3 newCell = new IntVec3(
|
||||
Mathf.RoundToInt(exactPosition.x),
|
||||
Mathf.RoundToInt(exactPosition.y),
|
||||
Mathf.RoundToInt(exactPosition.z)
|
||||
);
|
||||
|
||||
if (newCell != base.Position && newCell.InBounds(base.Map))
|
||||
{
|
||||
base.Position = newCell;
|
||||
}
|
||||
}
|
||||
|
||||
private void StartRandomFireAndDoFlameDamage()
|
||||
{
|
||||
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);
|
||||
where x.InBounds(base.Map)
|
||||
select x).RandomElementByWeight((IntVec3 x) => 1f - Mathf.Min(x.DistanceTo(base.Position) / effectRadius, 1f) + 0.05f);
|
||||
|
||||
FireUtility.TryStartFireIn(targetCell, base.Map, Rand.Range(0.1f, 0.925f), instigator);
|
||||
|
||||
|
||||
tmpThings.Clear();
|
||||
tmpThings.AddRange(targetCell.GetThingList(base.Map));
|
||||
|
||||
|
||||
for (int i = 0; i < tmpThings.Count; i++)
|
||||
{
|
||||
int num = ((tmpThings[i] is Corpse) ? CorpseFlameDamageAmountRange.RandomInRange : FlameDamageAmountRange.RandomInRange);
|
||||
Pawn pawn = tmpThings[i] as Pawn;
|
||||
BattleLogEntry_DamageTaken battleLogEntry_DamageTaken = null;
|
||||
|
||||
|
||||
if (pawn != null)
|
||||
{
|
||||
battleLogEntry_DamageTaken = new BattleLogEntry_DamageTaken(pawn, RulePackDefOf.DamageEvent_PowerBeam, instigator as Pawn);
|
||||
Find.BattleLog.Add(battleLogEntry_DamageTaken);
|
||||
}
|
||||
|
||||
DamageInfo damageInfo = new DamageInfo(DamageDefOf.Flame, num, 0f, -1f, instigator, null, weaponDef);
|
||||
|
||||
DamageInfo damageInfo = new DamageInfo(WulaDamageDefOf.Wula_Dark_Matter_Flame, num, 2f, -1f, instigator, null, weaponDef);
|
||||
tmpThings[i].TakeDamage(damageInfo).AssociateWithLog(battleLogEntry_DamageTaken);
|
||||
}
|
||||
|
||||
tmpThings.Clear();
|
||||
}
|
||||
|
||||
private void CompleteEnergyLance()
|
||||
{
|
||||
hasCompleted = true;
|
||||
|
||||
// 停止音效
|
||||
sustainer?.End();
|
||||
sustainer = null;
|
||||
|
||||
Log.Message($"[EnergyLance] Completed at position {base.Position}");
|
||||
|
||||
// 销毁自身
|
||||
Destroy();
|
||||
tmpThings.Clear();
|
||||
}
|
||||
|
||||
// 重写绘制方法,确保光束正确显示
|
||||
@@ -246,27 +381,8 @@ namespace WulaFallenEmpire
|
||||
Comps_PostDraw();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Values.Look(ref startPosition, "startPosition");
|
||||
Scribe_Values.Look(ref endPosition, "endPosition");
|
||||
Scribe_Values.Look(ref moveDistance, "moveDistance");
|
||||
Scribe_Values.Look(ref useFixedDistance, "useFixedDistance");
|
||||
Scribe_Values.Look(ref flightSpeed, "flightSpeed", 1f);
|
||||
Scribe_Values.Look(ref currentProgress, "currentProgress", 0f);
|
||||
Scribe_Values.Look(ref altitude, "altitude", 20f);
|
||||
Scribe_Values.Look(ref firesPerTick, "firesPerTick", 4);
|
||||
Scribe_Values.Look(ref effectRadius, "effectRadius", 15f);
|
||||
Scribe_Values.Look(ref durationTicks, "durationTicks", 600);
|
||||
Scribe_Values.Look(ref ticksPassed, "ticksPassed", 0);
|
||||
Scribe_Values.Look(ref hasStarted, "hasStarted", false);
|
||||
Scribe_Values.Look(ref hasCompleted, "hasCompleted", false);
|
||||
}
|
||||
|
||||
// 创建EnergyLance的静态方法
|
||||
public static EnergyLance MakeEnergyLance(ThingDef energyLanceDef, IntVec3 start, IntVec3 end, Map map,
|
||||
public static EnergyLance MakeEnergyLance(ThingDef energyLanceDef, IntVec3 start, IntVec3 end, Map map,
|
||||
float distance = 15f, bool fixedDistance = true, int duration = 600, Pawn instigatorPawn = null)
|
||||
{
|
||||
EnergyLance energyLance = (EnergyLance)ThingMaker.MakeThing(energyLanceDef);
|
||||
@@ -276,10 +392,12 @@ namespace WulaFallenEmpire
|
||||
energyLance.useFixedDistance = fixedDistance;
|
||||
energyLance.durationTicks = duration;
|
||||
energyLance.instigator = instigatorPawn;
|
||||
|
||||
GenSpawn.Spawn(energyLance, start, map);
|
||||
|
||||
Log.Message($"[EnergyLance] Created {energyLanceDef.defName} from {start} to {end}");
|
||||
|
||||
// 直接在目标位置生成光束
|
||||
IntVec3 spawnPosition = end.IsValid ? end : start;
|
||||
GenSpawn.Spawn(energyLance, spawnPosition, map);
|
||||
|
||||
Log.Message($"[EnergyLance] Created {energyLanceDef.defName} at {spawnPosition}, target: {end}");
|
||||
return energyLance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,25 @@ namespace WulaFallenEmpire
|
||||
public float moveSmoothing = 0.1f; // 移动平滑度 (0-1),值越小越平滑
|
||||
public int moteSpawnInterval = 3; // Mote生成间隔,值越大密度越低
|
||||
public float moteScale = 0.8f; // Mote缩放比例
|
||||
|
||||
|
||||
// 伤害配置
|
||||
public int firesPerTick = 4;
|
||||
public float effectRadius = 15f;
|
||||
|
||||
// 新增:移动速度配置
|
||||
public float flightSpeed = 5f; // 光束移动速度(格/秒)
|
||||
public float acceleration = 2f; // 加速度
|
||||
public float maxSpeed = 10f; // 最大速度
|
||||
public float turnSpeed = 90f; // 转向速度(度/秒)
|
||||
|
||||
// 移动模式配置
|
||||
public bool useDynamicMovement = true; // 使用动态追踪模式
|
||||
public bool snapToTarget = false; // 是否直接瞬移到目标
|
||||
public float snapDistance = 3f; // 瞬移触发距离
|
||||
|
||||
// 行为配置
|
||||
public bool hoverOverTarget = true; // 在目标上空悬停
|
||||
public float hoverAltitude = 20f; // 悬停高度
|
||||
public float attackRange = 15f; // 攻击范围
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompBuildingBombardment : ThingComp
|
||||
{
|
||||
public CompProperties_BuildingBombardment Props => (CompProperties_BuildingBombardment)props;
|
||||
|
||||
// 轰炸状态
|
||||
private BuildingBombardmentState currentState = BuildingBombardmentState.Idle;
|
||||
private int nextBurstTick = 0;
|
||||
private int currentBurstCount = 0;
|
||||
private int nextInnerBurstTick = 0;
|
||||
private List<LocalTargetInfo> currentTargets = new List<LocalTargetInfo>();
|
||||
|
||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||
{
|
||||
base.PostSpawnSetup(respawningAfterLoad);
|
||||
|
||||
if (!respawningAfterLoad)
|
||||
{
|
||||
// 新生成时立即开始第一轮轰炸
|
||||
StartNextBurst();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartNextBurst()
|
||||
{
|
||||
currentState = BuildingBombardmentState.Targeting;
|
||||
currentBurstCount = 0;
|
||||
currentTargets.Clear();
|
||||
|
||||
// 选择目标
|
||||
SelectTargets();
|
||||
|
||||
if (currentTargets.Count > 0)
|
||||
{
|
||||
currentState = BuildingBombardmentState.Bursting;
|
||||
nextInnerBurstTick = Find.TickManager.TicksGame;
|
||||
Log.Message($"[BuildingBombardment] Starting burst with {currentTargets.Count} targets");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有找到目标,等待下一轮
|
||||
currentState = BuildingBombardmentState.Idle;
|
||||
nextBurstTick = Find.TickManager.TicksGame + Props.burstIntervalTicks;
|
||||
Log.Message($"[BuildingBombardment] No targets found, waiting for next burst");
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectTargets()
|
||||
{
|
||||
Map map = parent.Map;
|
||||
if (map == null) return;
|
||||
|
||||
// 获取范围内的所有pawn
|
||||
var potentialTargets = new List<Pawn>();
|
||||
|
||||
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
|
||||
{
|
||||
if (IsValidTarget(pawn) && IsInRange(pawn.Position))
|
||||
{
|
||||
potentialTargets.Add(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
// 随机选择目标,最多burstCount个
|
||||
int targetCount = Mathf.Min(Props.burstCount, potentialTargets.Count);
|
||||
currentTargets = potentialTargets
|
||||
.InRandomOrder()
|
||||
.Take(targetCount)
|
||||
.Select(p => new LocalTargetInfo(p))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool IsValidTarget(Pawn pawn)
|
||||
{
|
||||
if (pawn == null || pawn.Downed || pawn.Dead) return false;
|
||||
|
||||
// 检查目标类型
|
||||
if (Props.targetEnemies && pawn.HostileTo(parent.Faction))
|
||||
return true;
|
||||
|
||||
if (Props.targetNeutrals && !pawn.HostileTo(parent.Faction) && pawn.Faction != parent.Faction)
|
||||
return true;
|
||||
|
||||
if (Props.targetAnimals && pawn.RaceProps.Animal)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsInRange(IntVec3 position)
|
||||
{
|
||||
float distance = Vector3.Distance(parent.Position.ToVector3(), position.ToVector3());
|
||||
return distance <= Props.radius;
|
||||
}
|
||||
|
||||
private void UpdateBursting()
|
||||
{
|
||||
if (Find.TickManager.TicksGame < nextInnerBurstTick)
|
||||
return;
|
||||
|
||||
if (currentBurstCount >= currentTargets.Count)
|
||||
{
|
||||
// 当前组发射完毕
|
||||
currentState = BuildingBombardmentState.Idle;
|
||||
nextBurstTick = Find.TickManager.TicksGame + Props.burstIntervalTicks;
|
||||
Log.Message($"[BuildingBombardment] Burst completed, waiting for next burst");
|
||||
return;
|
||||
}
|
||||
|
||||
// 发射当前目标
|
||||
var target = currentTargets[currentBurstCount];
|
||||
LaunchBombardment(target);
|
||||
currentBurstCount++;
|
||||
|
||||
// 设置下一个组内发射时间
|
||||
if (currentBurstCount < currentTargets.Count)
|
||||
{
|
||||
nextInnerBurstTick = Find.TickManager.TicksGame + Props.innerBurstIntervalTicks;
|
||||
}
|
||||
|
||||
Log.Message($"[BuildingBombardment] Launched bombardment {currentBurstCount}/{currentTargets.Count}");
|
||||
}
|
||||
|
||||
private void LaunchBombardment(LocalTargetInfo target)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 应用随机偏移
|
||||
IntVec3 targetCell = ApplyRandomOffset(target.Cell);
|
||||
|
||||
if (Props.skyfallerDef != null)
|
||||
{
|
||||
// 使用 Skyfaller
|
||||
Skyfaller skyfaller = SkyfallerMaker.MakeSkyfaller(Props.skyfallerDef);
|
||||
GenSpawn.Spawn(skyfaller, targetCell, parent.Map);
|
||||
}
|
||||
else if (Props.projectileDef != null)
|
||||
{
|
||||
// 使用抛射体作为备用
|
||||
LaunchProjectileAt(targetCell);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Log.Error($"[BuildingBombardment] Error launching bombardment: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private IntVec3 ApplyRandomOffset(IntVec3 originalCell)
|
||||
{
|
||||
if (Props.randomOffset <= 0f)
|
||||
return originalCell;
|
||||
|
||||
// 在随机偏移范围内选择一个位置
|
||||
float offsetX = Rand.Range(-Props.randomOffset, Props.randomOffset);
|
||||
float offsetZ = Rand.Range(-Props.randomOffset, Props.randomOffset);
|
||||
|
||||
IntVec3 offsetCell = new IntVec3(
|
||||
Mathf.RoundToInt(originalCell.x + offsetX),
|
||||
originalCell.y,
|
||||
Mathf.RoundToInt(originalCell.z + offsetZ)
|
||||
);
|
||||
|
||||
// 确保位置有效
|
||||
if (offsetCell.InBounds(parent.Map))
|
||||
return offsetCell;
|
||||
else
|
||||
return originalCell;
|
||||
}
|
||||
|
||||
private void LaunchProjectileAt(IntVec3 targetCell)
|
||||
{
|
||||
// 从建筑位置发射抛射体
|
||||
Vector3 spawnPos = parent.Position.ToVector3Shifted();
|
||||
|
||||
Projectile projectile = (Projectile)GenSpawn.Spawn(Props.projectileDef, parent.Position, parent.Map);
|
||||
if (projectile != null)
|
||||
{
|
||||
projectile.Launch(
|
||||
parent,
|
||||
spawnPos,
|
||||
new LocalTargetInfo(targetCell),
|
||||
new LocalTargetInfo(targetCell),
|
||||
ProjectileHitFlags.All,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case BuildingBombardmentState.Idle:
|
||||
if (Find.TickManager.TicksGame >= nextBurstTick)
|
||||
{
|
||||
StartNextBurst();
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildingBombardmentState.Bursting:
|
||||
UpdateBursting();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
|
||||
Scribe_Values.Look(ref currentState, "currentState", BuildingBombardmentState.Idle);
|
||||
Scribe_Values.Look(ref nextBurstTick, "nextBurstTick", 0);
|
||||
Scribe_Values.Look(ref currentBurstCount, "currentBurstCount", 0);
|
||||
Scribe_Values.Look(ref nextInnerBurstTick, "nextInnerBurstTick", 0);
|
||||
Scribe_Collections.Look(ref currentTargets, "currentTargets", LookMode.LocalTargetInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public enum BuildingBombardmentState
|
||||
{
|
||||
Idle,
|
||||
Targeting,
|
||||
Bursting
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompProperties_BuildingBombardment : CompProperties
|
||||
{
|
||||
// 轰炸区域配置
|
||||
public float radius = 15f; // 作用半径
|
||||
|
||||
// 目标选择配置
|
||||
public bool targetEnemies = true; // 是否以敌人为目标
|
||||
public bool targetNeutrals = false; // 是否以中立单位为目标
|
||||
public bool targetAnimals = false; // 是否以动物为目标
|
||||
|
||||
// 召唤配置
|
||||
public int burstCount = 3; // 单组召唤数量
|
||||
public int innerBurstIntervalTicks = 10; // 同组召唤间隔
|
||||
public int burstIntervalTicks = 60; // 组间召唤间隔
|
||||
public float randomOffset = 2f; // 随机偏移量
|
||||
|
||||
// Skyfaller 配置
|
||||
public ThingDef skyfallerDef; // 使用的 Skyfaller
|
||||
public ThingDef projectileDef; // 备用的抛射体定义
|
||||
|
||||
public CompProperties_BuildingBombardment()
|
||||
{
|
||||
this.compClass = typeof(CompBuildingBombardment);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user