This commit is contained in:
Tourswen
2025-12-06 00:03:01 +08:00
parent 284727e3ba
commit ea64ff9e6c
47 changed files with 100 additions and 315 deletions

View File

@@ -79,8 +79,6 @@ namespace WulaFallenEmpire
}
}
Log.Message($"[BuildingSpawner] Found {allFlyOvers.Count} FlyOvers on map");
foreach (var thing in allFlyOvers)
{
if (thing is FlyOver flyOver && !flyOver.Destroyed)
@@ -94,13 +92,11 @@ namespace WulaFallenEmpire
if (facilitiesComp.HasFacility("BuildingdropperFacility"))
{
Log.Message($"[BuildingSpawner] Found valid FlyOver at {flyOver.Position} with BuildingdropperFacility");
return true;
}
}
}
Log.Message("[BuildingSpawner] No FlyOver with BuildingdropperFacility found");
return false;
}
catch (System.Exception ex)
@@ -146,8 +142,6 @@ namespace WulaFallenEmpire
autoCallScheduled = true;
callTick = Find.TickManager.TicksGame + Props.autoCallDelayTicks;
calling = true;
Log.Message($"[BuildingSpawner] Scheduled auto-call for non-player building {parent.Label} at tick {callTick}");
}
}
@@ -195,8 +189,6 @@ namespace WulaFallenEmpire
{
try
{
Log.Message($"[BuildingSpawner] Executing auto building spawn for non-player building at {parent.Position}");
if (Props.buildingToSpawn == null)
{
Log.Error("[BuildingSpawner] Building def is null!");
@@ -246,10 +238,6 @@ namespace WulaFallenEmpire
// 重置状态
ResetCall();
autoCallScheduled = false;
// 显示消息
Messages.Message("WULA_AutoBuildingSpawned".Translate(Props.buildingToSpawn.label, parent.Faction.Name),
MessageTypeDefOf.NeutralEvent);
}
catch (System.Exception ex)
{
@@ -264,7 +252,6 @@ namespace WulaFallenEmpire
// 非玩家派系不能手动呼叫
if (IsNonPlayerFaction && !isAutoCall)
{
Messages.Message("WULA_NonPlayerCannotCall".Translate(), parent, MessageTypeDefOf.RejectInput);
return;
}
@@ -274,8 +261,6 @@ namespace WulaFallenEmpire
return;
}
Log.Message($"[BuildingSpawner] Starting building spawn from {parent.Label} at {parent.Position}");
calling = true;
used = true;
int delay = isAutoCall ? Props.autoCallDelayTicks : Props.delayTicks;
@@ -329,8 +314,6 @@ namespace WulaFallenEmpire
// 执行建筑生成
protected virtual void ExecuteBuildingSpawn()
{
Log.Message($"[BuildingSpawner] Executing building spawn at {parent.Position}");
if (Props.buildingToSpawn == null)
{
Log.Error("[BuildingSpawner] Building def is null!");
@@ -341,7 +324,6 @@ namespace WulaFallenEmpire
var resourceCheck = CheckAndConsumeMaterials();
if (!resourceCheck.HasEnoughMaterials)
{
Log.Message($"[BuildingSpawner] Aborting building spawn due to insufficient materials.");
ResetCall();
return;
}
@@ -426,7 +408,6 @@ namespace WulaFallenEmpire
if (roof != null && !roof.isThickRoof && Props.allowThinRoof)
{
Log.Message($"[BuildingSpawner] Destroying thin roof at {targetPos}");
parent.Map.roofGrid.SetRoof(targetPos, null);
// 生成屋顶破坏效果
@@ -510,9 +491,6 @@ namespace WulaFallenEmpire
powerComp.PowerOn = true;
}
}
// 记录日志
Log.Message($"[BuildingSpawner] Successfully spawned {Props.buildingToSpawn.label} at {newBuilding.Position}");
}
// 资源管理与SkyfallerCaller类似
@@ -824,7 +802,6 @@ namespace WulaFallenEmpire
callTick = -1;
usedGlobalStorage = false;
autoCallScheduled = false;
Messages.Message("WULA_BuildingCallCancelled".Translate(), parent, MessageTypeDefOf.NeutralEvent);
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
@@ -853,9 +830,9 @@ namespace WulaFallenEmpire
string reason = GetDisabledReason();
Command_Action callCommand = new Command_Action
{
defaultLabel = "WULA_CallBuilding".Translate(),
defaultLabel = "WULA_TeleportBuilding".Translate(),
defaultDesc = GetCallDescription(),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_SpawnBuilding"),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_TeleportBuilding"),
action = () => CallBuilding(false),
disabledReason = reason
};
@@ -904,7 +881,7 @@ namespace WulaFallenEmpire
private string GetCallDescription()
{
var sb = new StringBuilder();
sb.Append("WULA_CallBuildingDesc".Translate(Props.buildingToSpawn.label));
sb.Append("WULA_TeleportBuildingDesc".Translate(Props.buildingToSpawn.label));
if (Props.requiredResearch != null)
{
@@ -932,117 +909,7 @@ namespace WulaFallenEmpire
}
}
string costString = GetCostString();
if (!string.IsNullOrEmpty(costString))
{
sb.AppendLine().AppendLine().Append("WULA_RequiredMaterials".Translate());
sb.Append(costString);
}
return sb.ToString();
}
// 获取成本字符串
private string GetCostString()
{
var costList = CostList;
if (costList.NullOrEmpty())
{
return "";
}
var sb = new StringBuilder();
foreach (var cost in costList)
{
sb.AppendLine($" - {cost.thingDef.LabelCap}: {cost.count}");
}
return sb.ToString();
}
// 检查字符串
public override string CompInspectStringExtra()
{
if (parent?.Map == null)
{
return base.CompInspectStringExtra();
}
var sb = new StringBuilder();
// 显示自动呼叫状态
if (autoCallScheduled && calling)
{
int ticksLeft = callTick - Find.TickManager.TicksGame;
sb.Append("WULA_AutoBuildingArrivingIn".Translate(ticksLeft.ToStringTicksToPeriod()));
}
else if (calling)
{
int ticksLeft = callTick - Find.TickManager.TicksGame;
if (ticksLeft > 0)
{
string messageKey = usedGlobalStorage ?
"WULA_BuildingArrivingInFromGlobal" :
"WULA_BuildingArrivingIn";
sb.Append(messageKey.Translate(ticksLeft.ToStringTicksToPeriod()));
}
}
else if (!used)
{
if (IsNonPlayerFaction && Props.canAutoCall)
{
sb.Append("WULA_AutoBuildingReady".Translate());
}
else
{
sb.Append("WULA_ReadyToCallBuilding".Translate(Props.buildingToSpawn.label));
}
// 显示科技需求
if (Props.requiredResearch != null && !HasRequiredResearch)
{
sb.AppendLine().Append("WULA_MissingResearch".Translate(Props.requiredResearch.label));
}
// 显示FlyOver需求
if (Props.requireFlyOver && !HasRequiredFlyOver)
{
sb.AppendLine().Append("WULA_MissingBuildingDropperFlyOver".Translate());
}
// 显示屋顶状态
RoofDef roof = parent.Position.GetRoof(parent.Map);
if (roof != null)
{
if (roof.isThickRoof && !Props.allowThickRoof)
{
sb.AppendLine().Append("WULA_BlockedByThickRoof".Translate());
}
else if (!roof.isThickRoof && !Props.allowThinRoof)
{
sb.AppendLine().Append("WULA_BlockedByRoof".Translate());
}
}
// 显示成本
string costString = GetCostString();
if (!string.IsNullOrEmpty(costString))
{
sb.AppendLine().AppendLine("WULA_RequiredMaterials".Translate());
sb.Append(costString);
}
}
string baseInspectString = base.CompInspectStringExtra();
if (!string.IsNullOrEmpty(baseInspectString))
{
if (sb.Length > 0)
{
sb.AppendLine();
}
sb.Append(baseInspectString);
}
return sb.Length > 0 ? sb.ToString().TrimEnd() : null;
}
}
}

View File

@@ -10,22 +10,18 @@ namespace WulaFallenEmpire
{
// 记录已经处理过的建筑(避免重复)
private HashSet<Thing> processedBuildings = new HashSet<Thing>();
// 组件类型过滤
public bool includeBuildingSpawner = true;
public bool includeSkyfallerCaller = true;
public Designator_CallSkyfallerInArea()
{
defaultLabel = "WULA_Designator_CallInArea".Translate();
defaultDesc = "WULA_Designator_CallInAreaDesc".Translate();
icon = ContentFinder<Texture2D>.Get("Wula/UI/Designators/Designator_CallInArea");
defaultLabel = "WULA_Designator_CallSkyfallerInArea".Translate();
defaultDesc = "WULA_Designator_CallSkyfallerInAreaDesc".Translate();
icon = ContentFinder<Texture2D>.Get("Wula/UI/Designators/Designator_CallSkyfallerInArea");
soundDragSustain = SoundDefOf.Designate_DragStandard;
soundDragChanged = SoundDefOf.Designate_DragStandard_Changed;
useMouseIcon = true;
soundSucceeded = SoundDefOf.Designate_Claim;
hotKey = KeyBindingDefOf.Misc12;
tutorTag = "CallInArea";
tutorTag = "CallSkyfallerInArea";
}
public override DrawStyleCategoryDef DrawStyleCategory => DrawStyleCategoryDefOf.FilledRectangle;
@@ -39,13 +35,13 @@ namespace WulaFallenEmpire
if (c.Fogged(Map))
return false;
// 检查单元格内是否有符合条件的玩家建筑
// 只要单元格内有玩家建筑,就允许选择
var things = Map.thingGrid.ThingsListAt(c);
foreach (var thing in things)
{
if (thing.def.category == ThingCategory.Building &&
thing.Faction == Faction.OfPlayer &&
HasValidComponent(thing))
thing.TryGetComp<CompSkyfallerCaller>() != null)
{
return true;
}
@@ -54,28 +50,6 @@ namespace WulaFallenEmpire
// 即使单元格内没有符合条件的建筑,也允许选择(这样用户可以拖动区域)
return true;
}
// 检查建筑是否有有效的组件
private bool HasValidComponent(Thing thing)
{
// 检查 Building Spawner 组件
if (includeBuildingSpawner)
{
var buildingSpawner = thing.TryGetComp<CompBuildingSpawner>();
if (buildingSpawner != null && buildingSpawner.CanCallBuilding)
return true;
}
// 检查 Skyfaller Caller 组件
if (includeSkyfallerCaller)
{
var skyfallerCaller = thing.TryGetComp<CompSkyfallerCaller>();
if (skyfallerCaller != null && skyfallerCaller.CanCallSkyfaller)
return true;
}
return false;
}
public override void DesignateSingleCell(IntVec3 c)
{
@@ -89,53 +63,32 @@ namespace WulaFallenEmpire
processedBuildings.Clear();
int totalBuildings = 0;
int buildingSpawnerCount = 0;
int skyfallerCallerCount = 0;
// 处理所有选中的单元格
foreach (var cell in cells)
{
if (cell.InBounds(Map))
{
// 统计该单元格处理的建筑数量
int cellCount = processedBuildings.Count;
ProcessCell(cell);
int newBuildings = processedBuildings.Count - cellCount;
// 统计每个组件类型的调用数量
foreach (var building in processedBuildings)
{
if (building.Destroyed) continue;
if (building.TryGetComp<CompBuildingSpawner>()?.calling == true)
buildingSpawnerCount++;
else if (building.TryGetComp<CompSkyfallerCaller>()?.calling == true)
skyfallerCallerCount++;
}
totalBuildings += newBuildings;
}
}
// 显示结果消息
// 计算成功和失败的数量
// 这里需要跟踪每个建筑的调用结果
// 由于我们直接调用CallSkyfaller需要知道哪些失败了
// 简化处理在ProcessCell中统计
// 显示简单的结果消息
if (totalBuildings > 0)
{
string message = "WULA_AreaCallInitiated".Translate(totalBuildings);
if (buildingSpawnerCount > 0 && skyfallerCallerCount > 0)
{
message += "\n" + "WULA_BothComponentsCalled".Translate(
buildingSpawnerCount, skyfallerCallerCount);
}
else if (buildingSpawnerCount > 0)
{
message += "\n" + "WULA_BuildingSpawnerCalled".Translate(buildingSpawnerCount);
}
else if (skyfallerCallerCount > 0)
{
message += "\n" + "WULA_SkyfallerCallerCalled".Translate(skyfallerCallerCount);
}
Messages.Message(message, MessageTypeDefOf.PositiveEvent);
Messages.Message("WULA_AreaCallInitiated".Translate(totalBuildings),
MessageTypeDefOf.PositiveEvent);
}
else
{
@@ -162,44 +115,21 @@ namespace WulaFallenEmpire
if (processedBuildings.Contains(thing))
continue;
// 标记为已处理
processedBuildings.Add(thing);
// 获取空投组件
var comp = thing.TryGetComp<CompSkyfallerCaller>();
if (comp == null)
continue;
// 尝试调用两种组件(如果有且可以调用)
bool anyCalled = false;
// 1. 先尝试 Building Spawner
if (includeBuildingSpawner)
// 尝试呼叫空投
if (comp.CanCallSkyfaller)
{
var buildingSpawner = thing.TryGetComp<CompBuildingSpawner>();
if (buildingSpawner != null && buildingSpawner.CanCallBuilding)
{
buildingSpawner.CallBuilding(false);
anyCalled = true;
// 如果建筑被销毁,记录日志
if (thing.Destroyed)
{
Log.Message($"[Designator] Building destroyed after BuildingSpawner call at {cell}");
}
}
comp.CallSkyfaller(false);
processedBuildings.Add(thing);
}
// 2. 尝试 Skyfaller Caller如果建筑还存在
if (!thing.Destroyed && includeSkyfallerCaller)
// 即使不能呼叫,也添加到已处理列表,避免重复尝试
else
{
var skyfallerCaller = thing.TryGetComp<CompSkyfallerCaller>();
if (skyfallerCaller != null && skyfallerCaller.CanCallSkyfaller)
{
skyfallerCaller.CallSkyfaller(false);
anyCalled = true;
}
}
// 如果没有任何组件被调用,从处理列表中移除(防止重复尝试)
if (!anyCalled)
{
processedBuildings.Remove(thing);
processedBuildings.Add(thing);
}
}
}
@@ -213,43 +143,20 @@ namespace WulaFallenEmpire
if (t.Faction != Faction.OfPlayer)
return false;
return HasValidComponent(t);
var comp = t.TryGetComp<CompSkyfallerCaller>();
if (comp == null)
return false;
return true;
}
public override void DesignateThing(Thing t)
{
// 用于反向设计器(右键菜单)
processedBuildings.Add(t);
// 尝试调用两种组件
bool anyCalled = false;
// 1. 先尝试 Building Spawner
if (includeBuildingSpawner)
var comp = t.TryGetComp<CompSkyfallerCaller>();
if (comp != null && comp.CanCallSkyfaller)
{
var buildingSpawner = t.TryGetComp<CompBuildingSpawner>();
if (buildingSpawner != null && buildingSpawner.CanCallBuilding)
{
buildingSpawner.CallBuilding(false);
anyCalled = true;
}
}
// 2. 尝试 Skyfaller Caller如果建筑还存在
if (!t.Destroyed && includeSkyfallerCaller)
{
var skyfallerCaller = t.TryGetComp<CompSkyfallerCaller>();
if (skyfallerCaller != null && skyfallerCaller.CanCallSkyfaller)
{
skyfallerCaller.CallSkyfaller(false);
anyCalled = true;
}
}
if (!anyCalled)
{
Messages.Message("WULA_NoComponentCanCall".Translate(),
t, MessageTypeDefOf.RejectInput);
comp.CallSkyfaller(false);
}
}
@@ -257,32 +164,6 @@ namespace WulaFallenEmpire
{
// 参考Designator_Deconstruct只绘制鼠标悬停方框
GenUI.RenderMouseoverBracket();
// 可以添加额外的视觉效果来显示哪些建筑将被影响
if (Find.DesignatorManager.SelectedDesignator == this)
{
DrawAffectedBuildings();
}
}
// 绘制受影响的建筑
private void DrawAffectedBuildings()
{
if (Map == null) return;
// 这里可以绘制高亮显示哪些建筑会被影响
// 但由于性能考虑,只在特定条件下绘制
if (DebugSettings.godMode)
{
foreach (var building in Map.listerBuildings.allBuildingsColonist)
{
if (HasValidComponent(building))
{
GenDraw.DrawFieldEdges(new List<IntVec3> { building.Position },
building.Destroyed ? Color.red : Color.green);
}
}
}
}
}
}
}

View File

@@ -164,12 +164,24 @@ namespace WulaFallenEmpire
private static void AddQuad(LayerSubMesh sm, Vector3 c, float scale, float altitude, Color color)
{
int count = sm.verts.Count;
// 添加微小的UV偏移来避免单像素黑边
const float uvOffset = 0.001f;
Vector2[] adjustedUVs = new Vector2[]
{
new Vector2(uvOffset, uvOffset),
new Vector2(uvOffset, 1f - uvOffset),
new Vector2(1f - uvOffset, 1f - uvOffset),
new Vector2(1f - uvOffset, uvOffset)
};
for (int i = 0; i < 4; i++)
{
sm.verts.Add(new Vector3(c.x + UVs[i].x * scale, altitude, c.z + UVs[i].y * scale));
sm.uvs.Add(UVs[i % 4]);
sm.uvs.Add(adjustedUVs[i]); // 使用调整后的UV坐标
sm.colors.Add(color);
}
sm.tris.Add(count);
sm.tris.Add(count + 1);
sm.tris.Add(count + 2);
@@ -178,6 +190,7 @@ namespace WulaFallenEmpire
sm.tris.Add(count + 3);
}
private static bool IsCornerIndoorMasked(IntVec3 c, CornerType cornerType, Map map)
{
switch (cornerType)

View File

@@ -269,6 +269,7 @@
<Compile Include="QuestNodes\QuestNode_Hyperlinks.cs" />
<Compile Include="QuestNodes\QuestNode_SpawnPrefabSkyfallerCaller.cs" />
<Compile Include="QuestNodes\QuestPart_GlobalResourceCheck.cs" />
<Compile Include="SectionLayer_WulaHull.cs" />
<Compile Include="Stat\StatWorker_Energy.cs" />
<Compile Include="Stat\StatWorker_Maintenance.cs" />
<Compile Include="Stat\StatWorker_NanoRepair.cs" />