Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/Ability/WULA_AbilityGuidedEnergyLance/CompBuildingEnergyLance.cs

362 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RimWorld;
using Verse;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace WulaFallenEmpire
{
public class CompBuildingEnergyLance : ThingComp
{
public CompProperties_BuildingEnergyLance Props => (CompProperties_BuildingEnergyLance)props;
// 状态管理
private EnergyLanceState currentState = EnergyLanceState.Idle;
private int nextUpdateTick = 0;
private int noTargetTicks = 0;
// 目标管理
private Pawn currentTarget = null;
private IntVec3 lastTargetPosition = IntVec3.Invalid;
// EnergyLance实例
private GuidedEnergyLance activeLance = null;
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
if (!respawningAfterLoad)
{
// 新生成时立即开始搜索目标
nextUpdateTick = Find.TickManager.TicksGame;
currentState = EnergyLanceState.Searching;
Log.Message($"[BuildingEnergyLance] Building spawned, starting target search");
}
}
private void UpdateState()
{
switch (currentState)
{
case EnergyLanceState.Idle:
// 空闲状态,等待下一次更新
break;
case EnergyLanceState.Searching:
SearchForTarget();
break;
case EnergyLanceState.Tracking:
TrackTarget();
break;
case EnergyLanceState.NoTarget:
HandleNoTarget();
break;
}
}
private void SearchForTarget()
{
Map map = parent.Map;
if (map == null) return;
// 获取范围内的所有有效目标
var potentialTargets = new List<Pawn>();
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
{
if (IsValidTarget(pawn) && IsInRange(pawn.Position))
{
potentialTargets.Add(pawn);
}
}
if (potentialTargets.Count > 0)
{
// 选择第一个目标(可以改为其他选择逻辑)
currentTarget = potentialTargets[0];
lastTargetPosition = currentTarget.Position;
// 创建EnergyLance
CreateEnergyLance();
currentState = EnergyLanceState.Tracking;
noTargetTicks = 0;
Log.Message($"[BuildingEnergyLance] Locked target: {currentTarget.Label}, position: {currentTarget.Position}");
}
else
{
// 没有找到目标
currentState = EnergyLanceState.NoTarget;
Log.Message($"[BuildingEnergyLance] No targets found in range");
}
}
private void TrackTarget()
{
if (currentTarget == null || !currentTarget.Spawned)
{
// 目标丢失,重新搜索
currentState = EnergyLanceState.Searching;
currentTarget = null;
return;
}
// 检查目标是否仍然有效
if (!IsValidTarget(currentTarget) || !IsInRange(currentTarget.Position))
{
// 目标无效或超出范围,寻找最近的敌人
FindNearestTarget();
return;
}
// 更新目标位置
lastTargetPosition = currentTarget.Position;
// 向EnergyLance发送目标位置
if (activeLance != null && !activeLance.Destroyed)
{
activeLance.UpdateTarget(lastTargetPosition);
noTargetTicks = 0;
Log.Message($"[BuildingEnergyLance] Updated target position: {lastTargetPosition}");
}
else
{
// EnergyLance丢失重新创建
CreateEnergyLance();
}
}
private void FindNearestTarget()
{
Map map = parent.Map;
if (map == null) return;
Pawn nearestTarget = null;
float nearestDistance = float.MaxValue;
// 获取当前EnergyLance位置
IntVec3 searchCenter = (activeLance != null && !activeLance.Destroyed) ?
activeLance.Position : parent.Position;
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
{
if (IsValidTarget(pawn) && IsInRange(pawn.Position))
{
float distance = Vector3.Distance(searchCenter.ToVector3(), pawn.Position.ToVector3());
if (distance < nearestDistance)
{
nearestDistance = distance;
nearestTarget = pawn;
}
}
}
if (nearestTarget != null)
{
currentTarget = nearestTarget;
lastTargetPosition = currentTarget.Position;
// 更新EnergyLance目标
if (activeLance != null && !activeLance.Destroyed)
{
activeLance.UpdateTarget(lastTargetPosition);
}
Log.Message($"[BuildingEnergyLance] Switched to nearest target: {currentTarget.Label}, distance: {nearestDistance}");
}
else
{
// 没有找到替代目标
currentState = EnergyLanceState.NoTarget;
currentTarget = null;
Log.Message($"[BuildingEnergyLance] No alternative targets found");
}
}
private void HandleNoTarget()
{
noTargetTicks++;
// 向EnergyLance发送空位置
if (activeLance != null && !activeLance.Destroyed)
{
activeLance.UpdateTarget(IntVec3.Invalid);
}
// 检查是否应该销毁EnergyLance
if (noTargetTicks >= Props.maxNoTargetTicks)
{
if (activeLance != null && !activeLance.Destroyed)
{
activeLance.Destroy();
activeLance = null;
}
// 回到搜索状态
currentState = EnergyLanceState.Searching;
noTargetTicks = 0;
Log.Message($"[BuildingEnergyLance] EnergyLance destroyed due to no targets");
}
else if (noTargetTicks % 60 == 0) // 每60刻检查一次是否有新目标
{
SearchForTarget();
}
}
private void CreateEnergyLance()
{
if (Props.energyLanceDef == null)
{
Log.Error($"[BuildingEnergyLance] No energyLanceDef configured");
return;
}
try
{
// 销毁现有的EnergyLance
if (activeLance != null && !activeLance.Destroyed)
{
activeLance.Destroy();
}
// 创建新的EnergyLance
IntVec3 spawnPos = GetLanceSpawnPosition();
activeLance = (GuidedEnergyLance)GenSpawn.Spawn(Props.energyLanceDef, spawnPos, parent.Map);
// 初始化EnergyLance
activeLance.duration = Props.energyLanceDuration;
activeLance.instigator = parent;
activeLance.controlBuilding = this.parent;
activeLance.firesPerTick = Props.firesPerTick;
// 如果有当前目标,设置初始位置
if (currentTarget != null)
{
activeLance.UpdateTarget(currentTarget.Position);
}
activeLance.StartStrike();
Log.Message($"[BuildingEnergyLance] Created EnergyLance at {spawnPos}");
}
catch (System.Exception ex)
{
Log.Error($"[BuildingEnergyLance] Error creating EnergyLance: {ex}");
}
}
private IntVec3 GetLanceSpawnPosition()
{
// 在建筑周围寻找一个合适的生成位置
Map map = parent.Map;
IntVec3 center = parent.Position;
// 优先选择建筑上方的位置
if (center.InBounds(map) && center.Walkable(map))
{
return center;
}
// 如果建筑位置不可用,在周围寻找
foreach (IntVec3 cell in GenRadial.RadialCellsAround(center, 2f, true))
{
if (cell.InBounds(map) && cell.Walkable(map))
{
return cell;
}
}
// 如果都不可用,返回建筑位置
return center;
}
private bool IsValidTarget(Pawn pawn)
{
if (pawn == null || pawn.Downed || pawn.Dead || !pawn.Spawned)
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;
}
public override void CompTick()
{
base.CompTick();
int currentTick = Find.TickManager.TicksGame;
// 检查是否需要更新状态
if (currentTick >= nextUpdateTick)
{
UpdateState();
nextUpdateTick = currentTick + Props.updateIntervalTicks;
}
// 检查EnergyLance状态
if (activeLance != null && activeLance.Destroyed)
{
activeLance = null;
if (currentState == EnergyLanceState.Tracking)
{
currentState = EnergyLanceState.Searching;
}
}
}
// 外部调用当EnergyLance需要目标时调用
public bool TryGetCurrentTarget(out IntVec3 targetPos)
{
if (currentTarget != null && IsValidTarget(currentTarget) && IsInRange(currentTarget.Position))
{
targetPos = currentTarget.Position;
return true;
}
targetPos = IntVec3.Invalid;
return false;
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref currentState, "currentState", EnergyLanceState.Idle);
Scribe_Values.Look(ref nextUpdateTick, "nextUpdateTick", 0);
Scribe_Values.Look(ref noTargetTicks, "noTargetTicks", 0);
Scribe_References.Look(ref currentTarget, "currentTarget");
Scribe_Values.Look(ref lastTargetPosition, "lastTargetPosition", IntVec3.Invalid);
Scribe_References.Look(ref activeLance, "activeLance");
}
}
public enum EnergyLanceState
{
Idle,
Searching,
Tracking,
NoTarget
}
}