diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index fa641e81..9da1e209 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/ThingDefs_Races/Races_Wulaspecies.xml b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml index 72811c46..1643202d 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml @@ -903,6 +903,225 @@ + + + BulletImpact_Metal + + 1200 + 0.5 + 1 + 0 + -100 + 250 + 0 + 2.00 + 3.4 + 1 + 12 + 1 + 0.33 + 5 + 0.5 + 0.10 + 0.20 + 0.66 + + true + None + + Mechanoid + false + false + None + 2500 + Filth_MachineBits + NamerMech + 1000~2000 + 2 + MechConstant + true + Mech_Light + ToolUser + WULA_AutonomousMech + 0.7 + Light + + + 10 + + +
  • + + +
  • Blunt
  • + + 6 + 2.6 + HeadAttackTool + true + +
    + +
  • + CompMechanoid +
  • +
  • + true + 30 + MechanoidsWakeUp +
  • + +
  • + true + true + true +
  • + +
  • +
  • +
  • + + -10 + 999999 + 0 +
  • +
    +
    + + + + + 5 + + 0 + + + +
  • + MechanoidFullyFormed +
  • +
    + + DeathActionWorker_Vanish + Filth_MachineBits + 1~2 + +
    + +
  • + Mech_WULA_Cat_Cute + 5.9 + false + false + true +
  • +
    +
    + + Mech_WULA_Cat + + 乌拉帝国的一种小型自律机械体,无需监管者,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作,因为似猫的外形受到乌拉星人欢迎。 + Wula/Things/WULA_Cat/WULA_Cat_Thin_south + + + 6 + 0.001 + + + +
  • Hauling
  • + + + + + +
  • Cooking
  • + +
  • PlantCutting
  • +
  • Growing
  • +
  • Cleaning
  • +
  • Doctor
  • +
  • Firefighter
  • +
    +
    +
    + + Mech_WULA_Cat_EMP + + 乌拉帝国的一种小型自律机械体,无需监管者,只能执行救火、搬运和清扫任务,但是相比起基础型号多配备了一个EMP投掷物,可以辅助乌拉帝国军团对抗机械部队。 + + + Mech_WULA_Cat_Fire + + 乌拉帝国的一种小型自律机械体,无需监管者,只能执行救火、搬运和清扫任务,但是相比起基础型号多配备了一个燃烧瓶投掷物,可以点燃靠近阵线的敌军。 + + + Mech_WULA_Cat_Constructor + + 乌拉帝国的一种小型自律机械体,无需监管者,只能执行建造和开采任务,可以跳起来用手上的HAm-1"装修锤"锤烂敌人的膝盖。 + Wula/Things/WULA_Constructor_Cat/WULA_Cat_Thin_south + + +
  • Mining
  • +
  • Construction
  • +
    +
    + + 2 + +
    + + Mech_WULA_Cat_Assault + + 乌拉帝国的一种小型自律机械体,无需监管者,可以执行搬运、狩猎和割除任务,身着轻甲,装备了一把DLa-4"云母"突击步枪附下挂刺刀,可以给敌方造成不小的麻烦。 + Wula/Things/WULA_Assault_Cat/WULA_Cat_Thin_south + + +
  • Hunting
  • +
  • Hauling
  • +
  • PlantCutting
  • +
    +
    + + 0.25 + 0.25 + + 4 + +
    + + Mech_WULA_Cat_DM + + 乌拉帝国的一种小型自律机械体,无需监管者,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作。这种型号的乌拉猫猫内置了一台不稳定暗物质引擎,这使得其无需充电,但是在死亡时会产生巨大的爆炸。 + Wula/Things/WULA_DM_Cat/WULA_Cat_Thin_south + + + 6 + 0.001 + -1 + + + +
  • Hauling
  • +
  • Cooking
  • +
  • PlantCutting
  • +
  • Growing
  • +
  • Cleaning
  • +
  • Doctor
  • +
  • Firefighter
  • +
    +
    + +
  • + 30 + BombSuper + 550 +
  • +
    +
    + + + Wula_AI_Heavy_Panzer @@ -1287,252 +1506,6 @@ - - - Mech_WULA_Cat - - 乌拉帝国的一种小型机械体,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作,因为似猫的外形受到乌拉星人欢迎。 - Wula/Things/WULA_Cat/WULA_Cat_Thin_south - - - 6 - 0.001 - - 0 - - - -
  • Hauling
  • - - - - - -
  • Cooking
  • - -
  • PlantCutting
  • -
  • Growing
  • -
  • Cleaning
  • -
  • Doctor
  • -
  • Firefighter
  • -
    - -
  • - MechanoidFullyFormed -
  • -
    - - - - - DeathActionWorker_Vanish - Filth_MachineBits - 1~2 - -
    - - -
  • -
  • - Mech_WULA_Cat_Cute - 5.9 - false - true - true -
  • -
    - -
    - - - Wula/Things/WULA_Attack_Cat/WULA_Cat_Thin_south - - - 5 - - 0 - - - WULA_AutonomousMech - -
  • Hauling
  • - - - - - - - - - -
  • Cleaning
  • - -
  • Firefighter
  • -
    - -
  • - MechanoidFullyFormed -
  • -
    - - - - - DeathActionWorker_Vanish - Filth_MachineBits - 1~2 - -
    - -
  • - true - true - true -
  • - -
  • -
  • - Mech_WULA_Cat_Cute - 5.9 - false - true - true -
  • -
    - -
    - - Mech_WULA_Cat_EMP - - 乌拉帝国的一种小型机械体,只能执行救火、搬运和清扫任务,但是相比起基础型号多配备了一个EMP投掷物,可以辅助乌拉帝国军团对抗机械部队。 - - - Mech_WULA_Cat_Fire - - 乌拉帝国的一种小型机械体,只能执行救火、搬运和清扫任务,但是相比起基础型号多配备了一个燃烧瓶投掷物,可以点燃靠近阵线的敌军。 - - - Mech_WULA_Cat_Constructor - - 乌拉帝国的一种小型机械体,只能执行建造和开采任务,可以跳起来用手上的HAm-1"装修锤"锤烂敌人的膝盖。 - Wula/Things/WULA_Constructor_Cat/WULA_Cat_Thin_south - - -
  • Mining
  • -
  • Construction
  • -
    -
    - - 2 - -
    - - Mech_WULA_Cat_Assault - - 乌拉帝国的一种小型机械体,可以执行搬运、狩猎和割除任务,身着轻甲,装备了一把DLa-4"云母"突击步枪附下挂刺刀,可以给敌方造成不小的麻烦。 - Wula/Things/WULA_Assault_Cat/WULA_Cat_Thin_south - - -
  • Hunting
  • -
  • Hauling
  • -
  • PlantCutting
  • -
    -
    - - 0.25 - 0.25 - - 4 - -
    - - Mech_WULA_Cat_DM - - 乌拉帝国的一种小型机械体,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作。这种型号的乌拉猫猫内置了一台不稳定暗物质引擎,这使得其无需充电,但是在死亡时会产生巨大的爆炸。 - Wula/Things/WULA_DM_Cat/WULA_Cat_Thin_south - - - 6 - 0.001 - -1 - - - 0 - - - -
  • Hauling
  • - - - - - -
  • Cooking
  • - -
  • PlantCutting
  • -
  • Growing
  • -
  • Cleaning
  • -
  • Doctor
  • -
  • Firefighter
  • -
    - -
  • - MechanoidFullyFormed -
  • -
    - - - - - DeathActionWorker_Vanish - Filth_MachineBits - 1~2 - -
    - - -
  • -
  • - 30 - BombSuper - 550 -
  • -
  • - Mech_WULA_Cat_Cute - 5.9 - false - true - true -
  • -
    -
    WULA_Fxxk_Goose diff --git a/1.6/1.6/Defs/ThinkTreeDefs/WULA_AutonomousMech.xml b/1.6/1.6/Defs/ThinkTreeDefs/WULA_AutonomousMech.xml index 6430b576..d49741ee 100644 --- a/1.6/1.6/Defs/ThinkTreeDefs/WULA_AutonomousMech.xml +++ b/1.6/1.6/Defs/ThinkTreeDefs/WULA_AutonomousMech.xml @@ -21,9 +21,12 @@ Downed - -
  • + +
  • + 0.05 +
  • +
  • @@ -46,14 +49,19 @@
  • - -
  • + +
  • DraftedOrder
  • + +
  • + 8 + 30 +
  • @@ -70,6 +78,14 @@
  • + +
  • + 0.3 + +
  • + +
  • +
  • @@ -82,7 +98,14 @@ Work
  • -
  • + + +
  • + 0.2 + +
  • + +
  • @@ -119,9 +142,26 @@ Recharge
  • + + +
  • + 0.9 + + +
  • + None + 充电完成 +
  • + + + +
  • -
  • - true + + +
  • + None + 等待空闲充电站
  • @@ -166,4 +206,36 @@ + + + + WULA_AutonomousCombat + + 战斗中 + 战斗 + false + 99 + Violent + true + + + + WULA_AutonomousWaitCombat + WulaFallenEmpire.JobDriver_AutonomousWaitCombat + standing guard. + true + true + false + true + false + true + false + +
  • + true + true + 35 +
  • +
    +
    diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml index 03a2b5ee..b4ddf964 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml @@ -6,5 +6,37 @@ 自动生产 切换是否自动生产单位。开启后,当资源和冷却允许时,会自动生产单位以维持队列上限。 自动生产已开启。再次点击以关闭。 + + + 行为模式:{0} + 修改自律机械的行为模式 + + 工作 + 充电 + 关机 + 未知 + + 工作模式 - 根据机体设定,自行进行工作 + 充电模式 - 充电后休眠 + 关机模式 - 立即关机,会在此状态下以非常缓慢的速率充电 + + + 自主操作中 + 自主模式:{0} + + + ({0}) + ({0}) + 当前能量:{0} + (低电量) + (电量危急!) + + + {0}电量不足,切换到充电模式 + {0}已充满电,返回工作模式 + {0}电量危急! + {0}切换到{1}模式 + 征召自律机械 + 使自律机械进入征召状态 \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs index 4f43a9ae..d02b8108 100644 --- a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs @@ -38,13 +38,19 @@ namespace WulaFallenEmpire Shutdown // 关机模式:立即休眠 } + public class CompProperties_AutonomousMech : CompProperties { public bool enableAutonomousDrafting = true; public bool enableAutonomousWork = true; public bool requirePowerForAutonomy = true; public bool suppressUncontrolledWarning = true; - + + // 新增:能量管理设置 + public float lowEnergyThreshold = 0.3f; // 低能量阈值 + public float criticalEnergyThreshold = 0.1f; // 临界能量阈值 + public float rechargeCompleteThreshold = 0.9f; // 充电完成阈值 + public CompProperties_AutonomousMech() { compClass = typeof(CompAutonomousMech); @@ -54,202 +60,290 @@ namespace WulaFallenEmpire public class CompAutonomousMech : ThingComp { public CompProperties_AutonomousMech Props => (CompProperties_AutonomousMech)props; - + public Pawn MechPawn => parent as Pawn; - - // 新增:当前工作模式 + private AutonomousWorkMode currentWorkMode = AutonomousWorkMode.Work; - + private bool wasLowEnergy = false; // 记录上次是否处于低能量状态 + public bool CanBeAutonomous { get { if (MechPawn == null || MechPawn.Dead || MechPawn.Downed) return false; - + if (!Props.enableAutonomousDrafting) return false; - + if (MechPawn.GetOverseer() != null) return false; - + if (Props.requirePowerForAutonomy) { - var energyNeed = MechPawn.needs?.TryGetNeed(); - if (energyNeed != null && energyNeed.CurLevelPercentage < 0.1f) + // 在临界能量下不允许自主模式 + if (GetEnergyLevel() < Props.criticalEnergyThreshold) return false; } - + return true; } } - + public bool CanWorkAutonomously { get { if (!Props.enableAutonomousWork) return false; - + if (!CanBeAutonomous) return false; - + if (MechPawn.Drafted) return false; - + return true; } } - + public bool ShouldSuppressUncontrolledWarning { get { if (!Props.suppressUncontrolledWarning) return false; - + return CanBeAutonomous; } } - // 新增:公开访问当前工作模式 public AutonomousWorkMode CurrentWorkMode => currentWorkMode; + // 新增:能量状态检查方法 + public float GetEnergyLevel() + { + var energyNeed = MechPawn.needs?.TryGetNeed(); + return energyNeed?.CurLevelPercentage ?? 0f; + } + + public bool IsLowEnergy => GetEnergyLevel() < Props.lowEnergyThreshold; + public bool IsCriticalEnergy => GetEnergyLevel() < Props.criticalEnergyThreshold; + public bool IsFullyCharged => GetEnergyLevel() >= Props.rechargeCompleteThreshold; + + // ... 现有代码 ... public override void PostSpawnSetup(bool respawningAfterLoad) { base.PostSpawnSetup(respawningAfterLoad); - - if (MechPawn != null && MechPawn.IsColonyMech) + + // 确保使用独立战斗系统 + InitializeAutonomousCombat(); + } + private void InitializeAutonomousCombat() + { + // 确保有 draftController + if (MechPawn.drafter == null) { + MechPawn.drafter = new Pawn_DraftController(MechPawn); + } + + // 强制启用 FireAtWill + if (MechPawn.drafter != null) + { + MechPawn.drafter.FireAtWill = true; + } + + // 确保工作设置不会干扰战斗 + EnsureCombatWorkSettings(); + } + private void EnsureCombatWorkSettings() + { + if (MechPawn.workSettings == null) + return; + // 设置自主战斗工作类型(如果存在) + WorkTypeDef autonomousCombat = DefDatabase.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.GetNamedSilentFail("WULA_AutonomousWaitCombat"); + if (autonomousCombatJob != null) + { + Job job = JobMaker.MakeJob(autonomousCombatJob); + MechPawn.jobs.StartJob(job, JobCondition.InterruptForced); + } + } + public override void CompTick() + { + base.CompTick(); + + // 每60 tick检查一次能量状态 + if (MechPawn != null && MechPawn.IsColonyMech && Find.TickManager.TicksGame % 60 == 0) + { + CheckEnergyStatus(); EnsureWorkSettings(); } } + // 新增:能量状态检查 + private void CheckEnergyStatus() + { + if (!CanWorkAutonomously) + return; + + bool isLowEnergyNow = IsLowEnergy; + + // 如果能量状态发生变化 + if (isLowEnergyNow != wasLowEnergy) + { + if (isLowEnergyNow) + { + // 进入低能量状态 + if (currentWorkMode == AutonomousWorkMode.Work) + { + // 自动切换到充电模式 + SetWorkMode(AutonomousWorkMode.Recharge); + Messages.Message("WULA_LowEnergySwitchToRecharge".Translate(MechPawn.LabelCap), + MechPawn, MessageTypeDefOf.CautionInput); + } + } + else + { + // 恢复能量状态 + if (currentWorkMode == AutonomousWorkMode.Recharge && IsFullyCharged) + { + // 充满电后自动切换回工作模式 + SetWorkMode(AutonomousWorkMode.Work); + Messages.Message("WULA_FullyChargedSwitchToWork".Translate(MechPawn.LabelCap), + MechPawn, MessageTypeDefOf.PositiveEvent); + } + } + + wasLowEnergy = isLowEnergyNow; + } + + // 临界能量警告 + if (IsCriticalEnergy && currentWorkMode != AutonomousWorkMode.Recharge && currentWorkMode != AutonomousWorkMode.Shutdown) + { + Messages.Message("WULA_CriticalEnergyLevels".Translate(MechPawn.LabelCap), + MechPawn, MessageTypeDefOf.ThreatBig); + // 强制切换到充电模式 + SetWorkMode(AutonomousWorkMode.Recharge); + } + } + public override IEnumerable CompGetGizmosExtra() { if (MechPawn == null || !CanBeAutonomous) yield break; - - // 自主征召按钮 - yield return new Command_Toggle - { - defaultLabel = "Autonomous Mode", - defaultDesc = "Enable autonomous operation without mechanitor control", - icon = TexCommand.Draft, - isActive = () => MechPawn.Drafted, - toggleAction = () => ToggleAutonomousDraft(), - hotKey = KeyBindingDefOf.Misc1 - }; - + // 工作模式切换按钮 if (CanWorkAutonomously) { + string energyInfo = "WULA_EnergyInfo".Translate(GetEnergyLevel().ToStringPercent()); yield return new Command_Action { - defaultLabel = "Work Mode: " + GetCurrentWorkModeDisplay(), - defaultDesc = "Switch autonomous work mode", - icon = TexCommand.Attack, + defaultLabel = "WULA_Mech_WorkMode".Translate(GetCurrentWorkModeDisplay()) + energyInfo, + defaultDesc = GetWorkModeDescription(), + icon = GetWorkModeIcon(), action = () => ShowWorkModeMenu() }; } } - private void ToggleAutonomousDraft() + // 修改:返回包含能量信息的描述 + private string GetWorkModeDescription() { - if (MechPawn.drafter == null) - return; + string baseDesc = "WULA_Switch_Mech_WorkMode".Translate(); + string energyInfo = "WULA_CurrentEnergy".Translate(GetEnergyLevel().ToStringPercent()); - if (MechPawn.Drafted) - { - MechPawn.drafter.Drafted = false; - Messages.Message($"{MechPawn.LabelCap} autonomous mode deactivated", - MechPawn, MessageTypeDefOf.NeutralEvent); - } - else - { - if (CanBeAutonomous) - { - MechPawn.drafter.Drafted = true; - Messages.Message($"{MechPawn.LabelCap} is now operating autonomously", - MechPawn, MessageTypeDefOf.PositiveEvent); - } - else - { - Messages.Message($"Cannot activate autonomous mode: {GetBlockReason()}", - MechPawn, MessageTypeDefOf.NegativeEvent); - } - } + if (IsLowEnergy) + energyInfo += "WULA_EnergyLow".Translate(); + if (IsCriticalEnergy) + energyInfo += "WULA_EnergyCritical".Translate(); + + return baseDesc + "\n" + energyInfo; + } + + // 新增:根据能量状态返回不同的图标 + private UnityEngine.Texture2D GetWorkModeIcon() + { + if (IsCriticalEnergy) + return TexCommand.DesirePower; + else if (IsLowEnergy) + return TexCommand.ToggleVent; + else + return TexCommand.Attack; } - // 修改:返回自定义工作模式的显示名称 private string GetCurrentWorkModeDisplay() { switch (currentWorkMode) { case AutonomousWorkMode.Work: - return "Work"; + return "WULA_WorkMode_Work".Translate(); case AutonomousWorkMode.Recharge: - return "Recharge"; + return "WULA_WorkMode_Recharge".Translate(); case AutonomousWorkMode.Shutdown: - return "Shutdown"; + return "WULA_WorkMode_Shutdown".Translate(); default: - return "Unknown"; + return "WULA_WorkMode_Unknown".Translate(); } } private void ShowWorkModeMenu() { List list = new List(); - + // 工作模式 - list.Add(new FloatMenuOption("Work Mode - Perform assigned work tasks", + list.Add(new FloatMenuOption("WULA_WorkMode_Work_Desc".Translate(), () => SetWorkMode(AutonomousWorkMode.Work))); - + // 充电模式 - list.Add(new FloatMenuOption("Recharge Mode - Charge and then shutdown", + list.Add(new FloatMenuOption("WULA_WorkMode_Recharge_Desc".Translate(), () => SetWorkMode(AutonomousWorkMode.Recharge))); - + // 休眠模式 - list.Add(new FloatMenuOption("Shutdown Mode - Immediately shutdown", + list.Add(new FloatMenuOption("WULA_WorkMode_Shutdown_Desc".Translate(), () => SetWorkMode(AutonomousWorkMode.Shutdown))); Find.WindowStack.Add(new FloatMenu(list)); } - // 修改:设置自定义工作模式 private void SetWorkMode(AutonomousWorkMode mode) { currentWorkMode = mode; - + // 清除当前工作,让机械族重新选择符合新模式的工作 if (MechPawn.CurJob != null && MechPawn.CurJob.def != JobDefOf.Wait_Combat) { MechPawn.jobs.StopAll(); } - - string modeName = GetCurrentWorkModeDisplay(); - Messages.Message($"{MechPawn.LabelCap} switched to {modeName} mode", - MechPawn, MessageTypeDefOf.NeutralEvent); - - Log.Message($"AutonomousMech: {MechPawn.LabelCap} work mode set to {modeName}"); - } - private string GetBlockReason() - { - if (MechPawn.Dead || MechPawn.Downed) - return "Mech is incapacitated"; - - if (MechPawn.GetOverseer() != null) - return "Mech is under mechanitor control"; - - if (Props.requirePowerForAutonomy) - { - var energyNeed = MechPawn.needs?.TryGetNeed(); - if (energyNeed != null && energyNeed.CurLevelPercentage < 0.1f) - return "Insufficient energy"; - } - - return "Autonomous mode disabled"; + string modeName = GetCurrentWorkModeDisplay(); + Messages.Message("WULA_SwitchedToMode".Translate(MechPawn.LabelCap, modeName), + MechPawn, MessageTypeDefOf.NeutralEvent); } private void EnsureWorkSettings() @@ -264,18 +358,20 @@ namespace WulaFallenEmpire { if (!CanBeAutonomous) return null; - + + string energyInfo = "WULA_EnergyInfoShort".Translate(GetEnergyLevel().ToStringPercent()); + if (MechPawn.Drafted) - return "Operating autonomously"; + return "WULA_Autonomous_Drafted".Translate() + energyInfo; else - return $"Autonomous mode: {GetCurrentWorkModeDisplay()}"; + return "WULA_Autonomous_Mode".Translate(GetCurrentWorkModeDisplay()) + energyInfo; } - - // 新增:保存和加载工作模式 + public override void PostExposeData() { base.PostExposeData(); Scribe_Values.Look(ref currentWorkMode, "currentWorkMode", AutonomousWorkMode.Work); + Scribe_Values.Look(ref wasLowEnergy, "wasLowEnergy", false); } } } diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobDriver_AutonomousWaitCombat.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobDriver_AutonomousWaitCombat.cs new file mode 100644 index 00000000..1cd48ca1 --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobDriver_AutonomousWaitCombat.cs @@ -0,0 +1,234 @@ +// 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(); + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return true; + } + + protected override IEnumerable 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(); + 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(); + 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(); // 自定义报告文本 + } + } +} diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobExtension_AutonomousCombat.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobExtension_AutonomousCombat.cs new file mode 100644 index 00000000..e742ec89 --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobExtension_AutonomousCombat.cs @@ -0,0 +1,14 @@ +// 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; + } +} diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousCombat.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousCombat.cs new file mode 100644 index 00000000..b4e9715f --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousCombat.cs @@ -0,0 +1,42 @@ +// 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()?.CanWorkAutonomously == true) + { + return priority; + } + return 0f; + } + + protected override Job TryGiveJob(Pawn pawn) + { + // 确保是自主机械族且被征召 + var comp = pawn.GetComp(); + if (comp?.CanWorkAutonomously != true || pawn.drafter?.Drafted != true) + return null; + + // 创建自主战斗工作 + Job job = JobMaker.MakeJob(DefDatabase.GetNamed("WULA_AutonomousWaitCombat")); + job.expiryInterval = expiryInterval; + job.checkOverrideOnDamage = true; + + // 设置工作标签,确保不会被其他工作干扰 + pawn.mindState?.prioritizedWork?.Clear(); + + return job; + } + } +} diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousWaitCombat.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousWaitCombat.cs new file mode 100644 index 00000000..fcd4588f --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_AutonomousWaitCombat.cs @@ -0,0 +1,37 @@ +// 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()?.CanWorkAutonomously == true) + { + Job job = JobMaker.MakeJob(JobDefOf.Wait_Combat); + job.canUseRangedWeapon = canUseRangedWeapon; + job.expiryInterval = 30; // 短时间,便于重新评估 + return job; + } + + return null; + } + } +} diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs new file mode 100644 index 00000000..a7f1dca1 --- /dev/null +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs @@ -0,0 +1,60 @@ +using RimWorld; +using Verse; +using Verse.AI; + +namespace WulaFallenEmpire +{ + // 检查机械族是否需要充电 + public class ThinkNode_ConditionalNeedRecharge : ThinkNode_Conditional + { + public float energyThreshold = 0.3f; + + protected override bool Satisfied(Pawn pawn) + { + if (pawn == null || pawn.Dead || pawn.Downed) + return false; + + var energyNeed = pawn.needs?.TryGetNeed(); + if (energyNeed == null) + return false; + + return energyNeed.CurLevelPercentage < energyThreshold; + } + } + + // 检查机械族是否紧急需要充电 + public class ThinkNode_ConditionalEmergencyRecharge : ThinkNode_Conditional + { + public float emergencyThreshold = 0.1f; + + protected override bool Satisfied(Pawn pawn) + { + if (pawn == null || pawn.Dead || pawn.Downed) + return false; + + var energyNeed = pawn.needs?.TryGetNeed(); + if (energyNeed == null) + return false; + + return energyNeed.CurLevelPercentage < emergencyThreshold; + } + } + + // 检查机械族是否充满电 + public class ThinkNode_ConditionalFullyCharged : ThinkNode_Conditional + { + public float fullChargeThreshold = 0.9f; + + protected override bool Satisfied(Pawn pawn) + { + if (pawn == null || pawn.Dead || pawn.Downed) + return false; + + var energyNeed = pawn.needs?.TryGetNeed(); + if (energyNeed == null) + return false; + + return energyNeed.CurLevelPercentage >= fullChargeThreshold; + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 400bd3cf..3eb5a034 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -105,9 +105,11 @@ + +