This commit is contained in:
Tourswen
2025-11-03 02:39:00 +08:00
parent 8f85bd00f3
commit 242866bada
183 changed files with 5967 additions and 3078 deletions

View File

@@ -38,7 +38,6 @@ namespace WulaFallenEmpire
Shutdown // 关机模式:立即休眠
}
public class CompProperties_AutonomousMech : CompProperties
{
public bool enableAutonomousDrafting = true;
@@ -70,7 +69,7 @@ namespace WulaFallenEmpire
{
get
{
if (MechPawn == null || MechPawn.Dead || MechPawn.Downed)
if (MechPawn == null || MechPawn.Dead )
return false;
if (!Props.enableAutonomousDrafting)
@@ -79,13 +78,6 @@ namespace WulaFallenEmpire
if (MechPawn.GetOverseer() != null)
return false;
if (Props.requirePowerForAutonomy)
{
// 在临界能量下不允许自主模式
if (GetEnergyLevel() < Props.criticalEnergyThreshold)
return false;
}
return true;
}
}
@@ -118,6 +110,33 @@ namespace WulaFallenEmpire
}
}
// 在 CompAutonomousMech 类中添加这个新属性
public bool CanFightAutonomously
{
get
{
if (MechPawn == null || MechPawn.Dead || MechPawn.Downed)
return false;
if (!Props.enableAutonomousDrafting)
return false;
if (MechPawn.GetOverseer() != null)
return false;
if (!MechPawn.drafter?.Drafted == true)
return false;
if (Props.requirePowerForAutonomy)
{
if (GetEnergyLevel() < Props.criticalEnergyThreshold)
return false;
}
return true;
}
}
public AutonomousWorkMode CurrentWorkMode => currentWorkMode;
// 新增:能量状态检查方法
@@ -131,7 +150,6 @@ namespace WulaFallenEmpire
public bool IsCriticalEnergy => GetEnergyLevel() < Props.criticalEnergyThreshold;
public bool IsFullyCharged => GetEnergyLevel() >= Props.rechargeCompleteThreshold;
// ... 现有代码 ...
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
@@ -139,6 +157,7 @@ namespace WulaFallenEmpire
// 确保使用独立战斗系统
InitializeAutonomousCombat();
}
private void InitializeAutonomousCombat()
{
// 确保有 draftController
@@ -152,48 +171,8 @@ namespace WulaFallenEmpire
{
MechPawn.drafter.FireAtWill = true;
}
}
// 确保工作设置不会干扰战斗
EnsureCombatWorkSettings();
}
private void EnsureCombatWorkSettings()
{
if (MechPawn.workSettings == null)
return;
// 设置自主战斗工作类型(如果存在)
WorkTypeDef autonomousCombat = DefDatabase<WorkTypeDef>.GetNamedSilentFail("WULA_AutonomousCombat");
if (autonomousCombat != null)
{
MechPawn.workSettings.SetPriority(autonomousCombat, 1);
}
}
public override void CompTick()
{
base.CompTick();
// 定期检查战斗状态
if (Find.TickManager.TicksGame % 60 == 0)
{
CheckCombatStatus();
}
}
private void CheckCombatStatus()
{
if (MechPawn.drafter?.Drafted == true && MechPawn.CurJob == null)
{
// 如果被征召但没有工作,强制进入自主战斗状态
ForceAutonomousCombat();
}
}
private void ForceAutonomousCombat()
{
JobDef autonomousCombatJob = DefDatabase<JobDef>.GetNamedSilentFail("WULA_AutonomousWaitCombat");
if (autonomousCombatJob != null)
{
Job job = JobMaker.MakeJob(autonomousCombatJob);
MechPawn.jobs.StartJob(job, JobCondition.InterruptForced);
}
}
public override void CompTick()
{
base.CompTick();
@@ -211,7 +190,6 @@ namespace WulaFallenEmpire
{
if (!CanWorkAutonomously)
return;
bool isLowEnergyNow = IsLowEnergy;
// 如果能量状态发生变化
@@ -374,4 +352,4 @@ namespace WulaFallenEmpire
Scribe_Values.Look(ref wasLowEnergy, "wasLowEnergy", false);
}
}
}
}

View File

@@ -1,234 +0,0 @@
// JobDriver_AutonomousWaitCombat.cs
using System;
using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class JobDriver_AutonomousWaitCombat : JobDriver
{
private const int TargetSearchInterval = 4;
private bool collideWithPawns;
private JobExtension_AutonomousCombat CombatExtension =>
job.def.GetModExtension<JobExtension_AutonomousCombat>();
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
return true;
}
protected override IEnumerable<Toil> MakeNewToils()
{
Toil waitToil = new Toil();
waitToil.initAction = delegate
{
if (pawn.Spawned)
{
pawn.Map.pawnDestinationReservationManager.Reserve(pawn, job, pawn.Position);
pawn.pather?.StopDead();
}
// 初始化战斗设置
InitializeCombatSettings();
// 立即检查攻击目标
CheckForAutoAttack();
};
waitToil.tickAction = delegate
{
// 定期检查攻击目标
if (Find.TickManager.TicksGame % TargetSearchInterval == 0)
{
CheckForAutoAttack();
}
// 处理朝向
HandleFacing();
};
waitToil.defaultCompleteMode = ToilCompleteMode.Never;
yield return waitToil;
}
private void InitializeCombatSettings()
{
var comp = pawn.GetComp<CompAutonomousMech>();
if (comp?.CanWorkAutonomously == true)
{
// 确保征召设置正确
if (pawn.drafter != null)
{
pawn.drafter.FireAtWill = CombatExtension?.forceFireAtWill ?? true;
}
}
}
private void HandleFacing()
{
// 如果有指定朝向,就面向该方向
if (job.overrideFacing != Rot4.Invalid)
{
pawn.rotationTracker.FaceTarget(pawn.Position + job.overrideFacing.FacingCell);
return;
}
// 如果有职责焦点,就面向焦点
if (pawn.mindState?.duty?.focus != null)
{
pawn.rotationTracker.FaceTarget(pawn.mindState.duty.focus);
return;
}
// 自动寻找敌人并面向它
Thing enemyTarget = FindNearestEnemy();
if (enemyTarget != null)
{
pawn.rotationTracker.FaceTarget(enemyTarget);
}
}
private void CheckForAutoAttack()
{
if (!CanAutoAttack())
return;
// 先检查近战攻击
if (CheckMeleeAttack())
return;
// 再检查远程攻击
CheckRangedAttack();
}
private bool CanAutoAttack()
{
// 基础状态检查
if (pawn.Downed || pawn.stances.FullBodyBusy || pawn.IsCarryingPawn())
return false;
var comp = pawn.GetComp<CompAutonomousMech>();
if (comp?.CanWorkAutonomously != true)
return false;
// 检查扩展设置
if (CombatExtension?.autoAttackEnabled != true)
return false;
// 忽略工作标签检查,因为这是独立系统
if (!CombatExtension.ignoreWorkTags)
{
if (pawn.WorkTagIsDisabled(WorkTags.Violent))
return false;
}
return true;
}
private bool CheckMeleeAttack()
{
if (!pawn.kindDef.canMeleeAttack)
return false;
// 检查相邻格子的敌人
for (int i = 0; i < 9; i++)
{
IntVec3 cell = pawn.Position + GenAdj.AdjacentCellsAndInside[i];
if (!cell.InBounds(pawn.Map))
continue;
foreach (Thing thing in cell.GetThingList(pawn.Map))
{
if (thing is Pawn targetPawn && IsValidMeleeTarget(targetPawn))
{
pawn.meleeVerbs.TryMeleeAttack(targetPawn);
collideWithPawns = true;
return true;
}
}
}
return false;
}
private bool IsValidMeleeTarget(Pawn target)
{
return !target.ThreatDisabled(pawn) &&
pawn.HostileTo(target) &&
GenHostility.IsActiveThreatTo(target, pawn.Faction) &&
!pawn.ThreatDisabledBecauseNonAggressiveRoamer(target);
}
private void CheckRangedAttack()
{
if (!CanUseRangedWeapon())
return;
Verb verb = pawn.CurrentEffectiveVerb;
if (verb == null || verb.verbProps.IsMeleeAttack)
return;
Thing shootTarget = FindRangedTarget();
if (shootTarget != null)
{
pawn.TryStartAttack(shootTarget);
collideWithPawns = true;
}
}
private bool CanUseRangedWeapon()
{
if (!CombatExtension?.canUseRangedWeapon ?? false)
return false;
// 检查武器
if (pawn.equipment?.Primary == null || !pawn.equipment.Primary.def.IsRangedWeapon)
return false;
// 检查 FireAtWill 设置
if (pawn.drafter != null && !pawn.drafter.FireAtWill)
return false;
return true;
}
private Thing FindRangedTarget()
{
int searchRadius = CombatExtension?.attackSearchRadius ?? 25;
TargetScanFlags flags = TargetScanFlags.NeedLOSToAll |
TargetScanFlags.NeedThreat |
TargetScanFlags.NeedAutoTargetable;
if (pawn.CurrentEffectiveVerb?.IsIncendiary_Ranged() == true)
{
flags |= TargetScanFlags.NeedNonBurning;
}
return (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(
pawn, flags, null, 0f, searchRadius);
}
private Thing FindNearestEnemy()
{
int searchRadius = CombatExtension?.attackSearchRadius ?? 25;
return (Thing)AttackTargetFinder.BestAttackTarget(
pawn,
TargetScanFlags.NeedThreat,
x => x is Pawn p && pawn.HostileTo(p),
0f, searchRadius,
default,
float.MaxValue,
canTakeTargets: true);
}
public override string GetReport()
{
return "WULA_StandingGuard".Translate(); // 自定义报告文本
}
}
}

View File

@@ -1,14 +0,0 @@
// JobExtension_AutonomousCombat.cs
using Verse;
namespace WulaFallenEmpire
{
public class JobExtension_AutonomousCombat : DefModExtension
{
public bool canUseRangedWeapon = true;
public bool autoAttackEnabled = true;
public int attackSearchRadius = 25;
public bool ignoreWorkTags = true;
public bool forceFireAtWill = true;
}
}

View File

@@ -1,42 +0,0 @@
// JobGiver_AutonomousCombat.cs
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class JobGiver_AutonomousCombat : ThinkNode_JobGiver
{
public float priority = 8f;
public int expiryInterval = 30;
public override float GetPriority(Pawn pawn)
{
// 只有在征召状态下才有优先级
if (pawn.drafter?.Drafted == true &&
pawn.GetComp<CompAutonomousMech>()?.CanWorkAutonomously == true)
{
return priority;
}
return 0f;
}
protected override Job TryGiveJob(Pawn pawn)
{
// 确保是自主机械族且被征召
var comp = pawn.GetComp<CompAutonomousMech>();
if (comp?.CanWorkAutonomously != true || pawn.drafter?.Drafted != true)
return null;
// 创建自主战斗工作
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_AutonomousWaitCombat"));
job.expiryInterval = expiryInterval;
job.checkOverrideOnDamage = true;
// 设置工作标签,确保不会被其他工作干扰
pawn.mindState?.prioritizedWork?.Clear();
return job;
}
}
}

View File

@@ -1,37 +0,0 @@
// JobGiver_AutonomousWaitCombat.cs
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class JobGiver_AutonomousWaitCombat : ThinkNode_JobGiver
{
public bool canUseRangedWeapon = true;
public override float GetPriority(Pawn pawn)
{
// 只有在征召状态下才有高优先级
if (pawn.drafter?.Drafted == true)
{
return 9.5f; // 比常规工作低,但比空闲高
}
return 0f;
}
protected override Job TryGiveJob(Pawn pawn)
{
// 只有在征召状态下才使用 Wait_Combat
if (pawn.drafter?.Drafted == true &&
pawn.GetComp<CompAutonomousMech>()?.CanWorkAutonomously == true)
{
Job job = JobMaker.MakeJob(JobDefOf.Wait_Combat);
job.canUseRangedWeapon = canUseRangedWeapon;
job.expiryInterval = 30; // 短时间,便于重新评估
return job;
}
return null;
}
}
}

View File

@@ -0,0 +1,31 @@
using HarmonyLib;
using RimWorld;
using Verse;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(FloatMenuOptionProvider), "SelectedPawnValid")]
public static class Patch_FloatMenuOptionProvider_SelectedPawnValid
{
[HarmonyPostfix]
public static void Postfix(Pawn pawn, FloatMenuContext context, ref bool __result)
{
// 如果已经有效,不需要修改
if (__result)
return;
// 检查是否是机械族且被原版逻辑拒绝
if (!pawn.RaceProps.IsMechanoid)
return;
// 检查是否有自主机械组件
var comp = pawn.GetComp<CompAutonomousMech>();
if (comp == null || !comp.CanWorkAutonomously)
return;
// 对于自主机械族直接返回true跳过机械族限制
// 其他条件已经在原版方法中检查过了
__result = true;
}
}
}

View File

@@ -0,0 +1,41 @@
using HarmonyLib;
using RimWorld;
using Verse;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(Pawn), "get_IsColonyMechPlayerControlled")]
public static class Patch_IsColonyMechPlayerControlled
{
[HarmonyPostfix]
public static void Postfix(Pawn __instance, ref bool __result)
{
// 如果原版已经返回true不需要修改
if (__result)
return;
// 检查是否是殖民地机械
if (!__instance.IsColonyMech)
return;
// 检查是否有自主机械组件
var comp = __instance.GetComp<CompAutonomousMech>();
if (comp == null)
return;
// 如果机械族处于自主战斗模式,则视为玩家控制
if (comp.CanFightAutonomously)
{
__result = true;
return;
}
// 如果机械族处于自主工作模式,也视为玩家控制(用于工作相关判定)
if (comp.CanWorkAutonomously)
{
__result = true;
return;
}
}
}
}