using RimWorld; using System.Collections.Generic; using System.Text; using UnityEngine; using Verse; using System.Linq; namespace WulaFallenEmpire { public static class TransformValidationUtility { /// /// 检查位置是否可以放置目标建筑(通用版本) /// public static bool CanPlaceBuildingAt(ThingDef buildingDef, IntVec3 center, Map map, Faction faction, out string failReason) { return CanPlaceBuildingAt(buildingDef, center, map, faction, null, out failReason); } /// /// 检查位置是否可以放置目标建筑(带忽略物体版本) /// public static bool CanPlaceBuildingAt(ThingDef buildingDef, IntVec3 center, Map map, Faction faction, Thing thingToIgnore, out string failReason) { failReason = null; // 1. 检查建筑定义 if (buildingDef == null) { failReason = "目标建筑定义为空"; return false; } // 2. 检查建筑尺寸是否为奇数(根据您的需求) if (!IsOddSizedBuilding(buildingDef)) { failReason = $"建筑 {buildingDef.LabelCap} 的尺寸不是奇数,不符合放置要求"; return false; } // 3. 检查地图边界 if (!IsWithinMapBounds(buildingDef, center, map, out failReason)) return false; // 4. 检查地形是否可建造 if (!HasBuildableTerrain(buildingDef, center, map, out failReason)) return false; // 5. 检查其他建筑挤占(排除要忽略的物体) if (!IsAreaClearOfBlockingBuildings(buildingDef, center, map, thingToIgnore, out failReason)) return false; // 6. 检查特殊放置条件(如不可放置在水上等) if (!MeetsSpecialPlacementConditions(buildingDef, center, map, out failReason)) return false; // 7. 使用RimWorld原生的放置检查(最终验证)- 移除派系限制 if (!GenConstruct.CanPlaceBlueprintAt(buildingDef, center, Rot4.North, map, false, null, null, null)) { failReason = "该位置不符合建筑放置要求"; return false; } return true; } /// /// 检查建筑尺寸是否为奇数 /// public static bool IsOddSizedBuilding(ThingDef buildingDef) { return buildingDef.Size.x % 2 == 1 && buildingDef.Size.z % 2 == 1; } /// /// 检查地图边界 /// private static bool IsWithinMapBounds(ThingDef buildingDef, IntVec3 center, Map map, out string failReason) { CellRect occupiedRect = GenAdj.OccupiedRect(center, Rot4.North, buildingDef.Size); if (!occupiedRect.InBounds(map)) { failReason = "建筑超出地图边界"; return false; } failReason = null; return true; } /// /// 检查地形是否可建造 - 重新设计的逻辑 /// private static bool HasBuildableTerrain(ThingDef buildingDef, IntVec3 center, Map map, out string failReason) { CellRect occupiedRect = GenAdj.OccupiedRect(center, Rot4.North, buildingDef.Size); foreach (IntVec3 cell in occupiedRect) { if (!cell.InBounds(map)) continue; TerrainDef terrain = map.terrainGrid.TerrainAt(cell); if (terrain == null) { failReason = "未知地形"; return false; } // 检查是否在水体上 if (terrain.IsWater) { failReason = $"无法在水体 ({terrain.LabelCap}) 上放置建筑"; return false; } // 检查affordance - 使用更宽松的逻辑 if (!HasValidAffordance(buildingDef, terrain)) { failReason = $"地形 {terrain.LabelCap} 不支持放置 {buildingDef.LabelCap}"; return false; } } failReason = null; return true; } /// /// 检查affordance兼容性 - 重新设计的逻辑 /// private static bool HasValidAffordance(ThingDef buildingDef, TerrainDef terrain) { // 如果建筑没有指定affordance要求,则跳过检查 if (buildingDef.terrainAffordanceNeeded == null) return true; // 如果地形没有affordances列表,则检查失败 if (terrain.affordances == null || terrain.affordances.Count == 0) return false; // 检查地形是否提供建筑所需的affordance return terrain.affordances.Contains(buildingDef.terrainAffordanceNeeded); } /// /// 检查区域是否被其他建筑阻挡(排除指定物体) /// private static bool IsAreaClearOfBlockingBuildings(ThingDef buildingDef, IntVec3 center, Map map, Thing thingToIgnore, out string failReason) { CellRect occupiedRect = GenAdj.OccupiedRect(center, Rot4.North, buildingDef.Size); List blockingThings = new List(); foreach (IntVec3 cell in occupiedRect) { if (!cell.InBounds(map)) continue; // 检查该单元格上的所有建筑 List thingList = map.thingGrid.ThingsListAt(cell); foreach (Thing thing in thingList) { // 跳过要忽略的物体(如被转换的Pawn本身) if (thing == thingToIgnore) continue; if (thing.def.category == ThingCategory.Building || thing.def.category == ThingCategory.Pawn) { // 忽略蓝图和框架 if (thing.def.IsBlueprint || thing.def.IsFrame) continue; // 忽略被转换的Pawn本身 if (thing == thingToIgnore) continue; blockingThings.Add(thing); } } } if (blockingThings.Count > 0) { StringBuilder sb = new StringBuilder(); sb.AppendLine("以下物体阻挡了建筑放置:"); foreach (Thing thing in blockingThings) { sb.AppendLine($" - {thing.LabelCap}"); } failReason = sb.ToString().TrimEnd(); return false; } failReason = null; return true; } /// /// 检查特殊放置条件 /// private static bool MeetsSpecialPlacementConditions(ThingDef buildingDef, IntVec3 center, Map map, out string failReason) { CellRect occupiedRect = GenAdj.OccupiedRect(center, Rot4.North, buildingDef.Size); failReason = null; return true; } /// /// 获取建筑占用的所有单元格 /// public static List GetOccupiedCells(ThingDef buildingDef, IntVec3 center) { return GenAdj.OccupiedRect(center, Rot4.North, buildingDef.Size).Cells.ToList(); } } }