diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 321b2a61..54cb00aa 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml index ea7a7900..ed0d9e4c 100644 --- a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml +++ b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml @@ -85,14 +85,22 @@ WULA_EnterMech WulaFallenEmpire.JobDriver_EnterMech - Entering mech. + 驾驶构装体。 + + false + + + + WULA_BoardMech + WulaFallenEmpire.JobDriver_BoardMech + 作为乘员登上构装体。 false WULA_RefuelMech WulaFallenEmpire.JobDriver_RefuelMech - Refuleing TargetA. + 为 TargetA 加注燃料。 false @@ -113,7 +121,7 @@ WULA_RepairMech WulaFallenEmpire.JobDriver_RepairMech - Repairing TargetA. + 维修 TargetA。 false false @@ -127,12 +135,12 @@ Repair Repair Mech - + WULA_ForceEjectPilot WulaFallenEmpire.JobDriver_ForceEjectPilot - Prise TargetA. + 撬开 TargetA。 false @@ -140,7 +148,7 @@ WULA_CarryToMech WulaFallenEmpire.JobDriver_CarryToMech - carrying TargetA to TargetB. + 携带 TargetA 到 TargetB。 false \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Shuttle_Building.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Shuttle_Building.xml index eb92e0d2..de9c901f 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Shuttle_Building.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Shuttle_Building.xml @@ -182,8 +182,9 @@ WULA_ArmedShuttleWithPocket - 乌拉帝国用于在舰队和地表构建联系的特种穿梭机,拥有巨大的货仓和一个内部折叠的生活区,因此载重量惊人且可以在内部活动。它同时还拥有一面高反射概率的反射盾和MLt-1"棱晶"涡轮激光炮 ,可以抵挡大部分袭击。 - WulaFallenEmpire.Building_ArmedShuttleWithPocket + 乌拉帝国用于在舰队和地表构建联系的特种穿梭机,拥有载重量惊人的货仓。它同时还拥有一面高反射概率的反射盾和MLt-1"棱晶"涡轮激光炮 ,可以抵挡大部分袭击。 + + Building_TurretGun true Building 50 @@ -214,7 +215,7 @@ 500 150 25 - 4 + 2 true true @@ -235,8 +236,6 @@
  • ShuttleEngine
  • ShuttleEngine
  • -
  • ShuttleEngine
  • -
  • ShuttleEngine
  • 1000 @@ -269,7 +268,7 @@ {0} is ready to launch again.
  • - 5000 + 5000000 true true Shuttle_PawnLoaded @@ -298,7 +297,7 @@ ShuttleIdle_Ambience
  • - 15 + 10 30 2400 30 @@ -318,55 +317,25 @@ true - 0.75 + 0.5 30 0 Interceptor_BlockedProjectile
  • -
  • - 15 - 30 - Flame - 1 - false - false - false - true - false - false - false - 热辐射 - CVe-3"渡鸦"可以启动防御设施,蒸发胆敢进入反射立场内的敌军——这同时会使得它伤害附近所有的散落物品。 - Wula/UI/Commands/Wula_Psi_Titan_AreaDamage -
  • CompPowerPlant -2000 true
  • - - -
  • -
  • - 2000 - true - true - false - Shuttle_PawnLoaded - Shuttle_PawnExit -
  • -
  • - ShuttleIdle_Ambience -
  • - +
  • PlaceWorker_NotUnderRoof
  • PlaceWorker_TurretTop
  • @@ -428,7 +397,6 @@
    - WULA_PocketMapExit @@ -458,80 +426,6 @@ - - WULA_Shuttle_Autocannon - - 由乌拉帝国的穿梭机所装备的自动炮,能够组织起高射速的弹幕压制杀伤大规模目标。 - Ultra - 0 - - Wula/Weapon/WULA_Weapon_Empty - Graphic_Single - 2 - - 0.5 - None - - 40000 - 150 - 0.5 - 0.5 - 0.4 - 0.35 - 1.5 - - - - - 500 - 150 - 8 - - -
  • - Verb_Shoot - true - Bullet_WULA_Shuttle_Autocannon - 0.25 - 24 - 10 - 0.35 - 6 - Shot_TurretSniper - GunTail_Heavy - 12 - - true - true - true - -
  • -
    -
    - - Bullet_WULA_Shuttle_Autocannon - - Projectile_Explosive - Normal - True - - Wula/Projectile/WULA_Bullet_ChargeLanceShot_Red_Double - Graphic_Single - - (0.75,1) - - - WULA_Shuttle_Autocannon_Bullet - 14 - 120 - 2.4 - 0.4 - Explosion_Rocket - 0.75 - 0.1 - - - ArmedShuttleIncoming_WULA diff --git a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml index 81918af3..66c3da25 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml @@ -147,14 +147,6 @@ -
  • - 36000 - 8.2 - 8.4 - 0.02 - 4.0 - false -
  • @@ -336,7 +328,7 @@ Wula_AI_Rocket_Panzer - 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢,但是未像其姊妹型号那样装备护盾。 + 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢。 2 2 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 a87ce8c4..d91e3bd6 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml @@ -208,12 +208,25 @@ {0} 已经从 {1} 离开 征召驾驶员··· 指定一名驾驶员进入构装体 + 紧急登机 + 立刻召集上次驾驶过该构装体的驾驶员驾驶此构装体。 离开构装体 让该构装体的驾驶员离开构装体 没有可以作为构装体驾驶员的殖民者 此装备不能由此构装体使用 此装备不是为构装体设计的 此装备是专为构装体设计的,非构装体单位无法装备 + + 快速装载 + 命令附近的殖民者和机械族作为乘员登上构装体,乘员不会参与构装体的驾驶。 + 释放乘员 + 命令所有乘员快速离开构装体。 + {0} 登上了 {1} + {0} 离开了 {1} + 已命令 {0} 个单位登上 {1} + 无法成为乘员 + 构装体乘员位已满 + 登上构装体 {0} 构装体重新启动 没有可以执行操作的殖民者 @@ -274,4 +287,9 @@ 使地堡发出号召,让地图上所有的乌拉猫猫自动进入征召状态并聚集到该地堡附近。 集合能力冷却中 地堡被停用,无法进行集结征召 + + 飞行姿态 + 手动控制此单位是否保持飞行姿态。 + 已启用飞行姿态 + 停用飞行姿态 diff --git a/Content/Textures/Wula/UI/Commands/WFE_FlightToggle.png b/Content/Textures/Wula/UI/Commands/WFE_FlightToggle.png deleted file mode 100644 index 411f2f52..00000000 Binary files a/Content/Textures/Wula/UI/Commands/WFE_FlightToggle.png and /dev/null differ diff --git a/Content/Textures/Wula/UI/Commands/WULA_FlightToggle.png b/Content/Textures/Wula/UI/Commands/WULA_FlightToggle.png new file mode 100644 index 00000000..76415100 Binary files /dev/null and b/Content/Textures/Wula/UI/Commands/WULA_FlightToggle.png differ diff --git a/Source/WulaFallenEmpire/Pawn/Mechunit.cs b/Source/WulaFallenEmpire/Pawn/Mechunit.cs index 68aae6c4..ba85be4d 100644 --- a/Source/WulaFallenEmpire/Pawn/Mechunit.cs +++ b/Source/WulaFallenEmpire/Pawn/Mechunit.cs @@ -1,7 +1,7 @@ -// File: Wulamechunit_Fixed.cs using RimWorld; using System.Collections.Generic; using Verse; +using Verse.AI; using Verse.AI.Group; namespace WulaFallenEmpire @@ -32,6 +32,16 @@ namespace WulaFallenEmpire } } + // 添加乘员相关的Gizmo + var crewComp = this.TryGetComp(); + if (crewComp != null) + { + foreach (var gizmo in crewComp.CompGetGizmosExtra()) + { + yield return gizmo; + } + } + // 原有的征兆Gizmo if (drafter == null) { @@ -121,34 +131,66 @@ namespace WulaFallenEmpire // 关键修复:重写死亡相关方法 public override void Kill(DamageInfo? dinfo = null, Hediff exactCulprit = null) { - // 在死亡前弹出所有驾驶员 + // 在死亡前弹出所有驾驶员和乘员 var pilotComp = this.TryGetComp(); if (pilotComp != null && pilotComp.HasPilots) { pilotComp.EjectAllPilotsOnDeath(); } + var crewComp = this.TryGetComp(); + if (crewComp != null && crewComp.HasCrew) + { + crewComp.RemoveAllCrew(); + } + base.Kill(dinfo, exactCulprit); } // 重写销毁方法 public override void Destroy(DestroyMode mode = DestroyMode.Vanish) { - // 在销毁前弹出所有驾驶员 + // 在销毁前弹出所有驾驶员和乘员 var pilotComp = this.TryGetComp(); if (pilotComp != null && pilotComp.HasPilots) { pilotComp.EjectAllPilotsOnDeath(); } + var crewComp = this.TryGetComp(); + if (crewComp != null && crewComp.HasCrew) + { + crewComp.RemoveAllCrew(); + } + base.Destroy(mode); } // IThingHolder 接口实现 public new ThingOwner GetDirectlyHeldThings() { + // 合并驾驶员和乘员容器 var pilotComp = this.TryGetComp(); - return pilotComp?.GetDirectlyHeldThings(); + var crewComp = this.TryGetComp(); + + if (pilotComp != null && crewComp != null) + { + // 合并两个容器 + var combined = new ThingOwner(this); + combined.TryAddRangeOrTransfer(pilotComp.innerContainer); + combined.TryAddRangeOrTransfer(crewComp.innerContainer); + return combined; + } + else if (pilotComp != null) + { + return pilotComp.innerContainer; + } + else if (crewComp != null) + { + return crewComp.innerContainer; + } + + return null; } public new void GetChildHolders(List outChildren) @@ -159,8 +201,6 @@ namespace WulaFallenEmpire public override void ExposeData() { base.ExposeData(); - - // 驾驶员容器的数据会在CompMechPilotHolder中自动保存 } } } diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechCrewHolder/CompProperties_MechCrewHolder.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechCrewHolder/CompProperties_MechCrewHolder.cs new file mode 100644 index 00000000..e4b26a40 --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn_Comps/MechCrewHolder/CompProperties_MechCrewHolder.cs @@ -0,0 +1,472 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Verse; +using Verse.AI; + +namespace WulaFallenEmpire +{ + // 机甲乘员组件属性 + public class CompProperties_MechCrewHolder : CompProperties + { + public int maxCrew = 3; // 最大乘员数 + public float boardingRadius = 10f; // 登机半径 + public float maxPawnSize = 1.0f; // 最大装载体型大小 + public bool allowMechanoids = true; // 是否允许搭载机械族 + public bool draftOnExit = true; // 下车时是否进入征召状态 + + // 外观配置 + public string boardCrewIcon = "Wula/UI/Commands/WULA_BoardCrew"; + public string exitCrewIcon = "Wula/UI/Commands/WULA_ExitCrew"; + + // 工作配置 + public bool requireWorkTag = false; // 是否需要工作标签 + public string workTag = "CrewMember"; // 工作标签(如果需要) + + public CompProperties_MechCrewHolder() + { + compClass = typeof(CompMechCrewHolder); + } + + // 获取图标 + public Texture2D GetBoardCrewIcon() + { + if (!string.IsNullOrEmpty(boardCrewIcon) && + ContentFinder.Get(boardCrewIcon, false) != null) + { + return ContentFinder.Get(boardCrewIcon); + } + return ContentFinder.Get("UI/Commands/BoardCrew", false) ?? BaseContent.BadTex; + } + + public Texture2D GetExitCrewIcon() + { + if (!string.IsNullOrEmpty(exitCrewIcon) && + ContentFinder.Get(exitCrewIcon, false) != null) + { + return ContentFinder.Get(exitCrewIcon); + } + return ContentFinder.Get("UI/Commands/ExitCrew", false) ?? BaseContent.BadTex; + } + } + + // 机甲乘员组件实现 + public class CompMechCrewHolder : ThingComp, IThingHolder + { + public ThingOwner innerContainer; + + private Command_Action cachedBoardGizmo; + private Command_Action cachedExitGizmo; + private bool gizmosInitialized = false; + + // 属性 + public CompProperties_MechCrewHolder Props => (CompProperties_MechCrewHolder)props; + + public int CurrentCrewCount => innerContainer.Count; + public bool HasCrew => innerContainer.Count > 0; + public bool HasRoom => innerContainer.Count < Props.maxCrew; + public bool IsFull => innerContainer.Count >= Props.maxCrew; + + // 初始化 + public CompMechCrewHolder() + { + innerContainer = new ThingOwner(this); + } + + public override void Initialize(CompProperties props) + { + base.Initialize(props); + + if (innerContainer == null) + { + innerContainer = new ThingOwner(this); + } + } + + // 检查是否可以添加乘员 + public bool CanAddCrew(Pawn pawn) + { + if (pawn == null || pawn.Dead) + return false; + + if (!HasRoom) + return false; + + if (innerContainer.Contains(pawn)) + return false; + + // 检查体型大小 + if (pawn.BodySize > Props.maxPawnSize) + return false; + + // 检查是否允许机械族 + if (pawn.RaceProps.IsMechanoid && !Props.allowMechanoids) + return false; + + // 检查工作标签(如果需要) + if (Props.requireWorkTag) + { + WorkTags tag; + if (Enum.TryParse(Props.workTag, out tag)) + { + if (pawn.WorkTagIsDisabled(tag)) + return false; + } + } + + return true; + } + + // 添加乘员 + public void AddCrew(Pawn pawn) + { + if (!CanAddCrew(pawn)) + return; + + try + { + // 停止Pawn当前工作 + pawn.jobs?.StopAll(); + pawn.pather?.StopDead(); + + // 从地图移除并添加到容器 + if (pawn.Spawned) + pawn.DeSpawn(); + + innerContainer.TryAdd(pawn, true); + + // 触发事件 + Notify_CrewAdded(pawn); + + // 记录日志 + if (Prefs.DevMode) + { + Log.Message($"[CompMechCrewHolder] {pawn.LabelShort} boarded {parent.LabelShort}"); + } + } + catch (Exception ex) + { + Log.Error($"Error adding crew {pawn.LabelShort} to {parent.LabelShort}: {ex.Message}"); + } + } + + // 移除乘员 + public void RemoveCrew(Pawn pawn, IntVec3? exitPos = null) + { + if (!innerContainer.Contains(pawn)) + return; + + try + { + // 从容器移除 + innerContainer.Remove(pawn); + + // 生成到地图 + TrySpawnCrewAtPosition(pawn, exitPos ?? parent.Position); + + // 如果设置为征召状态 + if (Props.draftOnExit && pawn.drafter != null) + { + pawn.drafter.Drafted = true; + } + + // 触发事件 + Notify_CrewRemoved(pawn); + } + catch (Exception ex) + { + Log.Error($"Error removing crew {pawn.LabelShort} from {parent.LabelShort}: {ex.Message}"); + } + } + + // 移除所有乘员 + public void RemoveAllCrew(IntVec3? exitPos = null) + { + var crewToRemove = innerContainer; + + foreach (var thing in crewToRemove) + { + if (thing is Pawn pawn) + { + RemoveCrew(pawn, exitPos); + } + } + } + + // 获取所有符合条件的登机Pawn(半径内) + public List GetEligiblePawnsInRadius() + { + var eligiblePawns = new List(); + + if (parent.Map == null || !parent.Spawned) + return eligiblePawns; + + // 获取半径内的所有Pawn + var pawnsInRadius = parent.Map.mapPawns.AllPawnsSpawned + .Where(p => p.Position.DistanceTo(parent.Position) <= Props.boardingRadius) + .ToList(); + + foreach (var pawn in pawnsInRadius) + { + // 检查是否满足条件 + if (CanAddCrew(pawn) && + pawn.Faction == parent.Faction && + !pawn.Downed && + !pawn.Dead && + !pawn.IsPrisoner) + { + eligiblePawns.Add(pawn); + } + } + + return eligiblePawns; + } + + // 命令所有符合条件的Pawn登机 + public void OrderAllEligibleToBoard() + { + var eligiblePawns = GetEligiblePawnsInRadius(); + + int count = 0; + foreach (var pawn in eligiblePawns) + { + if (!HasRoom) + break; + + // 创建登机工作 + Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_BoardMech, parent); + pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); + count++; + } + + // 显示消息 + if (count > 0) + { + Messages.Message( + "WULA_CrewOrderedToBoard".Translate(count, parent.LabelShort), + parent, + MessageTypeDefOf.NeutralEvent + ); + } + } + + // 生成乘员到指定位置 + private bool TrySpawnCrewAtPosition(Pawn pawn, IntVec3 position) + { + Map map = parent.Map; + if (map == null) + return false; + + try + { + // 寻找安全位置 + if (!position.Walkable(map) || position.Fogged(map)) + { + CellFinder.TryFindRandomCellNear(position, map, 3, + c => c.Walkable(map) && !c.Fogged(map), + out position); + } + + GenSpawn.Spawn(pawn, position, map, WipeMode.Vanish); + return true; + } + catch (Exception ex) + { + Log.Error($"Error spawning crew {pawn.LabelShort}: {ex.Message}"); + return false; + } + } + + // 事件通知 + private void Notify_CrewAdded(Pawn crew) + { + if (crew.Faction == Faction.OfPlayer) + { + Messages.Message( + "WULA_CrewBoarded".Translate(crew.LabelShort, parent.LabelShort), + parent, + MessageTypeDefOf.PositiveEvent + ); + } + } + + private void Notify_CrewRemoved(Pawn crew) + { + if (crew.Faction == Faction.OfPlayer) + { + Messages.Message( + "WULA_CrewExited".Translate(crew.LabelShort, parent.LabelShort), + parent, + MessageTypeDefOf.NeutralEvent + ); + } + } + + // Gizmo显示 + public override IEnumerable CompGetGizmosExtra() + { + // 只对玩家派系显示 + if (parent.Faction != Faction.OfPlayer) + yield break; + + // 延迟初始化Gizmo + if (!gizmosInitialized) + { + InitializeGizmos(); + gizmosInitialized = true; + } + + // 登机按钮(如果有空间) + if (HasRoom) + { + yield return cachedBoardGizmo; + } + + // 下机按钮(如果有乘员) + if (HasCrew) + { + yield return cachedExitGizmo; + } + } + + private void InitializeGizmos() + { + // 登机Gizmo + cachedBoardGizmo = new Command_Action + { + defaultLabel = "WULA_BoardCrew".Translate(), + defaultDesc = "WULA_BoardCrewDesc".Translate(), + icon = Props.GetBoardCrewIcon(), + action = OrderAllEligibleToBoard, + hotKey = KeyBindingDefOf.Misc4 + }; + + // 下机Gizmo + cachedExitGizmo = new Command_Action + { + defaultLabel = "WULA_ExitCrew".Translate(), + defaultDesc = "WULA_ExitCrewDesc".Translate(), + icon = Props.GetExitCrewIcon(), + action = () => RemoveAllCrew(), + hotKey = KeyBindingDefOf.Misc5 + }; + } + + // 每帧更新 + public override void CompTick() + { + base.CompTick(); + + // 定期检查乘员状态 + if (Find.TickManager.TicksGame % 60 == 0) + { + CheckCrewStatus(); + } + } + + private void CheckCrewStatus() + { + var crewToRemove = new List(); + + foreach (var thing in innerContainer) + { + if (thing is Pawn pawn) + { + // 检查是否死亡 + if (pawn.Dead) + { + crewToRemove.Add(pawn); + } + + // 确保乘员不执行工作 + pawn.jobs?.StopAll(); + pawn.pather?.StopDead(); + } + } + + foreach (var pawn in crewToRemove) + { + RemoveCrew(pawn); + } + } + + // 数据保存/加载 + public override void PostExposeData() + { + base.PostExposeData(); + + Scribe_Deep.Look(ref innerContainer, "crewContainer", this); + + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + // 重置Gizmo状态 + gizmosInitialized = false; + cachedBoardGizmo = null; + cachedExitGizmo = null; + } + } + + // IThingHolder接口实现 + public ThingOwner GetDirectlyHeldThings() + { + return innerContainer; + } + + public void GetChildHolders(List outChildren) + { + ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings()); + } + + // 获取乘员列表 + public IEnumerable GetCrew() + { + foreach (var thing in innerContainer) + { + if (thing is Pawn pawn) + yield return pawn; + } + } + + // 死亡/销毁时处理 + public override void PostDestroy(DestroyMode mode, Map previousMap) + { + // 移除所有乘员 + if (HasCrew) + { + RemoveAllCrew(); + } + + base.PostDestroy(mode, previousMap); + } + + // 死亡时处理 + public override void PostPostApplyDamage(DamageInfo dinfo, float totalDamageDealt) + { + base.PostPostApplyDamage(dinfo, totalDamageDealt); + + // 如果机甲死亡,移除所有乘员 + if (parent is Pawn mech && mech.Dead && HasCrew) + { + RemoveAllCrew(); + } + } + + // 绘制效果(可选) + public override void PostDraw() + { + base.PostDraw(); + + // 可以添加一些视觉效果,比如显示乘员数等 + if (parent.Spawned && HasCrew) + { + // 在机甲上方显示乘员数量 + Vector3 drawPos = parent.DrawPos; + drawPos.y = AltitudeLayer.MetaOverlays.AltitudeFor(); + + GenMapUI.DrawThingLabel(drawPos, $"x{CurrentCrewCount}", Color.green); + } + } + } +} diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs index 07cef3a7..ff297120 100644 --- a/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs +++ b/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs @@ -1,4 +1,3 @@ -// File: CompMechPilotHolder.cs (添加残疾殖民者搬运逻辑) using WulaFallenEmpire; using RimWorld; using System; @@ -15,26 +14,31 @@ namespace WulaFallenEmpire public int maxPilots = 1; public string pilotWorkTag = "MechPilot"; - // 新增:驾驶员图标配置 + // 图标配置 public string summonPilotIcon = "Wula/UI/Commands/WULA_Enter_Mech"; public string ejectPilotIcon = "Wula/UI/Commands/WULA_Exit_Mech"; + public string recallPilotIcon = "Wula/UI/Commands/WULA_Recall_Pilot"; + + // 快速登机配置 + public bool enableQuickRecall = true; + public float recallRadius = 30f; - public float ejectPilotHealthPercentThreshold = 0.1f; // 默认30%血量 - public bool allowEntryBelowThreshold = false; // 血量低于阈值时是否允许进入 + public float ejectPilotHealthPercentThreshold = 0.1f; + public bool allowEntryBelowThreshold = false; - // 新增:Hediff同步配置 - public bool syncPilotHediffs = true; // 是否同步驾驶员的Hediff - public List syncedHediffDefs = null; // 需要同步的Hediff列表(null表示全部) - public bool autoApplyHediffOnEntry = false; // 进入时自动添加指定的Hediff - public HediffDef autoHediffDef = null; // 自动添加的Hediff - public float autoHediffSeverity = 0.5f; // 自动添加的Hediff严重性 + // Hediff同步配置 + public bool syncPilotHediffs = true; + public List syncedHediffDefs = null; + public bool autoApplyHediffOnEntry = false; + public HediffDef autoHediffDef = null; + public float autoHediffSeverity = 0.5f; public CompProperties_MechPilotHolder() { this.compClass = typeof(CompMechPilotHolder); } - // 新增:加载图标的方法 + // 图标加载方法 public Texture2D GetSummonPilotIcon() { if (!string.IsNullOrEmpty(summonPilotIcon) && ContentFinder.Get(summonPilotIcon, false) != null) @@ -54,20 +58,28 @@ namespace WulaFallenEmpire return ContentFinder.Get("UI/Commands/Eject", false) ?? BaseContent.BadTex; } + + public Texture2D GetRecallPilotIcon() + { + if (!string.IsNullOrEmpty(recallPilotIcon) && ContentFinder.Get(recallPilotIcon, false) != null) + { + return ContentFinder.Get(recallPilotIcon); + } + return ContentFinder.Get("UI/Commands/SummonPilot", false) ?? + BaseContent.BadTex; + } } public class CompMechPilotHolder : ThingComp, IThingHolder, ISuspendableThingHolder { public ThingOwner innerContainer; - // 标记是否正在处理死亡/销毁事件,避免重复处理 private bool isProcessingDestruction = false; - - // 新增:记录是否已经因为低血量弹出过驾驶员 private bool hasEjectedDueToLowHealth = false; - - // 新增:存储驾驶员同步的Hediff private Dictionary> syncedHediffs = new Dictionary>(); + + // 新增:记录上一次的驾驶员 + private Pawn lastPilot = null; public CompProperties_MechPilotHolder Props => (CompProperties_MechPilotHolder)props; @@ -78,17 +90,15 @@ namespace WulaFallenEmpire public bool IsContentsSuspended => true; - // 新增:获取精神状态定义 + // 精神状态定义 private MentalStateDef MechNoPilotStateDef => WULA_MentalStateDefOf.WULA_MechNoPilot; - // 新增:检查并更新精神状态 private void CheckAndUpdateMentalState() { var mech = parent as Pawn; if (mech == null || mech.Dead || MechNoPilotStateDef == null) return; - // 如果没有驾驶员,尝试进入待机状态 if (!HasPilots) { if (mech.MentalStateDef != MechNoPilotStateDef && !mech.InMentalState) @@ -96,7 +106,6 @@ namespace WulaFallenEmpire mech.mindState.mentalStateHandler.TryStartMentalState(MechNoPilotStateDef, null, true); } } - // 如果有驾驶员,确保退出待机状态 else { if (mech.MentalStateDef == MechNoPilotStateDef) @@ -106,45 +115,43 @@ namespace WulaFallenEmpire } } - // 修改:添加驾驶员 - 添加Hediff同步功能 + // 添加驾驶员 public void AddPilot(Pawn pawn) { if (!CanAddPilot(pawn)) return; - // 将pawn添加到容器中 + // 记录驾驶员 + if (lastPilot != pawn) + { + lastPilot = pawn; + } + if (pawn.Spawned) pawn.DeSpawnOrDeselect(); innerContainer.TryAdd(pawn, true); - // 停止pawn的移动 pawn.pather?.StopDead(); pawn.jobs?.StopAll(); - // 触发事件 Notify_PilotAdded(pawn); - - // 更新机甲的精神状态 CheckAndUpdateMentalState(); - // 新增:同步驾驶员的Hediff if (Props.syncPilotHediffs) { SyncPilotHediffs(pawn); } - // 新增:自动添加Hediff if (Props.autoApplyHediffOnEntry && Props.autoHediffDef != null) { AddAutoHediff(pawn); } } - // 修改:移除驾驶员 - 添加Hediff取消同步功能 + // 移除驾驶员 public void RemovePilot(Pawn pawn, IntVec3? exitPos = null) { - // 新增:移除前,清理同步的Hediff if (Props.syncPilotHediffs) { UnsyncPilotHediffs(pawn); @@ -152,27 +159,16 @@ namespace WulaFallenEmpire if (innerContainer.Contains(pawn)) { - // 从容器中移除 innerContainer.Remove(pawn); - - // 将pawn放回地图 TrySpawnPilotAtPosition(pawn, exitPos ?? parent.Position); - - // 触发事件 Notify_PilotRemoved(pawn); - - // 停止机甲的工作 StopMechJobs(); - - // 更新机甲的精神状态 CheckAndUpdateMentalState(); } } - // 新增:同步驾驶员的Hediff private void SyncPilotHediffs(Pawn pawn) { - // 修复:确保parent是Wulamechunit类型 if (pawn == null || !(parent is Wulamechunit mech)) return; @@ -180,23 +176,19 @@ namespace WulaFallenEmpire { var hediffsToSync = new List(); - // 收集需要同步的Hediff foreach (var hediff in pawn.health.hediffSet.hediffs) { if (ShouldSyncHediff(hediff)) { hediffsToSync.Add(hediff); - - // 激活Hediff的同步组件 var syncComp = hediff.TryGetComp(); if (syncComp != null) { - syncComp.OnPilotEnteredMech(mech); // 这里现在应该可以了 + syncComp.OnPilotEnteredMech(mech); } } } - // 存储同步的Hediff if (hediffsToSync.Count > 0) { syncedHediffs[pawn] = hediffsToSync; @@ -208,7 +200,6 @@ namespace WulaFallenEmpire } } - // 新增:取消同步驾驶员的Hediff private void UnsyncPilotHediffs(Pawn pawn) { if (pawn == null || !syncedHediffs.ContainsKey(pawn)) @@ -216,7 +207,6 @@ namespace WulaFallenEmpire try { - // 通知所有同步的Hediff断开连接 foreach (var hediff in syncedHediffs[pawn]) { var syncComp = hediff.TryGetComp(); @@ -226,7 +216,6 @@ namespace WulaFallenEmpire } } - // 从记录中移除 syncedHediffs.Remove(pawn); } catch (Exception ex) @@ -235,34 +224,27 @@ namespace WulaFallenEmpire } } - // 新增:判断Hediff是否需要同步 private bool ShouldSyncHediff(Hediff hediff) { if (hediff == null) return false; - // 检查是否有同步组件 var syncComp = hediff.TryGetComp(); if (syncComp == null) return false; - // 检查是否在指定的同步列表中 - if (Props.syncedHediffDefs != null && - Props.syncedHediffDefs.Count > 0) + if (Props.syncedHediffDefs != null && Props.syncedHediffDefs.Count > 0) { return Props.syncedHediffDefs.Contains(hediff.def.defName); } - // 默认同步所有有同步组件的Hediff return true; } - // 新增:自动添加Hediff private void AddAutoHediff(Pawn pawn) { try { - // 检查是否已经有相同的Hediff var existingHediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.autoHediffDef); if (existingHediff == null) { @@ -277,27 +259,23 @@ namespace WulaFallenEmpire } } - // 修改:在CompTick中添加Hediff同步检查 public override void CompTick() { base.CompTick(); try { - // 每60帧检查一次血量和精神状态 if (Find.TickManager.TicksGame % 60 == 0) { CheckLowHealth(); CheckAndUpdateMentalState(); } - // 每120帧检查一次Hediff同步状态 if (Find.TickManager.TicksGame % 120 == 0) { CheckHediffSync(); } - // 检查机甲是否死亡 var mech = parent as Pawn; if (mech != null && mech.Dead && HasPilots) { @@ -305,11 +283,10 @@ namespace WulaFallenEmpire return; } - // 定期检查驾驶员状态 var pilotsToRemove = new List(); foreach (var thing in innerContainer) { - if (thing is Pawn pawn && (pawn.Dead)) + if (thing is Pawn pawn && pawn.Dead) { pilotsToRemove.Add(pawn); } @@ -320,12 +297,10 @@ namespace WulaFallenEmpire RemovePilot(pawn); } - // 确保容器内的pawn处于正确状态 foreach (var thing in innerContainer) { if (thing is Pawn pawn) { - // 确保pawn在容器内不执行任何工作 pawn.jobs?.StopAll(); pawn.pather?.StopDead(); } @@ -337,37 +312,30 @@ namespace WulaFallenEmpire } } - // 新增:检查Hediff同步状态 private void CheckHediffSync() { - // 修复:确保parent是Wulamechunit类型 if (!Props.syncPilotHediffs || !(parent is Wulamechunit)) return; try { - // 检查每个驾驶员的同步状态 foreach (var pilot in GetPilots()) { if (pilot == null || pilot.Dead || pilot.Destroyed) continue; - // 检查是否有新的需要同步的Hediff SyncPilotHediffs(pilot); - // 检查是否有需要移除的Hediff if (syncedHediffs.ContainsKey(pilot)) { var currentHediffs = pilot.health.hediffSet.hediffs .Where(ShouldSyncHediff) .ToList(); - // 找出不再存在的Hediff var removedHediffs = syncedHediffs[pilot] .Where(h => !currentHediffs.Contains(h)) .ToList(); - // 清理不再存在的Hediff foreach (var hediff in removedHediffs) { var syncComp = hediff.TryGetComp(); @@ -377,7 +345,6 @@ namespace WulaFallenEmpire } } - // 更新记录 syncedHediffs[pilot] = currentHediffs; } } @@ -388,7 +355,6 @@ namespace WulaFallenEmpire } } - // 修改:在生成后初始化精神状态 public override void PostSpawnSetup(bool respawningAfterLoad) { base.PostSpawnSetup(respawningAfterLoad); @@ -398,16 +364,13 @@ namespace WulaFallenEmpire Log.Warning($"[WULA] CompMechPilotHolder attached to non-mech: {parent}"); } - // 确保加载后恢复状态 if (innerContainer == null) { innerContainer = new ThingOwner(this); } - // 初始化精神状态 CheckAndUpdateMentalState(); - // 新增:加载后重新同步Hediff if (Props.syncPilotHediffs) { foreach (var pilot in GetPilots()) @@ -417,7 +380,6 @@ namespace WulaFallenEmpire } } - // 修改:在数据保存和加载时处理Hediff同步 public override void PostExposeData() { base.PostExposeData(); @@ -425,17 +387,15 @@ namespace WulaFallenEmpire Scribe_Deep.Look(ref innerContainer, "innerContainer", this); Scribe_Values.Look(ref isProcessingDestruction, "isProcessingDestruction", false); Scribe_Values.Look(ref hasEjectedDueToLowHealth, "hasEjectedDueToLowHealth", false); - Scribe_Collections.Look(ref syncedHediffs, "syncedHediffs", - LookMode.Reference, LookMode.Deep); + Scribe_Collections.Look(ref syncedHediffs, "syncedHediffs", LookMode.Reference, LookMode.Deep); + Scribe_References.Look(ref lastPilot, "lastPilot"); - // 加载后检查精神状态和Hediff同步 if (Scribe.mode == LoadSaveMode.PostLoadInit) { CheckAndUpdateMentalState(); if (Props.syncPilotHediffs) { - // 重新同步所有驾驶员的Hediff foreach (var pilot in GetPilots()) { SyncPilotHediffs(pilot); @@ -444,34 +404,25 @@ namespace WulaFallenEmpire } } - // 新增:停止机甲所有工作 private void StopMechJobs() { var mech = parent as Pawn; if (mech == null) return; - // 停止所有工作 mech.jobs?.StopAll(); - - // 停止移动 mech.pather?.StopDead(); - // 取消征召 var drafter = mech.drafter; if (drafter != null && mech.Drafted) { mech.drafter.Drafted = false; } - // 停止当前所有工作队列 mech.jobs?.ClearQueuedJobs(); - - // 清除敌人目标 mech.mindState.enemyTarget = null; } - // 获取机甲当前血量百分比 public float CurrentHealthPercent { get @@ -484,30 +435,21 @@ namespace WulaFallenEmpire } } - // 检查机甲是否低于血量阈值 - public bool IsBelowHealthThreshold - { - get - { - return CurrentHealthPercent < Props.ejectPilotHealthPercentThreshold; - } - } + public bool IsBelowHealthThreshold => CurrentHealthPercent < Props.ejectPilotHealthPercentThreshold; - // 修改 CanAddPilot 方法,添加血量检查 public bool CanAddPilot(Pawn pawn) { if (pawn == null || pawn.Dead) return false; - // 允许无法行动但还活着的殖民者 if (pawn.Downed) - return true; // 这是新增的关键修改 + return true; if (!HasRoom) return false; if (innerContainer.Contains(pawn)) return false; - // 检查工作标签 + if (!string.IsNullOrEmpty(Props.pilotWorkTag)) { WorkTags tag; @@ -518,7 +460,6 @@ namespace WulaFallenEmpire } } - // 新增:检查血量阈值 if (!Props.allowEntryBelowThreshold && IsBelowHealthThreshold) { return false; @@ -526,45 +467,36 @@ namespace WulaFallenEmpire return true; } - // 修改:检查殖民者是否能够自行移动到机甲 private bool CanPawnMoveToMech(Pawn pawn, Wulamechunit mech) { if (pawn == null || mech == null) return false; - // 如果殖民者无法行动,需要搬运 if (pawn.Downed) return false; - // 检查殖民者是否能到达机甲 return pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly); } - // 修改 CompMechPilotHolder 的 CheckLowHealth 方法 private void CheckLowHealth() { if (IsBelowHealthThreshold && HasPilots) { - // 如果低于阈值且有驾驶员,弹出所有驾驶员 EjectPilotsDueToLowHealth(); } else if (!IsBelowHealthThreshold) { - // 如果恢复到阈值以上,重置标记 hasEjectedDueToLowHealth = false; } } - // 新增:因为低血量弹出驾驶员 private void EjectPilotsDueToLowHealth() { if (hasEjectedDueToLowHealth) return; - // 弹出所有驾驶员 RemoveAllPilots(); - // 发送消息 if (parent.Faction == Faction.OfPlayer) { Messages.Message("WULA_PilotsEjectedDueToLowHealth".Translate(parent.LabelShort, @@ -575,12 +507,10 @@ namespace WulaFallenEmpire hasEjectedDueToLowHealth = true; } - // 新增:在承受伤害后检查血量 public override void PostPostApplyDamage(DamageInfo dinfo, float totalDamageDealt) { base.PostPostApplyDamage(dinfo, totalDamageDealt); - // 如果机甲死亡,弹出驾驶员 var mech = parent as Pawn; if (mech != null && mech.Dead) { @@ -588,19 +518,27 @@ namespace WulaFallenEmpire } else { - // 检查是否因为伤害导致血量过低 CheckLowHealth(); } } - // 修改 Gizmo 显示,添加血量信息和Hediff同步状态 + // 修改Gizmo显示:只在条件满足时显示快速登机按钮 public override IEnumerable CompGetGizmosExtra() { - // 修复:确保parent是Wulamechunit类型 if (!(parent is Wulamechunit mech) || mech.Faction != Faction.OfPlayer) yield break; - // 召唤驾驶员Gizmo + // 快速登机按钮(只有在所有条件都满足时才显示) + if (Props.enableQuickRecall && HasRoom && !IsBelowHealthThreshold) + { + var recallGizmo = CreateRecallGizmo(); + if (recallGizmo != null) + { + yield return recallGizmo; + } + } + + // 召唤驾驶员按钮 if (HasRoom) { Command_Action summonCommand = new Command_Action @@ -615,7 +553,6 @@ namespace WulaFallenEmpire hotKey = KeyBindingDefOf.Misc2 }; - // 如果血量低于阈值且不允许进入,禁用按钮 if (!Props.allowEntryBelowThreshold && IsBelowHealthThreshold) { summonCommand.Disable("WULA_MechTooDamagedForEntry".Translate()); @@ -640,22 +577,82 @@ namespace WulaFallenEmpire }; } } + + // 创建快速登机Gizmo(只有条件完全满足时才创建) + private Command_Action CreateRecallGizmo() + { + // 检查是否有上次驾驶员 + if (lastPilot == null) + return null; + + // 检查驾驶员是否可用 + if (!IsPilotAvailableForRecall(lastPilot)) + return null; + + // 创建并返回Gizmo + return new Command_Action + { + defaultLabel = "WULA_RecallLastPilot".Translate(), + defaultDesc = "WULA_RecallLastPilotDesc".Translate(), + icon = Props.GetRecallPilotIcon(), + action = () => + { + RecallLastPilot(); + }, + hotKey = KeyBindingDefOf.Misc3 + }; + } + + // 检查驾驶员是否可用于快速登机 + private bool IsPilotAvailableForRecall(Pawn pilot) + { + if (pilot == null || pilot.Dead || pilot.Destroyed) + return false; + + if (innerContainer.Contains(pilot)) + return false; + + if (!CanAddPilot(pilot)) + return false; + + if (parent.Map == null || !pilot.Spawned || pilot.Map != parent.Map) + return false; + + if (pilot.Position.DistanceTo(parent.Position) > Props.recallRadius) + return false; + + if (!pilot.CanReach(parent, PathEndMode.Touch, Danger.Deadly)) + return false; + + if (pilot.IsPrisoner || pilot.IsSlave) + return false; + + return true; + } + + // 召回上次驾驶员 + private void RecallLastPilot() + { + if (lastPilot == null || IsFull || !IsPilotAvailableForRecall(lastPilot)) + { + return; + } + + Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, parent); + lastPilot.jobs.TryTakeOrderedJob(job, JobTag.Misc); + } public CompMechPilotHolder() { innerContainer = new ThingOwner(this); } - // 修改:弹出所有驾驶员时取消Hediff同步 public void RemoveAllPilots(IntVec3? exitPos = null) { - // 记录是否有驾驶员 bool hadPilots = HasPilots; - // 复制列表以避免迭代时修改的问题 var pilotsToRemove = innerContainer.ToList(); - // 先取消所有Hediff同步 foreach (var thing in pilotsToRemove) { if (thing is Pawn pawn) @@ -664,7 +661,6 @@ namespace WulaFallenEmpire } } - // 然后移除所有驾驶员 foreach (var thing in pilotsToRemove) { if (thing is Pawn pawn) @@ -673,14 +669,12 @@ namespace WulaFallenEmpire } } - // 如果有机甲并且原来有驾驶员,现在没有了,停止工作 if (hadPilots && parent is Pawn mech) { StopMechJobs(); } } - // 修改:专门用于死亡/销毁时弹出驾驶员的方法,取消Hediff同步 public void EjectAllPilotsOnDeath() { if (isProcessingDestruction) @@ -695,7 +689,6 @@ namespace WulaFallenEmpire return; } - // 先取消所有Hediff同步 var pilots = innerContainer.ToList(); foreach (var thing in pilots) { @@ -705,26 +698,14 @@ namespace WulaFallenEmpire } } - // 获取安全位置 IntVec3 ejectPos = FindSafeEjectPosition(); - // 弹出所有驾驶员 foreach (var thing in pilots) { if (thing is Pawn pawn) { - // 从容器中移除 innerContainer.Remove(pawn); - - // 尝试生成到地图上 - if (TrySpawnPilotAtPosition(pawn, ejectPos)) - { - // 驾驶员成功弹出 - } - else - { - Log.Error($"[WULA] 无法弹出驾驶员: {pawn.LabelShort}"); - } + TrySpawnPilotAtPosition(pawn, ejectPos); } } } @@ -744,10 +725,8 @@ namespace WulaFallenEmpire if (map == null) return parent.Position; - // 优先选择机甲周围的安全位置 IntVec3 pos = parent.Position; - // 如果当前位置不安全,查找周围安全位置 if (!pos.Walkable(map) || pos.Fogged(map)) { for (int i = 1; i <= 5; i++) @@ -762,7 +741,6 @@ namespace WulaFallenEmpire } } - // 如果周围没有安全位置,使用随机位置 if (!pos.Walkable(map) || pos.Fogged(map)) { CellFinder.TryFindRandomCellNear(pos, map, 10, @@ -782,7 +760,6 @@ namespace WulaFallenEmpire return false; } - // 尝试在指定位置生成 try { if (GenGrid.InBounds(position, map) && position.Walkable(map) && !position.Fogged(map)) @@ -791,7 +768,6 @@ namespace WulaFallenEmpire return true; } - // 如果指定位置不行,找附近的位置 IntVec3 spawnPos; if (RCellFinder.TryFindRandomCellNearWith(position, cell => cell.Walkable(map) && !cell.Fogged(map), @@ -801,7 +777,6 @@ namespace WulaFallenEmpire return true; } - // 实在找不到位置,就在任意位置生成 CellFinder.TryFindRandomCellNear(position, map, 20, cell => cell.Walkable(map) && !cell.Fogged(map), out spawnPos); @@ -855,10 +830,8 @@ namespace WulaFallenEmpire } } - // 关键修复:重写销毁相关方法 public override void PostDestroy(DestroyMode mode, Map previousMap) { - // 先弹出所有驾驶员并取消Hediff同步 if (HasPilots) { EjectAllPilotsOnDeath(); @@ -867,7 +840,6 @@ namespace WulaFallenEmpire base.PostDestroy(mode, previousMap); } - // IThingHolder 接口实现 public ThingOwner GetDirectlyHeldThings() { return innerContainer; @@ -878,32 +850,26 @@ namespace WulaFallenEmpire ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings()); } - // 修改:显示驾驶员选择菜单,包含无法行动的殖民者 private void ShowPilotSelectionMenu() { - // 修复:确保parent是Wulamechunit类型 if (!(parent is Wulamechunit mech)) return; List options = new List(); - // 获取所有可用的殖民者(包括无法行动的) var allColonists = mech.Map.mapPawns.FreeColonists .Where(p => CanAddPilot(p)) .ToList(); - // 分类:能够行动和无法行动的 var ableColonists = allColonists.Where(p => CanPawnMoveToMech(p, mech)).ToList(); var disabledColonists = allColonists.Where(p => !CanPawnMoveToMech(p, mech)).ToList(); - // 为能够行动的殖民者创建选项 if (ableColonists.Count == 0 && disabledColonists.Count == 0) { options.Add(new FloatMenuOption("WULA_NoAvailablePilots".Translate(), null)); } else { - // 能够行动的殖民者:直接进入 foreach (var colonist in ableColonists) { string colonistLabel = colonist.LabelShortCap; @@ -914,20 +880,12 @@ namespace WulaFallenEmpire action, colonist, Color.white, - MenuOptionPriority.Default, - null, - null, - 0f, - null, - null, - true, - 0 + MenuOptionPriority.Default ); options.Add(option); } - // 无法行动的殖民者:需要搬运 foreach (var colonist in disabledColonists) { string colonistLabel = colonist.LabelShortCap + " " + "WULA_DisabledColonistRequiresCarry".Translate(); @@ -938,14 +896,7 @@ namespace WulaFallenEmpire action, colonist, Color.yellow, - MenuOptionPriority.Default, - null, - null, - 0f, - null, - null, - true, - 0 + MenuOptionPriority.Default ); options.Add(option); @@ -957,22 +908,18 @@ namespace WulaFallenEmpire private void OrderColonistToEnterMech(Pawn colonist) { - // 修复:确保parent是Wulamechunit类型 if (!(parent is Wulamechunit mech) || colonist == null) return; - // 为殖民者安排进入机甲的工作 Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, mech); colonist.jobs.TryTakeOrderedJob(job, JobTag.Misc); } - // 新增:为残疾殖民者安排搬运工作 private void OrderCarryDisabledColonistToMech(Pawn disabledColonist) { if (!(parent is Wulamechunit mech) || disabledColonist == null) return; - // 寻找最近的、能够搬运的殖民者 Pawn carrier = FindClosestAvailableCarrier(disabledColonist, mech); if (carrier == null) @@ -982,7 +929,6 @@ namespace WulaFallenEmpire return; } - // 为搬运者安排搬运工作 Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_CarryToMech, disabledColonist, mech); carrier.jobs.TryTakeOrderedJob(job, JobTag.Misc); @@ -990,13 +936,11 @@ namespace WulaFallenEmpire parent, MessageTypeDefOf.PositiveEvent); } - // 新增:寻找最近的可用搬运者 private Pawn FindClosestAvailableCarrier(Pawn disabledColonist, Wulamechunit mech) { if (disabledColonist.Map == null) return null; - // 寻找能够行动的殖民者,并且能够搬运 var potentialCarriers = disabledColonist.Map.mapPawns.FreeColonists .Where(p => p != disabledColonist && !p.Downed && p.CanReserveAndReach(disabledColonist, PathEndMode.OnCell, Danger.Deadly, 1, -1, null, false) && @@ -1006,7 +950,6 @@ namespace WulaFallenEmpire if (potentialCarriers.Count == 0) return null; - // 选择最近的殖民者 return potentialCarriers .OrderBy(p => p.Position.DistanceTo(disabledColonist.Position)) .FirstOrDefault(); diff --git a/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs index bd728922..acdc7d9f 100644 --- a/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs +++ b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs @@ -25,10 +25,10 @@ namespace WulaFallenEmpire { yield return new Command_Toggle { - defaultLabel = "Toggle Flight", - defaultDesc = "Toggle flight mode on or off.", + defaultLabel = "WULA_ToggleFlight".Translate(), + defaultDesc = "WULA_ToggleFlight_Desc".Translate() + (flightEnabled ? "WULA_ToggleFlight_Enable".Translate() : "WULA_ToggleFlight_Disable".Translate()), Order = 100f, - icon = ContentFinder.Get("Wula/UI/Commands/WFE_FlightToggle", false) + icon = ContentFinder.Get("Wula/UI/Commands/WULA_FlightToggle", false) ?? RimWorld.TexCommand.GatherSpotActive, isActive = () => flightEnabled, toggleAction = () => diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs index 6dc6f405..3a096abf 100644 --- a/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; using RimWorld; +using System.Collections.Generic; +using System.Runtime.Remoting.Messaging; using UnityEngine; using Verse; @@ -23,10 +24,20 @@ namespace WulaFallenEmpire public override void CompTick() { base.CompTick(); - - if (!parent.Spawned || !enabled) + + if (!enabled) return; + if (parent is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Dead || pawn.Downed || !pawn.Spawned || pawn.Destroyed)) + return; + + //对于mechunit,需要判定有没有驾驶员 + var MechPilotComp = parent.TryGetComp(); + if (MechPilotComp != null && !MechPilotComp.HasPilots) + { + return; + } + ticksUntilNextDamage--; if (ticksUntilNextDamage <= 0) { diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs index c73cc423..8438c6fa 100644 --- a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs @@ -1,16 +1,16 @@ -using RimWorld; -using Verse; -using UnityEngine; -using Verse.Sound; +using HarmonyLib; +using RimWorld; using System.Collections.Generic; -using HarmonyLib; +using UnityEngine; +using Verse; +using Verse.Sound; +using static RimWorld.MechClusterSketch; namespace WulaFallenEmpire { [StaticConstructorOnStartup] public class ThingComp_AreaShield : ThingComp { - // 现有的字段保持不变... private int lastInterceptTicks = -999999; public int ticksToReset = 0; public int currentHitPoints; @@ -122,7 +122,6 @@ namespace WulaFallenEmpire } } - // 现有的其他方法保持不变... private float GetCurrentAlpha() { // 多个透明度来源叠加,取最大值 @@ -220,14 +219,21 @@ namespace WulaFallenEmpire if (Holder == null || !Holder.Spawned || Holder.Destroyed) return false; - if (Holder is Pawn pawn && (pawn.Dead || pawn.Downed)) + if (Holder is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Dead || pawn.Downed || !pawn.Spawned)) return false; if (IsOnCooldown) return false; - + + //对于mechunit,需要判定有没有驾驶员 + var MechPilotComp = Holder.TryGetComp(); + if (MechPilotComp != null && !MechPilotComp.HasPilots) + { + return false; + } + // 装备:只有在立定时才激活 - if (IsEquipment && IsHolderMoving) + if (IsHolderMoving) return false; return true; @@ -338,7 +344,6 @@ namespace WulaFallenEmpire } } - // 现有的其他方法保持不变... private void ApplyCosts(int cost = 1) { currentHitPoints -= cost; @@ -359,7 +364,7 @@ namespace WulaFallenEmpire if (currentHitPoints <= 0) return false; - + try { if (!GenGeo.IntersectLineCircleOutline(Holder.Position.ToVector2(), Props.radius, lastExactPos.ToVector2(), newExactPos.ToVector2())) diff --git a/Source/WulaFallenEmpire/Work/BoardMech/FloatMenuOptionProvider_BoardMech.cs b/Source/WulaFallenEmpire/Work/BoardMech/FloatMenuOptionProvider_BoardMech.cs new file mode 100644 index 00000000..0e899a6f --- /dev/null +++ b/Source/WulaFallenEmpire/Work/BoardMech/FloatMenuOptionProvider_BoardMech.cs @@ -0,0 +1,293 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using Verse; +using Verse.AI; + +namespace WulaFallenEmpire +{ + public class FloatMenuOptionProvider_BoardMech : FloatMenuOptionProvider + { + private static readonly List tmpPawns = new List(); + + protected override bool Drafted => false; // 征召状态下不能登机 + protected override bool Undrafted => true; // 非征召状态下可以登机 + protected override bool Multiselect => true; // 支持多选 + + // 检查Thing是否为机甲 + private bool IsMech(Thing thing) + { + // 检查是否有CompMechCrewHolder组件 + return thing?.TryGetComp() != null; + } + + // 检查Pawn是否在机甲内 + private bool IsPawnInMech(Pawn pawn, Thing mech) + { + var comp = mech.TryGetComp(); + if (comp == null) + return false; + + // 检查内部容器 + var holder = comp as IThingHolder; + if (holder != null) + { + var things = holder.GetDirectlyHeldThings(); + if (things != null && things.Contains(pawn)) + return true; + } + + return false; + } + + protected override bool AppliesInt(FloatMenuContext context) + { + // 必须有选中的殖民者 + if (context.FirstSelectedPawn == null) + return false; + + // 检查点击的单元格中是否有机甲 + var clickedThings = context.ClickedThings; + if (clickedThings == null || clickedThings.Count == 0) + return false; + + // 查找第一个有机甲乘员组件的Thing + Thing mech = null; + foreach (var thing in clickedThings) + { + if (IsMech(thing)) + { + mech = thing; + break; + } + } + + if (mech == null) + return false; + + return true; + } + + // 重写:获取选项 + public override IEnumerable GetOptionsFor(Thing clickedThing, FloatMenuContext context) + { + if (!AppliesInt(context)) + yield break; + + if (context.IsMultiselect) + { + var option = GetMultiselectBoardMechOption(clickedThing, context); + if (option != null) + yield return option; + yield break; + } + + var singleOption = GetSingleOptionFor(clickedThing, context); + if (singleOption != null) + yield return singleOption; + } + + // 获取多选选项 + private FloatMenuOption GetMultiselectBoardMechOption(Thing clickedThing, FloatMenuContext context) + { + tmpPawns.Clear(); + + var comp = clickedThing.TryGetComp(); + if (comp == null) + return null; + + // 收集所有可以登机的Pawn + foreach (var pawn in context.ValidSelectedPawns) + { + if (CanPawnBoardMech(pawn, clickedThing, comp)) + { + tmpPawns.Add(pawn); + } + } + + if (tmpPawns.Count == 0) + return null; + + // 检查是否有机甲已满的情况 + string failStr = null; + if (comp.IsFull) + { + failStr = "WULA_MechFull".Translate(); + } + + if (!failStr.NullOrEmpty()) + { + return new FloatMenuOption( + "WULA_BoardMech".Translate(clickedThing.LabelShort) + ": " + failStr, + null, + MenuOptionPriority.DisabledOption + ); + } + + // 计算可以登机的数量 + int canBoardCount = 0; + foreach (var pawn in tmpPawns) + { + if (comp.HasRoom) + { + canBoardCount++; + } + else + { + break; + } + } + + string label = "WULA_BoardMech".Translate(clickedThing.LabelShort); + + return new FloatMenuOption(label, () => + { + FleckMaker.Static(clickedThing.DrawPos, clickedThing.MapHeld, FleckDefOf.FeedbackEquip); + + // 为每个可以登机的Pawn创建Job + foreach (var pawn in tmpPawns) + { + if (comp.HasRoom && CanPawnBoardMech(pawn, clickedThing, comp)) + { + Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_BoardMech, clickedThing); + pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); + } + } + }, MenuOptionPriority.High); + } + + // 获取单个选项 + protected override FloatMenuOption GetSingleOptionFor(Thing clickedThing, FloatMenuContext context) + { + if (clickedThing == null || context.FirstSelectedPawn == null) + return null; + + // 检查是否有乘员组件 + var comp = clickedThing.TryGetComp(); + if (comp == null) + return null; + + // 创建菜单选项 + return CreateBoardMechOption(clickedThing, context.FirstSelectedPawn, comp); + } + + // 创建登机菜单选项 + private FloatMenuOption CreateBoardMechOption(Thing mech, Pawn pawn, CompMechCrewHolder comp) + { + string label = "WULA_BoardMech".Translate(mech.LabelShort); + string disabledReason = ""; + + // 检查条件 + bool canBoard = CanPawnBoardMech(pawn, mech, comp, ref disabledReason); + + if (canBoard) + { + return new FloatMenuOption(label, () => + { + // 创建登机工作 + Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_BoardMech, mech); + pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); + + // 播放音效 + FleckMaker.Static(mech.DrawPos, mech.MapHeld, FleckDefOf.FeedbackEquip); + }, MenuOptionPriority.High); + } + else + { + return new FloatMenuOption( + label + ": " + disabledReason, + null, + MenuOptionPriority.DisabledOption); + } + } + + // 检查是否可以登机(带原因) + private bool CanPawnBoardMech(Pawn pawn, Thing mech, CompMechCrewHolder comp, ref string disabledReason) + { + // 检查机甲是否已满 + if (comp.IsFull) + { + disabledReason = "WULA_MechCrewFull".Translate(); + return false; + } + + // 检查Pawn是否可以成为乘员 + if (!comp.CanAddCrew(pawn)) + { + disabledReason = "WULA_CannotBecomeCrew".Translate(); + return false; + } + + // 检查Pawn是否已经在机甲内 + if (IsPawnInMech(pawn, mech)) + { + disabledReason = "AlreadyInMech".Translate(); + return false; + } + + // 检查距离 + if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly)) + { + disabledReason = "NoPath".Translate(); + return false; + } + + // 检查Pawn状态 + if (pawn.Downed) + { + disabledReason = "Downed".Translate(); + return false; + } + + if (pawn.Dead) + { + disabledReason = "Dead".Translate(); + return false; + } + + // 检查是否为囚犯 + if (pawn.IsPrisoner) + { + disabledReason = "Prisoner".Translate(); + return false; + } + + // 检查是否为奴隶 + if (pawn.IsSlave) + { + disabledReason = "Slave".Translate(); + return false; + } + + // 检查机甲状态 + if (mech is Pawn mechPawn && mechPawn.Downed) + { + disabledReason = "Downed".Translate(); + return false; + } + + if (mech is Pawn mechPawn2 && mechPawn2.Dead) + { + disabledReason = "Dead".Translate(); + return false; + } + + // 检查是否被征召(乘员不能是征召状态) + if (pawn.Drafted) + { + disabledReason = "Drafted".Translate(); + return false; + } + + return true; + } + + // 检查是否可以登机(简化版) + private bool CanPawnBoardMech(Pawn pawn, Thing mech, CompMechCrewHolder comp) + { + string disabledReason = ""; + return CanPawnBoardMech(pawn, mech, comp, ref disabledReason); + } + } +} diff --git a/Source/WulaFallenEmpire/Work/BoardMech/JobDriver_BoardMech.cs b/Source/WulaFallenEmpire/Work/BoardMech/JobDriver_BoardMech.cs new file mode 100644 index 00000000..bc02b470 --- /dev/null +++ b/Source/WulaFallenEmpire/Work/BoardMech/JobDriver_BoardMech.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using Verse; +using Verse.AI; +using RimWorld; + +namespace WulaFallenEmpire +{ + public class JobDriver_BoardMech : JobDriver + { + private const TargetIndex MechIndex = TargetIndex.A; + + private CompMechCrewHolder CrewComp => job.targetA.Thing?.TryGetComp(); + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + // 预留目标机甲 + if (!pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed)) + { + return false; + } + return true; + } + + protected override IEnumerable MakeNewToils() + { + // 第0步:添加失败条件 + AddFailCondition(() => + { + var mech = TargetThingA as Pawn; + if (mech == null || mech.Destroyed || mech.Dead) + return true; + + var comp = CrewComp; + if (comp == null || comp.IsFull || !comp.CanAddCrew(pawn)) + return true; + + if (pawn.Downed || pawn.Dead) + return true; + + return false; + }); + + // 第1步:走到机甲旁边 + yield return Toils_Goto.GotoThing(MechIndex, PathEndMode.Touch); + + // 第2步:等待短暂时间(可选) + yield return Toils_General.Wait(10).WithProgressBarToilDelay(MechIndex); + + // 第3步:登上机甲 + Toil boardToil = new Toil(); + boardToil.initAction = () => + { + var mech = TargetThingA as Pawn; + if (mech == null) + return; + + var comp = CrewComp; + if (comp != null && comp.CanAddCrew(pawn)) + { + comp.AddCrew(pawn); + } + }; + boardToil.defaultCompleteMode = ToilCompleteMode.Instant; + yield return boardToil; + } + } +} diff --git a/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs b/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs index ec8039bd..1114a1a3 100644 --- a/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs +++ b/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs @@ -1,6 +1,7 @@ -// File: FloatMenuOptionProvider_EnterMech.cs using RimWorld; +using System; using System.Collections.Generic; +using System.Linq; using Verse; using Verse.AI; @@ -8,6 +9,7 @@ namespace WulaFallenEmpire { public class FloatMenuOptionProvider_EnterMech : FloatMenuOptionProvider { + private static readonly List tmpPawns = new List(); // 检查Thing是否为机甲 private bool IsMech(Thing thing) @@ -15,9 +17,9 @@ namespace WulaFallenEmpire return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true; } - protected override bool Drafted => true; // 征召状态下不能进入机甲 + protected override bool Drafted => false; // 征召状态下不能进入机甲 protected override bool Undrafted => true; // 非征召状态下可以进入 - protected override bool Multiselect => true; // 不支持多选 + protected override bool Multiselect => true; // 支持多选 // 检查是否适用于当前上下文 protected override bool AppliesInt(FloatMenuContext context) @@ -50,40 +52,97 @@ namespace WulaFallenEmpire if (comp == null) return false; - // 检查殖民者是否已经在机甲内 - // 由于CompMechPilotHolder没有ContainsPilot方法,我们需要通过其他方式检查 - if (IsPawnInMech(context.FirstSelectedPawn, mech)) - return false; - return true; } - // 检查殖民者是否已经在机甲内(替代ContainsPilot) - private bool IsPawnInMech(Pawn pawn, Thing mech) + // 重写:获取选项 + public override IEnumerable GetOptionsFor(Thing clickedThing, FloatMenuContext context) { - var comp = mech.TryGetComp(); - if (comp == null) - return false; - - // 尝试通过内部容器检查 - var holder = comp as IThingHolder; - if (holder != null) + if (!AppliesInt(context)) + yield break; + + if (context.IsMultiselect) { - var things = holder.GetDirectlyHeldThings(); - if (things != null && things.Contains(pawn)) - return true; + var option = GetMultiselectEnterMechOption(clickedThing, context); + if (option != null) + yield return option; + yield break; } - // 或者尝试通过其他属性检查 - // 这里假设CompMechPilotHolder有HasPilots属性 - if (comp.HasPilots) + var singleOption = GetSingleOptionFor(clickedThing, context); + if (singleOption != null) + yield return singleOption; + } + + // 获取多选选项 + private FloatMenuOption GetMultiselectEnterMechOption(Thing clickedThing, FloatMenuContext context) + { + tmpPawns.Clear(); + + var mech = clickedThing as Wulamechunit; + var comp = mech?.TryGetComp(); + + if (mech == null || comp == null) + return null; + + // 收集所有可以进入机甲的Pawn + foreach (var pawn in context.ValidSelectedPawns) { - // 如果有必要,可以通过反射或其他方式检查具体驾驶员 - // 暂时返回false,假设不在机甲内 - return false; + if (CanPawnEnterMech(pawn, mech, comp)) + { + tmpPawns.Add(pawn); + } } - return false; + if (tmpPawns.Count == 0) + return null; + + // 检查是否有机甲已满的情况 + string failStr = null; + if (comp.IsFull) + { + failStr = "WULA_MechFull".Translate(); + } + + if (!failStr.NullOrEmpty()) + { + return new FloatMenuOption( + "WULA_EnterMech".Translate(mech.LabelShort) + ": " + failStr, + null, + MenuOptionPriority.DisabledOption + ); + } + + // 计算可以进入的数量 + int canEnterCount = 0; + foreach (var pawn in tmpPawns) + { + if (comp.HasRoom) + { + canEnterCount++; + } + else + { + break; + } + } + + string label = "WULA_EnterMech".Translate(mech.LabelShort); + + return new FloatMenuOption(label, () => + { + FleckMaker.Static(mech.DrawPos, mech.MapHeld, FleckDefOf.FeedbackEquip); + + // 为每个可以进入的Pawn创建Job + foreach (var pawn in tmpPawns) + { + if (comp.HasRoom && CanPawnEnterMech(pawn, mech, comp)) + { + Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, mech); + pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); + } + } + }, MenuOptionPriority.High); } // 获取单个选项 @@ -111,6 +170,25 @@ namespace WulaFallenEmpire return CreateEnterMechOption(mech, context.FirstSelectedPawn, comp); } + // 检查殖民者是否已经在机甲内 + private bool IsPawnInMech(Pawn pawn, Thing mech) + { + var comp = mech.TryGetComp(); + if (comp == null) + return false; + + // 尝试通过内部容器检查 + var holder = comp as IThingHolder; + if (holder != null) + { + var things = holder.GetDirectlyHeldThings(); + if (things != null && things.Contains(pawn)) + return true; + } + + return false; + } + // 创建进入机甲的菜单选项 private FloatMenuOption CreateEnterMechOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp) { @@ -118,7 +196,7 @@ namespace WulaFallenEmpire string disabledReason = ""; // 检查条件是否允许进入 - bool canEnter = CanEnterMech(mech, pawn, comp, ref disabledReason); + bool canEnter = CanPawnEnterMech(pawn, mech, comp, ref disabledReason); // 如果条件允许,创建可点击的选项 if (canEnter) @@ -129,7 +207,7 @@ namespace WulaFallenEmpire Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, mech); pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc); - // 播放音效(如果有的话) + // 播放音效 FleckMaker.Static(mech.DrawPos, mech.MapHeld, FleckDefOf.FeedbackEquip); }, MenuOptionPriority.High); } @@ -143,8 +221,8 @@ namespace WulaFallenEmpire } } - // 检查殖民者是否可以进入机甲 - private bool CanEnterMech(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason) + // 检查殖民者是否可以进入机甲(带原因) + private bool CanPawnEnterMech(Pawn pawn, Wulamechunit mech, CompMechPilotHolder comp, ref string disabledReason) { // 检查机甲是否已满 if (comp.IsFull) @@ -160,6 +238,13 @@ namespace WulaFallenEmpire return false; } + // 检查殖民者是否已经在机甲内 + if (IsPawnInMech(pawn, mech)) + { + disabledReason = "AlreadyInMech".Translate(); + return false; + } + // 检查距离 if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly)) { @@ -207,7 +292,21 @@ namespace WulaFallenEmpire return false; } + // 检查是否被征召(驾驶员不能是征召状态) + if (pawn.Drafted) + { + disabledReason = "Drafted".Translate(); + return false; + } + return true; } + + // 检查殖民者是否可以进入机甲(简化版) + private bool CanPawnEnterMech(Pawn pawn, Wulamechunit mech, CompMechPilotHolder comp) + { + string disabledReason = ""; + return CanPawnEnterMech(pawn, mech, comp, ref disabledReason); + } } } diff --git a/Source/WulaFallenEmpire/WulaDefOf.cs b/Source/WulaFallenEmpire/WulaDefOf.cs index d98eeede..1b5149dc 100644 --- a/Source/WulaFallenEmpire/WulaDefOf.cs +++ b/Source/WulaFallenEmpire/WulaDefOf.cs @@ -31,7 +31,7 @@ namespace WulaFallenEmpire public static JobDef WULA_ForceEjectPilot; public static JobDef WULA_CarryToMech; public static JobDef WULA_TransformPawn; - + public static JobDef WULA_BoardMech; static Wula_JobDefOf() { DefOfHelper.EnsureInitializedInCtor(typeof(Wula_JobDefOf)); diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 681553e3..a0596e88 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -102,8 +102,11 @@ + + + diff --git a/美术与文本源文件/Wula/UI/Commands/WULA_FlightToggle.sai2 b/美术与文本源文件/Wula/UI/Commands/WULA_FlightToggle.sai2 new file mode 100644 index 00000000..ad76a8a2 Binary files /dev/null and b/美术与文本源文件/Wula/UI/Commands/WULA_FlightToggle.sai2 differ