diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml index 4d0a2413..ccf8586f 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml @@ -1,5 +1,62 @@ + + + WULA_AreaTeleportBeacon + + 负责协调殖民地与轨道上的乌拉帝国舰队进行材料输送的信标,空投建筑会优先从信标覆盖区域吸纳资源完成空投。 + Building + +
  • BuildingsMisc
  • +
    + + Wula/Building/WULA_OrbitalTradeBeacon + Graphic_Single + + (0.3, 0.2, 0.3) + (0,0,-0.1) + + + Building + MinifiedThing + + 75 + 800 + 0.5 + 5 + + MapMeshAndRealTime + true + 0.15 + + 40 + 1 + + Normal + + BuildingDestroyed_Metal_Small + + +
  • + (13, 13) + 120 + WULA_Colony_License_LV1_Technology +
  • +
    + false + 14 + WULA_Buildings + 2100 + false + +
  • PlaceWorker_ShowTradeBeaconRadius
  • +
    + Misc2 + +
  • WULA_Colony_License_LV1_Technology
  • +
    +
    + WULA_OrbitalTradeBeacon @@ -973,4 +1030,6 @@ + +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml index 84b81cea..e4eb405d 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml @@ -1,5 +1,27 @@ + + + WULA_TeleportLandingMarker + + 用于标记传送降落位置。 + WulaFallenEmpire.WULA_TeleportLandingMarker + + Wula/Building/WULA_Dropping_Building_Cleanzone_Plus + Graphic_Multi + (13,13) + + false + + + Building + false + true + true + RealtimeOnly + true + + WULA_Prefab_Cleanzone_NewColonyBase_Beacon diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml index e369a522..c4ce1f45 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml @@ -113,5 +113,33 @@ 请先选择一个分类 正在收集材料 已暂停 + + 取消传送 + 取消当前的传送预热。 + 启动传送 + 启动区域传送程序,将信标周围的物体传送到指定位置。 + 需要研究:{0} + 缺少必要的研究:{0} + 无法生成目标地图。 + 传送预热已开始。 + 传送已取消。 + 无效的目标位置。 + 无法获取目标地图。 + 传送成功。 + 选择降落点 + 选择传送到达的具体位置。 + 超出地图边界。 + 位于不可建造区域。 + 目标位置被迷雾覆盖。 + 被不可破坏的物体阻挡:{0} + 目标地形不可通过。 + 被厚岩顶阻挡。 + 必须选择一个降落点。 + 确认传送 + 确认当前位置并开始传送。 + 移动标记 + 重新选择降落位置。 + 由于传送取消,生成的临时地图已被清理。 + 燃料不足。 \ No newline at end of file diff --git a/Source/WulaFallenEmpire/3516260226.code-workspace b/Source/WulaFallenEmpire/3516260226.code-workspace index a2433624..aef43a98 100644 --- a/Source/WulaFallenEmpire/3516260226.code-workspace +++ b/Source/WulaFallenEmpire/3516260226.code-workspace @@ -13,6 +13,7 @@ "path": "../../../../Data" }, { + "name": "dll1.6", "path": "../../../../dll1.6" } ], diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompMapTeleporter.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompMapTeleporter.cs new file mode 100644 index 00000000..2aa55e1e --- /dev/null +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompMapTeleporter.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using RimWorld.Planet; +using UnityEngine; +using Verse; +using Verse.AI; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class CompMapTeleporter : ThingComp + { + public CompProperties_MapTeleporter Props => (CompProperties_MapTeleporter)props; + + private bool isWarmingUp = false; + private int warmupTicksLeft = 0; + private GlobalTargetInfo target; + private WULA_TeleportLandingMarker activeMarker; + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref isWarmingUp, "isWarmingUp", false); + Scribe_Values.Look(ref warmupTicksLeft, "warmupTicksLeft", 0); + Scribe_TargetInfo.Look(ref target, "target"); + Scribe_References.Look(ref activeMarker, "activeMarker"); + } + + public override void PostDrawExtraSelectionOverlays() + { + base.PostDrawExtraSelectionOverlays(); + GenDraw.DrawFieldEdges(CellRect.CenteredOn(parent.Position, Props.areaSize.x, Props.areaSize.z).Cells.ToList()); + } + + public override void CompTick() + { + base.CompTick(); + if (isWarmingUp) + { + warmupTicksLeft--; + if (warmupTicksLeft % 60 == 0) + { + Log.Message($"[WULA] Teleport warmup: {warmupTicksLeft} ticks left."); + Props.warmupEffecter?.Spawn(parent, parent.Map).Cleanup(); + } + + if (warmupTicksLeft <= 0) + { + Log.Message("[WULA] Warmup finished. Attempting teleport..."); + TryTeleport(); + isWarmingUp = false; + } + } + } + + public override IEnumerable CompGetGizmosExtra() + { + foreach (var gizmo in base.CompGetGizmosExtra()) + { + yield return gizmo; + } + + if (parent.Faction != Faction.OfPlayer) + yield break; + + if (isWarmingUp) + { + yield return new Command_Action + { + defaultLabel = "WULA_CancelTeleport".Translate(), + defaultDesc = "WULA_CancelTeleportDesc".Translate(), + icon = ContentFinder.Get("UI/Designators/Cancel"), + action = CancelTeleport + }; + } + else if (activeMarker != null && !activeMarker.Destroyed) + { + yield return new Command_Action + { + defaultLabel = "WULA_CancelTeleport".Translate(), + defaultDesc = "WULA_CancelTeleportDesc".Translate(), + icon = ContentFinder.Get("UI/Designators/Cancel"), + action = CancelTeleport + }; + } + else + { + string reason = GetDisabledReason(); + Command_Action teleportCmd = new Command_Action + { + defaultLabel = "WULA_InitiateTeleport".Translate(), + defaultDesc = GetDescription(), + icon = ContentFinder.Get("UI/Commands/LaunchShip"), + action = StartTargeting, + disabledReason = reason + }; + + if (!string.IsNullOrEmpty(reason)) + { + teleportCmd.Disable(reason); + } + + yield return teleportCmd; + } + } + + private string GetDisabledReason() + { + if (Props.requiredResearch != null && !Props.requiredResearch.IsFinished) + { + return "WULA_MissingResearch".Translate(Props.requiredResearch.label); + } + + return null; + } + + private string GetDescription() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.Append("WULA_InitiateTeleportDesc".Translate()); + + if (Props.requiredResearch != null) + { + sb.AppendLine().Append("WULA_RequiresResearch".Translate(Props.requiredResearch.label)); + } + + return sb.ToString(); + } + + private void StartTargeting() + { + CameraJumper.TryJump(CameraJumper.GetWorldTarget(parent)); + Find.WorldSelector.ClearSelection(); + Find.WorldTargeter.BeginTargeting(ChoseWorldTarget, true, null, true, null, null); + } + + private bool ChoseWorldTarget(GlobalTargetInfo targetInfo) + { + if (!targetInfo.IsValid) return false; + + this.target = targetInfo; + + MapParent mapParent = Find.WorldObjects.MapParentAt(targetInfo.Tile); + + if (mapParent == null) + { + SettleUtility.AddNewHome(targetInfo.Tile, Faction.OfPlayer); + mapParent = Find.WorldObjects.MapParentAt(targetInfo.Tile); + } + + if (mapParent != null) + { + if (!mapParent.HasMap) + { + IntVec3 mapSize = Find.World.info.initialMapSize; + GetOrGenerateMapUtility.GetOrGenerateMap(targetInfo.Tile, mapSize, null); + } + + if (mapParent.HasMap) + { + CameraJumper.TryJump(mapParent.Map.Center, mapParent.Map); + + if (activeMarker != null && !activeMarker.Destroyed) + { + activeMarker.Destroy(); + } + + activeMarker = (WULA_TeleportLandingMarker)ThingMaker.MakeThing(DefDatabase.GetNamed("WULA_TeleportLandingMarker")); + activeMarker.sourceThing = parent; + GenSpawn.Spawn(activeMarker, mapParent.Map.Center, mapParent.Map); + + Find.Selector.ClearSelection(); + Find.Selector.Select(activeMarker); + Find.DesignatorManager.Select(new Designator_TeleportArrival(this, mapParent.Map, activeMarker)); + + return true; + } + } + + Messages.Message("WULA_TeleportFailed_MapGeneration".Translate(), MessageTypeDefOf.RejectInput); + return false; + } + + public void ConfirmArrival(IntVec3 cell, Map map) + { + this.target = new GlobalTargetInfo(cell, map); + StartWarmup(); + } + + private void StartWarmup() + { + isWarmingUp = true; + warmupTicksLeft = Props.warmupTicks; + Props.warmupSound?.PlayOneShot(parent); + Messages.Message("WULA_TeleportWarmupStarted".Translate(), parent, MessageTypeDefOf.NeutralEvent); + } + + private void CancelTeleport() + { + isWarmingUp = false; + warmupTicksLeft = 0; + + if (activeMarker != null && !activeMarker.Destroyed) + { + activeMarker.Destroy(); + activeMarker = null; + } + + Messages.Message("WULA_TeleportCancelled".Translate(), parent, MessageTypeDefOf.NeutralEvent); + } + + private void TryTeleport() + { + Log.Message($"[WULA] TryTeleport called. Target valid: {target.IsValid}, Tile: {target.Tile}, Cell: {target.Cell}"); + + if (!target.IsValid) + { + Messages.Message("WULA_TeleportFailed_InvalidTarget".Translate(), parent, MessageTypeDefOf.RejectInput); + CancelTeleport(); + return; + } + + Map targetMap = target.Map; + IntVec3 targetCell = target.Cell; + + if (targetMap == null) + { + Log.Message($"[WULA] Target map is null. Generating map for tile {target.Tile}..."); + targetMap = GetOrGenerateTargetMap(target.Tile); + if (targetMap == null) + { + Messages.Message("WULA_TeleportFailed_NoMap".Translate(), parent, MessageTypeDefOf.RejectInput); + CancelTeleport(); + return; + } + targetCell = targetMap.Center; + } + + Log.Message($"[WULA] Teleporting to map {targetMap.Index}, cell {targetCell}"); + TeleportContents(targetMap, targetCell); + } + + private Map GetOrGenerateTargetMap(int tile) + { + MapParent mapParent = Find.WorldObjects.MapParentAt(tile); + + if (mapParent == null) + { + SettleUtility.AddNewHome(tile, Faction.OfPlayer); + mapParent = Find.WorldObjects.MapParentAt(tile); + } + + if (mapParent != null) + { + if (!mapParent.HasMap) + { + IntVec3 mapSize = Find.World.info.initialMapSize; + return GetOrGenerateMapUtility.GetOrGenerateMap(tile, mapSize, null); + } + return mapParent.Map; + } + + return null; + } + + private struct ThingToTeleport + { + public Thing thing; + public IntVec3 relativePos; + } + + private void TeleportContents(Map targetMap, IntVec3 targetCenter) + { + Map sourceMap = parent.Map; + CellRect rect = CellRect.CenteredOn(parent.Position, Props.areaSize.x, Props.areaSize.z); + IntVec3 center = parent.Position; + + List thingsToTeleport = new List(); + List> terrainToTeleport = new List>(); + + Log.Message($"[WULA] Collecting data from {rect.Area} cells around {center} with size {Props.areaSize}"); + + // 1. 收集数据 + HashSet collectedThings = new HashSet(); + foreach (IntVec3 cell in rect) + { + if (!cell.InBounds(sourceMap)) continue; + + terrainToTeleport.Add(new Pair(cell - center, cell.GetTerrain(sourceMap))); + + List thingList = sourceMap.thingGrid.ThingsListAt(cell); + for (int i = thingList.Count - 1; i >= 0; i--) + { + Thing t = thingList[i]; + if (t != parent && !collectedThings.Contains(t) && + (t.def.category == ThingCategory.Item || + t.def.category == ThingCategory.Pawn || + t.def.category == ThingCategory.Building)) + { + if (!t.def.destroyable) continue; + + collectedThings.Add(t); + thingsToTeleport.Add(new ThingToTeleport { thing = t, relativePos = t.Position - center }); + } + } + } + + // 2. 准备传送 (PreSwapMap) + foreach (var data in thingsToTeleport) data.thing.PreSwapMap(); + parent.PreSwapMap(); + + // 3. 从源地图移除 (DeSpawn) + foreach (var data in thingsToTeleport) + { + if (data.thing.Spawned) data.thing.DeSpawn(DestroyMode.WillReplace); + } + if (parent.Spawned) parent.DeSpawn(DestroyMode.WillReplace); + + // 4. 修改地形 + foreach (var pair in terrainToTeleport) + { + IntVec3 newPos = targetCenter + pair.First; + newPos = newPos.ClampInsideMap(targetMap); + + List targetThings = targetMap.thingGrid.ThingsListAt(newPos); + for (int i = targetThings.Count - 1; i >= 0; i--) + { + if (targetThings[i].def.destroyable) targetThings[i].Destroy(); + } + + if (pair.Second != null) + { + targetMap.terrainGrid.SetTerrain(newPos, pair.Second); + sourceMap.terrainGrid.SetTerrain(center + pair.First, TerrainDefOf.Soil); + } + } + + // 5. 放置到新地图 (Spawn) + foreach (var data in thingsToTeleport) + { + if (data.thing.Destroyed) continue; + IntVec3 newPos = targetCenter + data.relativePos; + newPos = newPos.ClampInsideMap(targetMap); + GenSpawn.Spawn(data.thing, newPos, targetMap, data.thing.Rotation); + } + GenSpawn.Spawn(parent, targetCenter, targetMap, parent.Rotation); + + // 6. 传送后处理 (PostSwapMap) + foreach (var data in thingsToTeleport) + { + if (!data.thing.Destroyed) data.thing.PostSwapMap(); + } + parent.PostSwapMap(); + + // 7. 完成 + CameraJumper.TryJump(targetCenter, targetMap); + Props.teleportSound?.PlayOneShot(new TargetInfo(targetCenter, targetMap, false)); + Messages.Message("WULA_TeleportSuccessful".Translate(), new TargetInfo(targetCenter, targetMap, false), MessageTypeDefOf.PositiveEvent); + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompProperties_MapTeleporter.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompProperties_MapTeleporter.cs new file mode 100644 index 00000000..55b52901 --- /dev/null +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/CompProperties_MapTeleporter.cs @@ -0,0 +1,21 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_MapTeleporter : CompProperties + { + public IntVec2 areaSize = new IntVec2(13, 13); + public int warmupTicks = 120; + public EffecterDef warmupEffecter; + public SoundDef warmupSound; + public SoundDef teleportSound; + + public ResearchProjectDef requiredResearch; + + public CompProperties_MapTeleporter() + { + compClass = typeof(CompMapTeleporter); + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/WULA_TeleportLandingMarker.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/WULA_TeleportLandingMarker.cs new file mode 100644 index 00000000..0787d2f3 --- /dev/null +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_Teleporter/WULA_TeleportLandingMarker.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class WULA_TeleportLandingMarker : Thing + { + public Thing sourceThing; + + public CompMapTeleporter SourceTeleporter => sourceThing?.TryGetComp(); + + public override CellRect? CustomRectForSelector + { + get + { + if (SourceTeleporter != null) + { + return CellRect.CenteredOn(Position, SourceTeleporter.Props.areaSize.x, SourceTeleporter.Props.areaSize.z); + } + return null; + } + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_References.Look(ref sourceThing, "sourceThing"); + } + + public override IEnumerable GetGizmos() + { + foreach (var gizmo in base.GetGizmos()) + { + yield return gizmo; + } + + yield return new Command_Action + { + defaultLabel = "WULA_ConfirmTeleport".Translate(), + defaultDesc = "WULA_ConfirmTeleportDesc".Translate(), + icon = ContentFinder.Get("UI/Commands/LaunchShip"), + action = Confirm + }; + + yield return new Command_Action + { + defaultLabel = "WULA_MoveMarker".Translate(), + defaultDesc = "WULA_MoveMarkerDesc".Translate(), + icon = ContentFinder.Get("UI/Commands/Install"), + action = StartMove + }; + } + + private void StartMove() + { + if (SourceTeleporter != null) + { + Find.DesignatorManager.Select(new Designator_TeleportArrival(SourceTeleporter, Map, this)); + } + } + + private void Confirm() + { + if (SourceTeleporter != null) + { + SourceTeleporter.ConfirmArrival(Position, Map); + } + Destroy(); + } + + protected override void DrawAt(Vector3 drawLoc, bool flip = false) + { + base.DrawAt(drawLoc, flip); + if (SourceTeleporter != null) + { + GenDraw.DrawFieldEdges(CellRect.CenteredOn(Position, SourceTeleporter.Props.areaSize.x, SourceTeleporter.Props.areaSize.z).Cells.ToList()); + } + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Damage/202512031732.xml b/Source/WulaFallenEmpire/Damage/202512031732.xml deleted file mode 100644 index e9f71f0e..00000000 --- a/Source/WulaFallenEmpire/Damage/202512031732.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Damage_WithExtraEffects - - WulaFallenEmpire.DamageWorker_ExtraDamage - - -
  • - 电击效果 - true - - -
  • - EMP - 15 - false - 25 - EMP_Small - ElectricArc - 5 - - -
  • - Mechanoid - 0,1 -
  • - - - - -
    -
    - - - - Damage_WithBurn - - WulaFallenEmpire.DamageWorker_ExtraDamage - - -
  • - 燃烧效果 - - -
  • - Burn - true - 0.3 - SparkHit - 10 - - -
  • - Pawn - 0.3,1 - -
  • Flammable
  • - - - - - - -
    -
    - - - - Damage_MultiEffect - - WulaFallenEmpire.DamageWorker_ExtraDamage - - -
  • - 组合效果 - - - -
  • - Cut - 5 - false - Torso - - -
  • - Animal -
  • -
  • - Humanlike -
  • - - - - -
  • - EMP - true - 0.5 - false - - -
  • - Mechanoid -
  • - - - - -
  • - Blunt - 20 - false - - -
  • - Building -
  • - - - - -
    -
    - - - - Gun_AdvancedRifle - - - -
  • - Verb_Shoot - Bullet_Advanced -
  • -
    -
    - - - - Bullet_Advanced - - - Damage_MultiEffect - 25 - - diff --git a/Source/WulaFallenEmpire/Designator/Designator_TeleportArrival.cs b/Source/WulaFallenEmpire/Designator/Designator_TeleportArrival.cs new file mode 100644 index 00000000..815e4363 --- /dev/null +++ b/Source/WulaFallenEmpire/Designator/Designator_TeleportArrival.cs @@ -0,0 +1,167 @@ +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class Designator_TeleportArrival : Designator + { + private CompMapTeleporter teleporter; + private Map targetMap; + private WULA_TeleportLandingMarker marker; + private List thingsToTeleport = new List(); + private IntVec3 sourceCenter; + + public override string Label => "WULA_SelectArrivalPoint".Translate(); + public override string Desc => "WULA_SelectArrivalPointDesc".Translate(); + + public Designator_TeleportArrival(CompMapTeleporter teleporter, Map targetMap, WULA_TeleportLandingMarker marker = null) + { + this.teleporter = teleporter; + this.targetMap = targetMap; + this.marker = marker; + this.useMouseIcon = true; + this.soundDragSustain = SoundDefOf.Designate_DragStandard; + this.soundDragChanged = SoundDefOf.Designate_DragStandard_Changed; + this.soundSucceeded = SoundDefOf.Designate_PlaceBuilding; + } + + public override AcceptanceReport CanDesignateCell(IntVec3 loc) + { + if (!loc.InBounds(targetMap)) return false; + + // 检查区域是否有效 + CellRect rect = CellRect.CenteredOn(loc, teleporter.Props.areaSize.x, teleporter.Props.areaSize.z); + foreach (IntVec3 cell in rect) + { + if (!cell.InBounds(targetMap)) return "WULA_OutOfBounds".Translate(); + + // 检查地图边缘 + if (cell.InNoBuildEdgeArea(targetMap)) + { + return "WULA_InNoBuildArea".Translate(); + } + + // 检查迷雾 + if (cell.Fogged(targetMap)) + { + return "WULA_BlockedByFog".Translate(); + } + + // 检查是否有不可覆盖的建筑 + List things = targetMap.thingGrid.ThingsListAt(cell); + foreach (Thing t in things) + { + if (t.def.category == ThingCategory.Building) + { + if (!t.def.destroyable) + { + return "WULA_BlockedByIndestructible".Translate(t.Label); + } + } + } + + // 检查地形是否支持建造 + TerrainDef terrain = cell.GetTerrain(targetMap); + if (terrain.passability == Traversability.Impassable && !terrain.IsWater) + { + return "WULA_TerrainImpassable".Translate(); + } + } + + return true; + } + + public override void DesignateSingleCell(IntVec3 c) + { + if (marker != null) + { + marker.Position = c; + Find.DesignatorManager.Deselect(); + Find.Selector.ClearSelection(); + Find.Selector.Select(marker); + } + else + { + teleporter.ConfirmArrival(c, targetMap); + Find.DesignatorManager.Deselect(); + } + } + + public override void Selected() + { + CacheThings(); + DrawRect(); + } + + public override void SelectedUpdate() + { + DrawRect(); + DrawGhosts(); + } + + public override void DrawMouseAttachments() + { + base.DrawMouseAttachments(); + DrawRect(); + } + + private void DrawRect() + { + GenDraw.DrawFieldEdges(CellRect.CenteredOn(UI.MouseCell(), teleporter.Props.areaSize.x, teleporter.Props.areaSize.z).Cells.ToList()); + } + + private void CacheThings() + { + thingsToTeleport.Clear(); + if (teleporter.parent == null || teleporter.parent.Map == null) return; + + sourceCenter = teleporter.parent.Position; + Map sourceMap = teleporter.parent.Map; + CellRect rect = CellRect.CenteredOn(sourceCenter, teleporter.Props.areaSize.x, teleporter.Props.areaSize.z); + + foreach (IntVec3 cell in rect) + { + if (!cell.InBounds(sourceMap)) continue; + foreach (Thing t in sourceMap.thingGrid.ThingsListAt(cell)) + { + if (t.def.category == ThingCategory.Building || t.def.category == ThingCategory.Item || t.def.category == ThingCategory.Pawn) + { + if (t != teleporter.parent) thingsToTeleport.Add(t); + } + } + } + // 添加自身 + thingsToTeleport.Add(teleporter.parent); + } + + private void DrawGhosts() + { + IntVec3 mouseCell = UI.MouseCell(); + if (!mouseCell.InBounds(targetMap)) return; + + foreach (Thing t in thingsToTeleport) + { + if (t == null || t.Destroyed) continue; + if (t.Graphic == null) continue; + + IntVec3 relativePos = t.Position - sourceCenter; + IntVec3 drawPos = mouseCell + relativePos; + + if (drawPos.InBounds(targetMap)) + { + try + { + GhostUtility.GhostGraphicFor(t.Graphic, t.def, Color.white).DrawFromDef(drawPos.ToVector3ShiftedWithAltitude(AltitudeLayer.Blueprint), t.Rotation, t.def); + } + catch + { + // 忽略绘制错误,防止UI崩溃 + } + } + } + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/EventSystem/Letter_EventChoice.cs b/Source/WulaFallenEmpire/EventSystem/Letter_EventChoice.cs deleted file mode 100644 index cbf39751..00000000 --- a/Source/WulaFallenEmpire/EventSystem/Letter_EventChoice.cs +++ /dev/null @@ -1,94 +0,0 @@ -using RimWorld; -using RimWorld.QuestGen; -using System; -using System.Collections.Generic; -using Verse; - -namespace WulaFallenEmpire -{ - public class Letter_EventChoice : ChoiceLetter - { - // These fields are now inherited from the base Letter class - // public string letterLabel; - // public string letterTitle; - // public string letterText; - public List options; - public new Quest quest; - - public override IEnumerable Choices - { - get - { - if (options.NullOrEmpty()) - { - yield break; - } - - foreach (var optionDef in options) - { - var currentOption = optionDef; - Action choiceAction = delegate - { - if (!currentOption.optionEffects.NullOrEmpty()) - { - foreach (var conditionalEffect in currentOption.optionEffects) - { - string reason; - if (AreConditionsMet(conditionalEffect.conditions, out reason)) - { - conditionalEffect.Execute(null); - } - } - } - if (quest != null && !quest.hidden && !quest.Historical) - { - quest.End(QuestEndOutcome.Success); - } - Find.LetterStack.RemoveLetter(this); - }; - - var diaOption = new DiaOption(currentOption.label.Translate()) - { - action = choiceAction, - resolveTree = true - }; - yield return diaOption; - } - } - } - - public override bool CanDismissWithRightClick => false; - - private bool AreConditionsMet(List conditions, out string reason) - { - reason = ""; - if (conditions.NullOrEmpty()) - { - return true; - } - - foreach (var condition in conditions) - { - if (!condition.IsMet(out string singleReason)) - { - reason = singleReason; - return false; - } - } - return true; - } - - public override void ExposeData() - { - base.ExposeData(); - // Scribe_Values.Look(ref letterLabel, "letterLabel"); // Now uses base.label - // Scribe_Values.Look(ref letterTitle, "letterTitle"); // Now uses base.title - // Scribe_Values.Look(ref letterText, "letterText"); // Now uses base.text - Scribe_Collections.Look(ref options, "options", LookMode.Deep); - if (Scribe.mode != LoadSaveMode.Saving || quest != null) - { - Scribe_References.Look(ref quest, "quest"); - } - } - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/EventSystem/QuestNode_Root_EventLetter.cs b/Source/WulaFallenEmpire/EventSystem/QuestNode_Root_EventLetter.cs deleted file mode 100644 index 5142eff6..00000000 --- a/Source/WulaFallenEmpire/EventSystem/QuestNode_Root_EventLetter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using RimWorld; -using RimWorld.QuestGen; -using System; -using System.Collections.Generic; -using Verse; - -namespace WulaFallenEmpire -{ - public class QuestNode_Root_EventLetter : QuestNode - { - // Fields to be set from the QuestScriptDef XML - public SlateRef letterLabel; - public SlateRef letterTitle; - public SlateRef letterText; - public List