using System; using System.Collections.Generic; using UnityEngine; using Verse; using Verse.AI; using RimWorld; namespace WulaFallenEmpire { public class CompStorageTurret : ThingComp { public Thing Thing => this.parent; private CompProperties_StorageTurret Props => (CompProperties_StorageTurret)this.props; // 存储的炮塔列表 private List turrets = new List(); // 标记是否已加载数据 private bool dataLoaded = false; // 获取当前机械族存储数量 private int StoredMechanoidCount { get { var recycler = parent as Building_MechanoidRecycler; if (recycler != null) { return recycler.StoredCount; } return 0; } } public override void Initialize(CompProperties props) { base.Initialize(props); // 只有在没有加载过数据时才初始化新炮塔 if (!dataLoaded) { UpdateTurrets(); } } public override void CompTick() { base.CompTick(); // 确保数据已加载 if (!dataLoaded) { dataLoaded = true; InitializeTurretsAfterLoad(); return; } // 更新炮塔数量 if (Find.TickManager.TicksGame % 60 == 0) { UpdateTurrets(); } // 更新所有炮塔 for (int i = 0; i < turrets.Count; i++) { if (i < StoredMechanoidCount) { turrets[i].TurretTick(); } } } // 加载后初始化炮塔 private void InitializeTurretsAfterLoad() { if (turrets == null) { turrets = new List(); } // 重新建立 parent 引用 for (int i = 0; i < turrets.Count; i++) { if (turrets[i] != null) { turrets[i].SetParent(this); turrets[i].SetIndex(i); turrets[i].PostLoadInit(); } } // 根据当前机械族数量调整炮塔数量 UpdateTurrets(); } private void UpdateTurrets() { int currentCount = Mathf.Min(StoredMechanoidCount, Props.maxTurrets); // 添加缺少的炮塔 while (turrets.Count < currentCount) { turrets.Add(new TurretInstance(this, turrets.Count)); } // 移除多余的炮塔 while (turrets.Count > currentCount) { // 注意:只移除未激活的炮塔 int lastIndex = turrets.Count - 1; if (lastIndex >= StoredMechanoidCount) { turrets.RemoveAt(lastIndex); } else { break; } } } public override void PostDraw() { base.PostDraw(); // 绘制所有激活的炮塔 for (int i = 0; i < turrets.Count; i++) { if (i < StoredMechanoidCount) { turrets[i].DrawTurret(); } } } public override void PostExposeData() { base.PostExposeData(); Scribe_Values.Look(ref dataLoaded, "dataLoaded", false); Scribe_Collections.Look(ref turrets, "turrets", LookMode.Deep); if (Scribe.mode == LoadSaveMode.PostLoadInit) { // 标记需要重新初始化 dataLoaded = false; } } // 单个炮塔实例类,实现 IAttackTargetSearcher 接口 public class TurretInstance : IExposable, IAttackTargetSearcher { private CompStorageTurret _parent; private int _index; // 炮塔状态 public Thing gun; public int burstCooldownTicksLeft; public int burstWarmupTicksLeft; public LocalTargetInfo currentTarget = LocalTargetInfo.Invalid; public float curRotation; public Material turretMat; // 标记是否已初始化 private bool initialized = false; // 安全访问器 public CompStorageTurret Parent => _parent; public int Index => _index; // IAttackTargetSearcher 接口实现 public Thing Thing => _parent?.parent; public Verb CurrentEffectiveVerb => AttackVerb; public LocalTargetInfo LastAttackedTarget => LocalTargetInfo.Invalid; public int LastAttackTargetTick => -1; public Thing TargetCurrentlyAimingAt => currentTarget.Thing; private bool WarmingUp => burstWarmupTicksLeft > 0; public Verb AttackVerb { get { if (gun == null) return null; var compEq = gun.TryGetComp(); return compEq?.PrimaryVerb; } } private bool CanShoot { get { if (_parent == null || _parent.parent == null) return false; if (!_parent.parent.Spawned || _parent.parent.Destroyed) return false; if (AttackVerb == null) { // 尝试重新初始化 if (!initialized) { PostLoadInit(); } return false; } return true; } } // 无参构造函数用于序列化 public TurretInstance() { } public TurretInstance(CompStorageTurret parent, int index) { SetParent(parent); SetIndex(index); Initialize(); } public void SetParent(CompStorageTurret parent) { _parent = parent; } public void SetIndex(int index) { _index = index; } private void Initialize() { if (initialized) return; MakeGun(); UpdateGunVerbs(); initialized = true; } // 加载后初始化 public void PostLoadInit() { if (initialized) return; if (gun == null) { MakeGun(); } UpdateGunVerbs(); initialized = true; } private void MakeGun() { if (_parent == null || _parent.Props == null || _parent.Props.turretDef == null) return; gun = ThingMaker.MakeThing(_parent.Props.turretDef, null); } private void UpdateGunVerbs() { if (gun == null) return; var compEq = gun.TryGetComp(); if (compEq == null) return; // 确保 parent 不为 null if (_parent == null || _parent.parent == null) { Log.Warning("[StorageTurret] Parent is null when updating gun verbs"); return; } foreach (var verb in compEq.AllVerbs) { // 关键修复:设置正确的 caster verb.caster = _parent.parent; verb.castCompleteCallback = () => { burstCooldownTicksLeft = AttackVerb?.verbProps?.defaultCooldownTime.SecondsToTicks() ?? 0; }; } } public void TurretTick() { if (!CanShoot || AttackVerb == null) return; // 确保动词已正确初始化 if (AttackVerb.caster == null) { UpdateGunVerbs(); return; } // 更新炮塔旋转 if (currentTarget.IsValid) { Vector3 targetPos = currentTarget.Cell.ToVector3Shifted(); Vector3 turretPos = GetTurretDrawPos(); curRotation = (targetPos - turretPos).AngleFlat() + _parent.Props.angleOffset; } AttackVerb.VerbTick(); if (AttackVerb.state != VerbState.Bursting) { if (WarmingUp) { burstWarmupTicksLeft--; if (burstWarmupTicksLeft == 0) { AttackVerb.TryStartCastOn(currentTarget, false, true, false, true); } } else { if (burstCooldownTicksLeft > 0) { burstCooldownTicksLeft--; } if (burstCooldownTicksLeft <= 0 && _parent.parent.IsHashIntervalTick(10)) { // 修复:将 this 作为 IAttackTargetSearcher 传递 currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition( this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f); if (currentTarget.IsValid) { burstWarmupTicksLeft = 1; } else { ResetCurrentTarget(); } } } } } private void ResetCurrentTarget() { currentTarget = LocalTargetInfo.Invalid; burstWarmupTicksLeft = 0; } public void DrawTurret() { if (_parent == null || _parent.parent == null || !_parent.parent.Spawned) return; Vector3 drawPos = GetTurretDrawPos(); float angle = curRotation; if (turretMat == null && _parent.Props?.turretDef?.graphicData?.texPath != null) { turretMat = MaterialPool.MatFrom(_parent.Props.turretDef.graphicData.texPath); } if (turretMat == null) return; Matrix4x4 matrix = default(Matrix4x4); matrix.SetTRS(drawPos, Quaternion.AngleAxis(angle, Vector3.up), Vector3.one); Graphics.DrawMesh(MeshPool.plane10, matrix, turretMat, 0); } private Vector3 GetTurretDrawPos() { if (_parent == null || _parent.parent == null) return Vector3.zero; // 计算炮塔位置(围绕建筑排列) float angle = 360f * _index / _parent.Props.maxTurrets; float radius = _parent.Props.turretSpacing; Vector3 offset = new Vector3( Mathf.Cos(angle * Mathf.Deg2Rad) * radius, 0, Mathf.Sin(angle * Mathf.Deg2Rad) * radius ); return _parent.parent.DrawPos + offset + new Vector3(0, 0.5f, 0); } public void ExposeData() { Scribe_Values.Look(ref burstCooldownTicksLeft, "burstCooldownTicksLeft", 0); Scribe_Values.Look(ref burstWarmupTicksLeft, "burstWarmupTicksLeft", 0); Scribe_TargetInfo.Look(ref currentTarget, "currentTarget"); Scribe_Deep.Look(ref gun, "gun"); Scribe_Values.Look(ref curRotation, "curRotation", 0f); Scribe_Values.Look(ref initialized, "initialized", false); // 注意:不序列化 _parent 和 _index,它们在加载后重新设置 } } } }