This commit is contained in:
2025-12-05 17:31:34 +08:00
parent a2a3390ed8
commit 284727e3ba
11 changed files with 1583 additions and 147 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
using RimWorld;
using System.Collections.Generic;
using Verse;
namespace WulaFallenEmpire
{
public class CompProperties_BuildingSpawner : CompProperties
{
public ThingDef buildingToSpawn;
public bool destroyBuilding = true;
public int delayTicks = 0;
// 自动召唤设置
public bool canAutoCall = true;
public int autoCallDelayTicks = 0; // 默认10秒
// FlyOver 前提条件
public bool requireFlyOver = false;
// 屋顶限制
public bool allowThinRoof = true;
public bool allowThickRoof = true;
// 新增:科技需求
public ResearchProjectDef requiredResearch;
// 新增:生成时的效果器
public EffecterDef spawnEffecter;
// 新增:音效
public SoundDef spawnSound;
// 新增:建筑朝向设置
public Rot4 buildingRotation = Rot4.North;
// 新增:位置偏移
public IntVec2 spawnOffset = IntVec2.Zero;
// 新增:允许替换现有建筑
public bool canReplaceExisting = false;
// 新增:是否继承原建筑的派系
public bool inheritFaction = true;
// 新增:建筑生成后的燃料量(如果适用)
public FloatRange fuelRange = new FloatRange(1f, 1f);
public CompProperties_BuildingSpawner()
{
compClass = typeof(CompBuildingSpawner);
}
public override void ResolveReferences(ThingDef parentDef)
{
base.ResolveReferences(parentDef);
// 验证buildingToSpawn
if (buildingToSpawn != null && buildingToSpawn.category != ThingCategory.Building)
{
Log.Error($"CompProperties_BuildingSpawner: buildingToSpawn must be a building, but got {buildingToSpawn.defName}");
buildingToSpawn = null;
}
}
public override IEnumerable<string> ConfigErrors(ThingDef parentDef)
{
foreach (string item in base.ConfigErrors(parentDef))
{
yield return item;
}
if (buildingToSpawn == null)
{
yield return "buildingToSpawn is not set";
}
else if (buildingToSpawn.category != ThingCategory.Building)
{
yield return $"buildingToSpawn must be a building, but got {buildingToSpawn.defName}";
}
}
}
}

View File

@@ -11,17 +11,21 @@ namespace WulaFallenEmpire
// 记录已经处理过的建筑(避免重复)
private HashSet<Thing> processedBuildings = new HashSet<Thing>();
// 组件类型过滤
public bool includeBuildingSpawner = true;
public bool includeSkyfallerCaller = true;
public Designator_CallSkyfallerInArea()
{
defaultLabel = "WULA_Designator_CallSkyfallerInArea".Translate();
defaultDesc = "WULA_Designator_CallSkyfallerInAreaDesc".Translate();
icon = ContentFinder<Texture2D>.Get("Wula/UI/Designators/Designator_CallSkyfallerInArea");
defaultLabel = "WULA_Designator_CallInArea".Translate();
defaultDesc = "WULA_Designator_CallInAreaDesc".Translate();
icon = ContentFinder<Texture2D>.Get("Wula/UI/Designators/Designator_CallInArea");
soundDragSustain = SoundDefOf.Designate_DragStandard;
soundDragChanged = SoundDefOf.Designate_DragStandard_Changed;
useMouseIcon = true;
soundSucceeded = SoundDefOf.Designate_Claim;
hotKey = KeyBindingDefOf.Misc12;
tutorTag = "CallSkyfallerInArea";
tutorTag = "CallInArea";
}
public override DrawStyleCategoryDef DrawStyleCategory => DrawStyleCategoryDefOf.FilledRectangle;
@@ -35,13 +39,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 &&
thing.TryGetComp<CompSkyfallerCaller>() != null)
HasValidComponent(thing))
{
return true;
}
@@ -50,6 +54,28 @@ 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)
{
@@ -63,30 +89,53 @@ 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)
{
Messages.Message("WULA_AreaCallInitiated".Translate(totalBuildings),
MessageTypeDefOf.PositiveEvent);
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);
}
else
{
@@ -113,21 +162,44 @@ namespace WulaFallenEmpire
if (processedBuildings.Contains(thing))
continue;
// 获取空投组件
var comp = thing.TryGetComp<CompSkyfallerCaller>();
if (comp == null)
continue;
// 标记为已处理
processedBuildings.Add(thing);
// 尝试呼叫空投
if (comp.CanCallSkyfaller)
// 尝试调用两种组件(如果有且可以调用)
bool anyCalled = false;
// 1. 先尝试 Building Spawner
if (includeBuildingSpawner)
{
comp.CallSkyfaller(false);
processedBuildings.Add(thing);
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}");
}
}
}
// 即使不能呼叫,也添加到已处理列表,避免重复尝试
else
// 2. 尝试 Skyfaller Caller如果建筑还存在
if (!thing.Destroyed && includeSkyfallerCaller)
{
processedBuildings.Add(thing);
var skyfallerCaller = thing.TryGetComp<CompSkyfallerCaller>();
if (skyfallerCaller != null && skyfallerCaller.CanCallSkyfaller)
{
skyfallerCaller.CallSkyfaller(false);
anyCalled = true;
}
}
// 如果没有任何组件被调用,从处理列表中移除(防止重复尝试)
if (!anyCalled)
{
processedBuildings.Remove(thing);
}
}
}
@@ -141,20 +213,43 @@ namespace WulaFallenEmpire
if (t.Faction != Faction.OfPlayer)
return false;
var comp = t.TryGetComp<CompSkyfallerCaller>();
if (comp == null)
return false;
return true;
return HasValidComponent(t);
}
public override void DesignateThing(Thing t)
{
// 用于反向设计器(右键菜单)
var comp = t.TryGetComp<CompSkyfallerCaller>();
if (comp != null && comp.CanCallSkyfaller)
processedBuildings.Add(t);
// 尝试调用两种组件
bool anyCalled = false;
// 1. 先尝试 Building Spawner
if (includeBuildingSpawner)
{
comp.CallSkyfaller(false);
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);
}
}
@@ -162,8 +257,32 @@ 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

@@ -106,6 +106,8 @@
<Compile Include="BuildingComp\WULA_BuildingBombardment\CompProperties_BuildingBombardment.cs" />
<Compile Include="Ability\WULA_AbilityCallSkyfaller\MapComponent_SkyfallerDelayed.cs" />
<Compile Include="BuildingComp\Building_TurretGunHasSpeed.cs" />
<Compile Include="BuildingComp\WULA_BuildingSpawner\CompBuildingSpawner.cs" />
<Compile Include="BuildingComp\WULA_BuildingSpawner\CompProperties_BuildingSpawner.cs" />
<Compile Include="BuildingComp\WULA_EnergyLanceTurret\CompEnergyLanceTurret.cs" />
<Compile Include="BuildingComp\WULA_EnergyLanceTurret\CompProperties_EnergyLanceTurret.cs" />
<Compile Include="BuildingComp\WULA_InitialFaction\CompProperties_InitialFaction.cs" />