373 lines
13 KiB
C#
373 lines
13 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using RimWorld;
|
|
using UnityEngine;
|
|
using Verse;
|
|
using Verse.AI;
|
|
|
|
namespace WulaFallenEmpire
|
|
{
|
|
public class CompProperties_SkyfallerCaller : CompProperties
|
|
{
|
|
public ThingDef skyfallerDef;
|
|
public bool destroyBuilding = true;
|
|
public int delayTicks = 0;
|
|
public string requiredFlyOverType = "default"; // 需要的 FlyOver 类型
|
|
public bool allowThinRoof = true; // 允许砸穿薄屋顶
|
|
public bool allowThickRoof = false; // 是否允许在厚岩顶下空投
|
|
public string requiredFlyOverLabel = "FlyOver"; // 显示给玩家的标签
|
|
|
|
public CompProperties_SkyfallerCaller()
|
|
{
|
|
compClass = typeof(CompSkyfallerCaller);
|
|
}
|
|
}
|
|
|
|
public class CompSkyfallerCaller : ThingComp
|
|
{
|
|
private CompProperties_SkyfallerCaller Props => (CompProperties_SkyfallerCaller)props;
|
|
|
|
private bool used = false;
|
|
private int callTick = -1;
|
|
private bool calling = false;
|
|
|
|
public bool CanCall => !used && !calling;
|
|
|
|
// 获取所需的 FlyOver 显示标签
|
|
public string RequiredFlyOverLabel
|
|
{
|
|
get
|
|
{
|
|
// 优先使用建筑配置的显示标签
|
|
if (!Props.requiredFlyOverLabel.NullOrEmpty())
|
|
return Props.requiredFlyOverLabel;
|
|
|
|
// 如果没有配置,回退到类型名称
|
|
return Props.requiredFlyOverType;
|
|
}
|
|
}
|
|
|
|
// 检查是否有对应类型的 FlyOver
|
|
public bool HasRequiredFlyOver
|
|
{
|
|
get
|
|
{
|
|
if (parent?.Map == null) return false;
|
|
|
|
// 查找地图上所有具有 FlyOverType 组件的物体
|
|
List<Thing> allThings = parent.Map.listerThings.AllThings;
|
|
int flyOverCount = 0;
|
|
int matchingTypeCount = 0;
|
|
|
|
foreach (Thing thing in allThings)
|
|
{
|
|
var typeComp = thing.TryGetComp<CompFlyOverType>();
|
|
if (typeComp != null)
|
|
{
|
|
flyOverCount++;
|
|
if (typeComp.FlyOverType == Props.requiredFlyOverType && typeComp.IsRequiredForDrop)
|
|
{
|
|
matchingTypeCount++;
|
|
Log.Message($"[SkyfallerCaller] Found required FlyOver of type: {Props.requiredFlyOverType} at {thing.Position}");
|
|
}
|
|
}
|
|
}
|
|
|
|
Log.Message($"[SkyfallerCaller] Searched {allThings.Count} things, found {flyOverCount} FlyOvers, {matchingTypeCount} matching type: {Props.requiredFlyOverType}");
|
|
|
|
return matchingTypeCount > 0;
|
|
}
|
|
}
|
|
|
|
// 检查屋顶条件
|
|
public bool CheckRoofConditions
|
|
{
|
|
get
|
|
{
|
|
if (parent?.Map == null) return false;
|
|
|
|
IntVec3 targetPos = parent.Position;
|
|
RoofDef roof = targetPos.GetRoof(parent.Map);
|
|
|
|
if (roof == null)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] No roof at target position, skyfaller allowed");
|
|
return true; // 没有屋顶,允许空投
|
|
}
|
|
|
|
if (roof.isThickRoof)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Thick roof detected at target position: {roof.defName}");
|
|
return Props.allowThickRoof; // 厚岩顶,根据配置决定
|
|
}
|
|
else
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Thin roof detected at target position: {roof.defName}");
|
|
return Props.allowThinRoof; // 薄屋顶,根据配置决定
|
|
}
|
|
}
|
|
}
|
|
|
|
// 检查所有召唤条件
|
|
public bool CanCallSkyfaller
|
|
{
|
|
get
|
|
{
|
|
if (!CanCall)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Cannot call: already used or calling");
|
|
return false;
|
|
}
|
|
|
|
if (!HasRequiredFlyOver)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Cannot call: missing required FlyOver type: {Props.requiredFlyOverType}");
|
|
return false;
|
|
}
|
|
|
|
if (!CheckRoofConditions)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Cannot call: roof conditions not met");
|
|
return false;
|
|
}
|
|
|
|
Log.Message($"[SkyfallerCaller] All conditions met for skyfaller call");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override void PostExposeData()
|
|
{
|
|
base.PostExposeData();
|
|
Scribe_Values.Look(ref used, "used", false);
|
|
Scribe_Values.Look(ref callTick, "callTick", -1);
|
|
Scribe_Values.Look(ref calling, "calling", false);
|
|
}
|
|
|
|
public override void CompTick()
|
|
{
|
|
base.CompTick();
|
|
|
|
if (calling && callTick >= 0 && Find.TickManager.TicksGame >= callTick)
|
|
{
|
|
ExecuteSkyfallerCall();
|
|
}
|
|
}
|
|
|
|
public void CallSkyfaller()
|
|
{
|
|
if (!CanCallSkyfaller)
|
|
{
|
|
// 显示相应的错误消息
|
|
if (!HasRequiredFlyOver)
|
|
{
|
|
Messages.Message("WULA_NoRequiredFlyOver".Translate(RequiredFlyOverLabel), parent, MessageTypeDefOf.RejectInput);
|
|
}
|
|
else if (!CheckRoofConditions)
|
|
{
|
|
if (parent.Position.GetRoof(parent.Map)?.isThickRoof == true)
|
|
{
|
|
Messages.Message("WULA_ThickRoofBlocking".Translate(), parent, MessageTypeDefOf.RejectInput);
|
|
}
|
|
else
|
|
{
|
|
Messages.Message("WULA_RoofBlocking".Translate(), parent, MessageTypeDefOf.RejectInput);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
Log.Message($"[SkyfallerCaller] Starting skyfaller call from {parent.Label} at {parent.Position}");
|
|
|
|
calling = true;
|
|
used = true;
|
|
callTick = Find.TickManager.TicksGame + Props.delayTicks;
|
|
|
|
if (Props.delayTicks <= 0)
|
|
{
|
|
ExecuteSkyfallerCall();
|
|
}
|
|
else
|
|
{
|
|
Messages.Message("WULA_SkyfallerIncoming".Translate(Props.delayTicks.ToStringTicksToPeriod()), parent, MessageTypeDefOf.ThreatBig);
|
|
}
|
|
}
|
|
|
|
private void ExecuteSkyfallerCall()
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Executing skyfaller call at {parent.Position}");
|
|
|
|
if (Props.skyfallerDef == null)
|
|
{
|
|
Log.Error("[SkyfallerCaller] Skyfaller def is null!");
|
|
return;
|
|
}
|
|
|
|
// 检查屋顶并处理
|
|
HandleRoofDestruction();
|
|
|
|
// 创建Skyfaller
|
|
Skyfaller skyfaller = SkyfallerMaker.MakeSkyfaller(Props.skyfallerDef);
|
|
if (skyfaller == null)
|
|
{
|
|
Log.Error("[SkyfallerCaller] Failed to create skyfaller!");
|
|
return;
|
|
}
|
|
|
|
IntVec3 spawnPos = parent.Position;
|
|
Log.Message($"[SkyfallerCaller] Spawning skyfaller at {spawnPos}");
|
|
|
|
GenSpawn.Spawn(skyfaller, spawnPos, parent.Map);
|
|
|
|
if (Props.destroyBuilding)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Destroying building {parent.Label}");
|
|
parent.Destroy(DestroyMode.Vanish);
|
|
}
|
|
|
|
calling = false;
|
|
callTick = -1;
|
|
}
|
|
|
|
private void HandleRoofDestruction()
|
|
{
|
|
if (parent?.Map == null) return;
|
|
|
|
IntVec3 targetPos = parent.Position;
|
|
RoofDef roof = targetPos.GetRoof(parent.Map);
|
|
|
|
if (roof != null && !roof.isThickRoof && Props.allowThinRoof)
|
|
{
|
|
Log.Message($"[SkyfallerCaller] Destroying thin roof at {targetPos}");
|
|
parent.Map.roofGrid.SetRoof(targetPos, null);
|
|
|
|
// 生成屋顶破坏效果
|
|
FleckMaker.ThrowDustPuffThick(targetPos.ToVector3Shifted(), parent.Map, 2f, new Color(1f, 1f, 1f, 2f));
|
|
}
|
|
}
|
|
|
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
|
{
|
|
foreach (var gizmo in base.CompGetGizmosExtra())
|
|
yield return gizmo;
|
|
|
|
if (!CanCall)
|
|
yield break;
|
|
|
|
Command_Action callCommand = new Command_Action
|
|
{
|
|
defaultLabel = "WULA_CallSkyfaller".Translate(),
|
|
defaultDesc = GetCallDescription(),
|
|
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_DropBuilding"),
|
|
action = CallSkyfaller,
|
|
disabledReason = GetDisabledReason()
|
|
};
|
|
|
|
yield return callCommand;
|
|
}
|
|
|
|
private string GetCallDescription()
|
|
{
|
|
string desc = "WULA_CallSkyfallerDesc".Translate();
|
|
|
|
if (!HasRequiredFlyOver)
|
|
{
|
|
desc += $"\n{"WULA_RequiresFlyOver".Translate(RequiredFlyOverLabel)}";
|
|
}
|
|
|
|
// 添加 null 检查
|
|
if (parent?.Map != null)
|
|
{
|
|
RoofDef roof = parent.Position.GetRoof(parent.Map);
|
|
if (roof != null)
|
|
{
|
|
if (roof.isThickRoof && !Props.allowThickRoof)
|
|
{
|
|
desc += $"\n{"WULA_ThickRoofBlockingDesc".Translate()}";
|
|
}
|
|
else if (!roof.isThickRoof && !Props.allowThinRoof)
|
|
{
|
|
desc += $"\n{"WULA_RoofBlockingDesc".Translate()}";
|
|
}
|
|
}
|
|
}
|
|
|
|
return desc;
|
|
}
|
|
|
|
private string GetDisabledReason()
|
|
{
|
|
if (!HasRequiredFlyOver)
|
|
{
|
|
return "WULA_NoRequiredFlyOver".Translate(RequiredFlyOverLabel);
|
|
}
|
|
|
|
if (!CheckRoofConditions)
|
|
{
|
|
// 添加 null 检查
|
|
if (parent?.Map != null)
|
|
{
|
|
RoofDef roof = parent.Position.GetRoof(parent.Map);
|
|
if (roof?.isThickRoof == true)
|
|
{
|
|
return "WULA_ThickRoofBlocking".Translate();
|
|
}
|
|
else
|
|
{
|
|
return "WULA_RoofBlocking".Translate();
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override string CompInspectStringExtra()
|
|
{
|
|
// 添加 null 检查,防止在小型化建筑上出现异常
|
|
if (parent?.Map == null)
|
|
return base.CompInspectStringExtra();
|
|
|
|
if (calling)
|
|
{
|
|
int ticksLeft = callTick - Find.TickManager.TicksGame;
|
|
if (ticksLeft > 0)
|
|
{
|
|
return "WULA_SkyfallerArrivingIn".Translate(ticksLeft.ToStringTicksToPeriod());
|
|
}
|
|
}
|
|
else if (!used)
|
|
{
|
|
string status = "WULA_ReadyToCallSkyfaller".Translate();
|
|
|
|
// 添加条件信息
|
|
if (!HasRequiredFlyOver)
|
|
{
|
|
status += $"\n{"WULA_MissingFlyOver".Translate(RequiredFlyOverLabel)}";
|
|
}
|
|
|
|
// 添加 null 检查
|
|
if (parent?.Map != null)
|
|
{
|
|
RoofDef roof = parent.Position.GetRoof(parent.Map);
|
|
if (roof != null)
|
|
{
|
|
if (roof.isThickRoof && !Props.allowThickRoof)
|
|
{
|
|
status += $"\n{"WULA_BlockedByThickRoof".Translate()}";
|
|
}
|
|
else if (!roof.isThickRoof && !Props.allowThinRoof)
|
|
{
|
|
status += $"\n{"WULA_BlockedByRoof".Translate()}";
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
return base.CompInspectStringExtra();
|
|
}
|
|
}
|
|
}
|