zc
This commit is contained in:
@@ -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<Pawn> tmpPawns = new List<Pawn>();
|
||||
|
||||
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<CompMechCrewHolder>() != null;
|
||||
}
|
||||
|
||||
// 检查Pawn是否在机甲内
|
||||
private bool IsPawnInMech(Pawn pawn, Thing mech)
|
||||
{
|
||||
var comp = mech.TryGetComp<CompMechCrewHolder>();
|
||||
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<FloatMenuOption> 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<CompMechCrewHolder>();
|
||||
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<CompMechCrewHolder>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<CompMechCrewHolder>();
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
// 预留目标机甲
|
||||
if (!pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Pawn> tmpPawns = new List<Pawn>();
|
||||
|
||||
// 检查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<FloatMenuOption> GetOptionsFor(Thing clickedThing, FloatMenuContext context)
|
||||
{
|
||||
var comp = mech.TryGetComp<CompMechPilotHolder>();
|
||||
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<CompMechPilotHolder>();
|
||||
|
||||
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<CompMechPilotHolder>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user