1
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
// File: FloatMenuOptionProvider_EnterMech.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class FloatMenuOptionProvider_EnterMech : FloatMenuOptionProvider
|
||||
{
|
||||
|
||||
// 检查Thing是否为机甲
|
||||
private bool IsMech(Thing thing)
|
||||
{
|
||||
return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
|
||||
}
|
||||
|
||||
protected override bool Drafted => true; // 征召状态下不能进入机甲
|
||||
protected override bool Undrafted => true; // 非征召状态下可以进入
|
||||
protected override bool Multiselect => true; // 不支持多选
|
||||
|
||||
// 检查是否适用于当前上下文
|
||||
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 mech = null;
|
||||
foreach (var thing in clickedThings)
|
||||
{
|
||||
if (IsMech(thing))
|
||||
{
|
||||
mech = thing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mech == null)
|
||||
return false;
|
||||
|
||||
// 检查机甲是否有驾驶员组件
|
||||
var comp = mech.TryGetComp<CompMechPilotHolder>();
|
||||
if (comp == null)
|
||||
return false;
|
||||
|
||||
// 检查殖民者是否已经在机甲内
|
||||
// 由于CompMechPilotHolder没有ContainsPilot方法,我们需要通过其他方式检查
|
||||
if (IsPawnInMech(context.FirstSelectedPawn, mech))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查殖民者是否已经在机甲内(替代ContainsPilot)
|
||||
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;
|
||||
}
|
||||
|
||||
// 或者尝试通过其他属性检查
|
||||
// 这里假设CompMechPilotHolder有HasPilots属性
|
||||
if (comp.HasPilots)
|
||||
{
|
||||
// 如果有必要,可以通过反射或其他方式检查具体驾驶员
|
||||
// 暂时返回false,假设不在机甲内
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取单个选项
|
||||
protected override FloatMenuOption GetSingleOptionFor(Thing clickedThing, FloatMenuContext context)
|
||||
{
|
||||
if (clickedThing == null || context.FirstSelectedPawn == null)
|
||||
return null;
|
||||
|
||||
// 如果不是机甲,返回null
|
||||
if (!IsMech(clickedThing))
|
||||
return null;
|
||||
|
||||
// 获取机甲和组件
|
||||
var mech = clickedThing as Wulamechunit;
|
||||
var comp = mech?.TryGetComp<CompMechPilotHolder>();
|
||||
|
||||
if (mech == null || comp == null)
|
||||
return null;
|
||||
|
||||
// 检查殖民者是否已经在机甲内
|
||||
if (IsPawnInMech(context.FirstSelectedPawn, mech))
|
||||
return null;
|
||||
|
||||
// 检查各种条件,生成相应的菜单选项
|
||||
return CreateEnterMechOption(mech, context.FirstSelectedPawn, comp);
|
||||
}
|
||||
|
||||
// 创建进入机甲的菜单选项
|
||||
private FloatMenuOption CreateEnterMechOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp)
|
||||
{
|
||||
string label = "WULA_EnterMech".Translate(mech.LabelShort);
|
||||
string disabledReason = "";
|
||||
|
||||
// 检查条件是否允许进入
|
||||
bool canEnter = CanEnterMech(mech, pawn, comp, ref disabledReason);
|
||||
|
||||
// 如果条件允许,创建可点击的选项
|
||||
if (canEnter)
|
||||
{
|
||||
return new FloatMenuOption(label, () =>
|
||||
{
|
||||
// 创建进入机甲的工作
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 创建禁用的选项,显示原因
|
||||
return new FloatMenuOption(
|
||||
"WULA_EnterMech".Translate(mech.LabelShort) + ": " + disabledReason,
|
||||
null,
|
||||
MenuOptionPriority.DisabledOption);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查殖民者是否可以进入机甲
|
||||
private bool CanEnterMech(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason)
|
||||
{
|
||||
// 检查机甲是否已满
|
||||
if (comp.IsFull)
|
||||
{
|
||||
disabledReason = "WULA_MechFull".Translate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查殖民者是否可以成为驾驶员
|
||||
if (!comp.CanAddPilot(pawn))
|
||||
{
|
||||
disabledReason = "WULA_CannotBecomePilot".Translate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查距离
|
||||
if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly))
|
||||
{
|
||||
disabledReason = "NoPath".Translate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查殖民者状态
|
||||
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.Downed)
|
||||
{
|
||||
disabledReason = "Downed".Translate();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mech.Dead)
|
||||
{
|
||||
disabledReason = "Dead".Translate();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// File: JobDriver_EnterMech.cs (不再保留机甲)
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class JobDriver_EnterMech : JobDriver
|
||||
{
|
||||
private const TargetIndex MechIndex = TargetIndex.A;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
Pawn pawn = this.pawn;
|
||||
LocalTargetInfo target = this.job.GetTarget(MechIndex);
|
||||
|
||||
// 不再保留机甲,这样多个殖民者可以同时被命令进入同一个机甲
|
||||
// 只需要检查殖民者是否可以到达机甲
|
||||
if (!pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 0. 初始检查
|
||||
AddFailCondition(() =>
|
||||
{
|
||||
var mech = TargetThingA as Wulamechunit;
|
||||
if (mech == null || mech.Destroyed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var comp = mech.GetComp<CompMechPilotHolder>();
|
||||
if (comp == null || comp.IsFull || !comp.CanAddPilot(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 enterToil = new Toil();
|
||||
enterToil.initAction = () =>
|
||||
{
|
||||
var mech = TargetThingA as Wulamechunit;
|
||||
if (mech == null)
|
||||
return;
|
||||
|
||||
var comp = mech.GetComp<CompMechPilotHolder>();
|
||||
if (comp != null && comp.CanAddPilot(pawn))
|
||||
{
|
||||
comp.AddPilot(pawn);
|
||||
Messages.Message("WULA_PilotEnteredMech".Translate(pawn.LabelShort, mech.LabelShort),
|
||||
MessageTypeDefOf.PositiveEvent, false);
|
||||
}
|
||||
};
|
||||
enterToil.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
yield return enterToil;
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
Normal file
188
Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
// File: WorkGiver_EnterMech.cs
|
||||
using RimWorld;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class WorkGiver_EnterMech : WorkGiver_Scanner
|
||||
{
|
||||
// 缓存机甲定义列表
|
||||
private static List<ThingDef> cachedMechDefs = null;
|
||||
|
||||
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||
|
||||
// 获取所有机甲定义的列表
|
||||
private List<ThingDef> GetAllMechDefs()
|
||||
{
|
||||
if (cachedMechDefs == null)
|
||||
{
|
||||
cachedMechDefs = new List<ThingDef>();
|
||||
|
||||
// 搜索所有ThingDef,找出继承自Wulamechunit的类
|
||||
foreach (var def in DefDatabase<ThingDef>.AllDefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (def.thingClass == typeof(Wulamechunit) ||
|
||||
def.thingClass?.IsSubclassOf(typeof(Wulamechunit)) == true)
|
||||
{
|
||||
cachedMechDefs.Add(def);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 忽略错误,继续搜索
|
||||
Log.Warning($"[WULA] Error checking ThingDef {def.defName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cachedMechDefs;
|
||||
}
|
||||
|
||||
// 检查Thing是否为机甲
|
||||
private bool IsMech(Thing thing)
|
||||
{
|
||||
return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
|
||||
}
|
||||
|
||||
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查基本条件
|
||||
if (t == null || pawn == null)
|
||||
return false;
|
||||
|
||||
// 必须是Wulamechunit或其子类
|
||||
if (!IsMech(t))
|
||||
return false;
|
||||
|
||||
// 检查距离
|
||||
if (!pawn.CanReach(t, PathEndMode, Danger.Deadly))
|
||||
return false;
|
||||
|
||||
// 检查机甲是否有驾驶员槽位组件
|
||||
var comp = t.TryGetComp<CompMechPilotHolder>();
|
||||
if (comp == null)
|
||||
return false;
|
||||
|
||||
// 检查是否已满
|
||||
if (comp.IsFull)
|
||||
return false;
|
||||
|
||||
// 检查殖民者是否可以成为驾驶员
|
||||
if (!comp.CanAddPilot(pawn))
|
||||
return false;
|
||||
|
||||
// 检查殖民者状态
|
||||
if (pawn.Downed || pawn.Dead)
|
||||
return false;
|
||||
|
||||
// 检查殖民者是否正在执行任务
|
||||
if (pawn.CurJob != null && pawn.CurJob.def != JobDefOf.Wait)
|
||||
return false;
|
||||
|
||||
// 检查是否被征召
|
||||
if (pawn.Drafted)
|
||||
return false;
|
||||
|
||||
// 检查是否为囚犯
|
||||
if (pawn.IsPrisoner)
|
||||
return false;
|
||||
|
||||
// 检查是否为奴隶
|
||||
if (pawn.IsSlave)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[WULA] Error in HasJobOnThing: {ex}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsMech(t))
|
||||
{
|
||||
// 创建进入机甲的工作
|
||||
return JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, t);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[WULA] Error creating job: {ex}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 只搜索玩家拥有的机甲
|
||||
List<Thing> potentialMechs = new List<Thing>();
|
||||
|
||||
// 获取地图中的所有机甲
|
||||
if (pawn.Map != null)
|
||||
{
|
||||
// 使用缓存的机甲定义列表
|
||||
var mechDefs = GetAllMechDefs();
|
||||
|
||||
foreach (var def in mechDefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var allMechs = pawn.Map.listerThings.ThingsOfDef(def);
|
||||
foreach (var mech in allMechs)
|
||||
{
|
||||
if (mech.Faction == Faction.OfPlayer &&
|
||||
mech.TryGetComp<CompMechPilotHolder>() != null)
|
||||
{
|
||||
potentialMechs.Add(mech);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning($"[WULA] Error getting mechs for def {def.defName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return potentialMechs;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[WULA] Error in PotentialWorkThingsGlobal: {ex}");
|
||||
return Enumerable.Empty<Thing>();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShouldSkip(Pawn pawn, bool forced = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 简化版本:只检查殖民者状态
|
||||
if (pawn.Downed || pawn.Dead || pawn.Drafted || pawn.IsPrisoner || pawn.IsSlave)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[WULA] Error in ShouldSkip: {ex}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user