This commit is contained in:
2026-02-24 12:02:38 +08:00
parent 1af5f0c1d8
commit 96bc1d4c5a
57 changed files with 6595 additions and 1170 deletions

View File

@@ -0,0 +1,181 @@
// File: Patches/ColonistBarMechPatch_Fixed.cs
using HarmonyLib;
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(ColonistBar), "CheckRecacheEntries")]
public static class Patch_ColonistBarMech_Fixed
{
[HarmonyPostfix]
public static void Postfix(ref List<ColonistBar.Entry> ___cachedEntries)
{
// 安全检查:只在玩家派系存在时运行
if (Faction.OfPlayer == null)
return;
try
{
// 建立机甲和驾驶员的映射关系
var mechToPilots = new Dictionary<Pawn, List<Pawn>>();
var pilotToMech = new Dictionary<Pawn, Pawn>();
var mechEntries = new HashSet<Pawn>();
// 只扫描玩家殖民地的地图
foreach (var map in Find.Maps.Where(m => m.IsPlayerHome))
{
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
{
// 只处理玩家殖民地的机甲Wulamechunit
if (pawn is Wulamechunit mech &&
(mech.Faction == Faction.OfPlayer || mech.HostFaction == Faction.OfPlayer))
{
var pilotComp = mech.TryGetComp<CompMechPilotHolder>();
if (pilotComp != null && pilotComp.HasPilots)
{
var pilots = pilotComp.GetPilots()
.Where(p => p.Faction == Faction.OfPlayer || p.HostFaction == Faction.OfPlayer)
.ToList();
if (pilots.Count > 0)
{
mechToPilots[mech] = pilots;
foreach (var pilot in pilots)
{
pilotToMech[pilot] = mech;
}
}
}
}
}
}
// 如果没有找到有机甲驾驶员的机甲,直接返回
if (mechToPilots.Count == 0)
return;
// 创建新的条目列表
var newEntries = new List<ColonistBar.Entry>();
// 第一轮:处理原始条目,隐藏驾驶员
foreach (var entry in ___cachedEntries)
{
var pawn = entry.pawn;
if (pawn == null)
{
// 保留空条目
newEntries.Add(entry);
continue;
}
// 如果是驾驶员,跳过(隐藏)
if (pilotToMech.ContainsKey(pawn))
{
continue;
}
// 如果是机甲
if (mechToPilots.ContainsKey(pawn))
{
// 确保机甲还没有被添加,并且有驾驶员
if (!mechEntries.Contains(pawn) && mechToPilots[pawn].Count > 0)
{
newEntries.Add(entry);
mechEntries.Add(pawn);
}
}
else
{
// 普通殖民者(不属于任何机甲的驾驶员)
newEntries.Add(entry);
}
}
// 第二轮:确保有机甲驾驶员的机甲被添加到列表
foreach (var mech in mechToPilots.Keys)
{
// 如果机甲还没有被添加,且有驾驶员
if (!mechEntries.Contains(mech) && mechToPilots[mech].Count > 0)
{
// 需要创建一个新的Entry
var map = mech.MapHeld;
if (map != null && map.IsPlayerHome)
{
// 计算group需要找到地图对应的group
int group = GetGroupForMap(map, ___cachedEntries);
newEntries.Add(new ColonistBar.Entry(mech, map, group));
mechEntries.Add(mech);
}
else if (mechToPilots[mech].Count > 0)
{
// 如果机甲不在任何地图上(可能被携带等),但仍有驾驶员
// 使用第一个驾驶员的地图和group作为参考
var pilot = mechToPilots[mech].First();
var pilotMap = pilot.MapHeld;
if (pilotMap != null && pilotMap.IsPlayerHome)
{
int group = GetGroupForMap(pilotMap, ___cachedEntries);
newEntries.Add(new ColonistBar.Entry(mech, pilotMap, group));
mechEntries.Add(mech);
}
}
}
}
// 替换原列表
___cachedEntries = newEntries;
}
catch (System.Exception ex)
{
Log.Error($"[DD] Error in fixed ColonistBar patch: {ex}");
// 出错时不改变原列表
}
}
// 辅助方法获取地图对应的group
private static int GetGroupForMap(Map map, List<ColonistBar.Entry> originalEntries)
{
if (map == null)
return 0;
// 在原始条目中查找第一个属于该地图的条目返回它的group
var entry = originalEntries.FirstOrDefault(e => e.map == map && e.pawn != null);
if (entry.pawn != null)
{
return entry.group;
}
// 如果没有找到有pawn的条目尝试查找任何属于该地图的条目包括空条目
entry = originalEntries.FirstOrDefault(e => e.map == map);
if (entry.map != null)
{
return entry.group;
}
// 如果还是找不到返回0作为默认值
return 0;
}
// 备用方案使用更简单的方法计算group
private static int CalculateGroupForMap(Map map)
{
if (map == null)
return 0;
// 简单的计算:玩家殖民地地图的索引
// 注意:这可能不完全准确,但通常工作
var playerMaps = Find.Maps.Where(m => m.IsPlayerHome).ToList();
int index = playerMaps.IndexOf(map);
// 如果找不到返回0
if (index < 0)
return 0;
return index;
}
}
}

View File

@@ -0,0 +1,74 @@
// File: Patches/Patch_Wulamechunit.cs (修改EquipmentUtility_CanEquip_Patch部分)
using HarmonyLib;
using RimWorld;
using System;
using Verse;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(EquipmentUtility), nameof(EquipmentUtility.CanEquip), new Type[] { typeof(Thing), typeof(Pawn), typeof(string), typeof(bool) }, new ArgumentType[] { ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal })]
public static class EquipmentUtility_CanEquip_Patch
{
[HarmonyPrefix]
public static bool CanEquip_Prefix(Thing thing, Pawn pawn, out string cantReason, ref bool __result)
{
cantReason = null;
try
{
// 检查是否有机甲专用武器组件
var mechWeapon = thing?.TryGetComp<CompMechOnlyWeapon>();
// 情况1这是机甲专用武器
if (mechWeapon != null)
{
// 检查是否是机甲
if (pawn is Wulamechunit)
{
// 检查是否允许此机甲使用
if (mechWeapon.CanBeEquippedByMech(pawn))
{
// 机甲可以使用此专用武器
return true;
}
else
{
// 此机甲不在允许列表中
cantReason = "DD_Equipment_For_Other_Mech".Translate();
__result = false;
return false;
}
}
else
{
// 非机甲尝试装备专用武器,禁止
cantReason = "DD_Human_Cannot_Equip_Mech_Weapon".Translate();
__result = false;
return false;
}
}
// 情况2这是普通武器
else if (thing?.def?.IsWeapon == true)
{
// 检查是否是机甲
if (pawn is Wulamechunit)
{
// 机甲不能装备普通武器
cantReason = "DD_Equipment_Not_Allow_For_Mech".Translate();
__result = false;
return false;
}
// 非机甲可以装备普通武器,继续检查
}
// 情况3不是武器或不是机甲按原逻辑处理
return true;
}
catch (Exception ex)
{
Log.Error($"[DD] CanEquip patch error: {ex}");
return true;
}
}
}
}

View File

@@ -0,0 +1,130 @@
// File: Patch_RomanceFix.cs
using HarmonyLib;
using RimWorld;
using System.Collections.Generic;
using Verse;
namespace WulaFallenEmpire
{
/// <summary>
/// 修复浪漫关系菜单相关的空引用异常
/// </summary>
public static class RomancePatches
{
/// <summary>
/// 补丁:防止对机甲单位显示浪漫菜单
/// </summary>
[HarmonyPatch(typeof(FloatMenuOptionProvider_Romance))]
[HarmonyPatch("GetSingleOptionFor")]
public static class Patch_FloatMenuOptionProvider_Romance_GetSingleOptionFor
{
[HarmonyPrefix]
public static bool Prefix(Pawn clickedPawn, ref FloatMenuOption __result)
{
// 如果是机甲单位直接返回null
if (clickedPawn is Wulamechunit)
{
__result = null;
return false; // 跳过原始方法
}
// 额外检查如果clickedPawn没有story组件也跳过
if (clickedPawn?.story == null)
{
__result = null;
return false;
}
return true; // 继续执行原始方法
}
}
/// <summary>
/// 补丁:防止在爱情关系检查中出现空引用
/// </summary>
[HarmonyPatch(typeof(LovePartnerRelationUtility))]
[HarmonyPatch("ExistingLovePartners")]
public static class Patch_LovePartnerRelationUtility_ExistingLovePartners
{
[HarmonyPrefix]
public static bool Prefix(Pawn pawn, bool allowDead, ref List<DirectPawnRelation> __result)
{
// 如果pawn是机甲单位返回空列表
if (pawn is Wulamechunit)
{
__result = new List<DirectPawnRelation>();
return false; // 跳过原始方法
}
// 如果pawn没有story组件返回空列表
if (pawn?.story == null)
{
__result = new List<DirectPawnRelation>();
return false;
}
return true; // 继续执行原始方法
}
}
/// <summary>
/// 补丁:防止浪漫关系配对检查中的空引用
/// </summary>
[HarmonyPatch(typeof(RelationsUtility))]
[HarmonyPatch("RomanceEligiblePair")]
public static class Patch_RelationsUtility_RomanceEligiblePair
{
[HarmonyPrefix]
public static bool Prefix(Pawn initiator, Pawn target, bool forOpinionExplanation, ref AcceptanceReport __result)
{
// 如果任一pawn是机甲单位返回拒绝
if (initiator is Wulamechunit || target is Wulamechunit)
{
__result = new AcceptanceReport("DD_MechCannotRomance".Translate());
return false; // 跳过原始方法
}
// 如果任一pawn没有story组件返回拒绝
if (initiator?.story == null || target?.story == null)
{
__result = new AcceptanceReport("DD_NoStoryComponent".Translate());
return false;
}
return true; // 继续执行原始方法
}
}
/// <summary>
/// 补丁:防止浪漫关系检查中的空引用
/// </summary>
[HarmonyPatch(typeof(RelationsUtility))]
[HarmonyPatch("RomanceOption")]
public static class Patch_RelationsUtility_RomanceOption
{
[HarmonyPrefix]
public static bool Prefix(Pawn initiator, Pawn romanceTarget, ref FloatMenuOption option, ref float chance, ref bool __result)
{
// 如果任一pawn是机甲单位返回false
if (initiator is Wulamechunit || romanceTarget is Wulamechunit)
{
__result = false;
option = null;
chance = 0f;
return false; // 跳过原始方法
}
// 如果任一pawn没有story组件返回false
if (initiator?.story == null || romanceTarget?.story == null)
{
__result = false;
option = null;
chance = 0f;
return false;
}
return true; // 继续执行原始方法
}
}
}
}

View File

@@ -0,0 +1,230 @@
using HarmonyLib;
using RimWorld;
using System;
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace WulaFallenEmpire.HarmonyPatches
{
/// <summary>
/// 整合的伤害处理系统
/// 处理1. 机甲装甲系统 2. HediffComp_Invulnerable免疫系统
/// </summary>
[HarmonyPatch(typeof(Thing))]
[HarmonyPatch("TakeDamage")]
public static class Thing_TakeDamage_Patch
{
// 缓存装甲值StatDef
private static readonly StatDef ArmorStatDef = StatDef.Named("DD_MechArmor");
// 阻挡效果的MoteDef
private static readonly ThingDef BlockMoteDef = DefDatabase<ThingDef>.GetNamedSilentFail("Mote_Spark");
// 阻挡音效
private static readonly SoundDef BlockSoundDef = DefDatabase<SoundDef>.GetNamedSilentFail("ArmorBlock");
// 免疫效果的MoteDef
private static readonly ThingDef ImmuneMoteDef = DefDatabase<ThingDef>.GetNamedSilentFail("Mote_Immunity");
// 免疫音效
private static readonly SoundDef ImmuneSoundDef = DefDatabase<SoundDef>.GetNamedSilentFail("ImmuneSound");
// 调试统计
private static readonly Dictionary<Thing, DamageBlockStats> DebugStats = new Dictionary<Thing, DamageBlockStats>();
private class DamageBlockStats
{
public int mechArmorBlocked = 0;
public int invulnerableBlocked = 0;
public int totalHits = 0;
public int TotalBlocked => mechArmorBlocked + invulnerableBlocked;
public override string ToString()
{
return $"机甲装甲阻挡: {mechArmorBlocked}, 免疫阻挡: {invulnerableBlocked}, 总计阻挡: {TotalBlocked}, 总命中: {totalHits}";
}
}
/// <summary>
/// 前置补丁在TakeDamage执行前检查伤害免疫
/// </summary>
[HarmonyPrefix]
public static bool Prefix(Thing __instance, ref DamageInfo dinfo, ref DamageWorker.DamageResult __result)
{
// 更新调试统计
if (!DebugStats.ContainsKey(__instance))
DebugStats[__instance] = new DamageBlockStats();
DebugStats[__instance].totalHits++;
// 第一步检查伤害免疫HediffComp
if (__instance is Pawn pawn)
{
bool blockedByInvulnerable = CheckInvulnerableHediff(pawn, dinfo, out HediffComp_Invulnerable invulnerableComp);
if (blockedByInvulnerable)
{
// 被HediffComp免疫阻挡
DebugStats[__instance].invulnerableBlocked++;
// 显示免疫效果
ShowImmuneEffect(pawn, dinfo);
// 播放免疫音效
PlayImmuneSound(pawn);
// 调用HediffComp的OnDamageBlocked方法
invulnerableComp?.OnDamageBlocked(dinfo);
// 返回空结果,跳过原方法
__result = new DamageWorker.DamageResult();
return false;
}
}
// 第二步:检查机甲装甲系统
float armorValue = __instance.GetStatValue(ArmorStatDef);
// 如果装甲值 <= 0不启动装甲系统继续原方法
if (armorValue <= 0)
return true;
// 计算穿甲伤害
float armorPenetration = dinfo.ArmorPenetrationInt;
float piercingDamage = dinfo.Amount * armorPenetration;
// 判断是否应该阻挡
bool shouldBlock = piercingDamage < armorValue;
if (shouldBlock)
{
// 机甲装甲阻挡成功
DebugStats[__instance].mechArmorBlocked++;
// 显示阻挡效果
ShowBlockEffect(__instance, dinfo);
// 播放阻挡音效
PlayBlockSound(__instance);
// 返回空结果,跳过原方法
__result = new DamageWorker.DamageResult();
return false;
}
return true;
}
/// <summary>
/// 检查伤害免疫HediffComp
/// </summary>
private static bool CheckInvulnerableHediff(Pawn pawn, DamageInfo dinfo, out HediffComp_Invulnerable invulnerableComp)
{
invulnerableComp = null;
if (pawn == null || pawn.health == null || pawn.health.hediffSet == null)
return false;
// 检查所有Hediff寻找HediffComp_Invulnerable
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.TryGetComp<HediffComp_Invulnerable>() is HediffComp_Invulnerable comp)
{
invulnerableComp = comp;
return comp.ShouldBlockDamage(dinfo);
}
}
return false;
}
/// <summary>
/// 显示免疫效果
/// </summary>
private static void ShowImmuneEffect(Pawn pawn, DamageInfo dinfo)
{
if (!pawn.Spawned)
return;
// 显示文字效果
Vector3 textPos = pawn.DrawPos + new Vector3(0, 0, 1f);
MoteMaker.ThrowText(textPos, pawn.Map, "DD_ImmuneToDamage".Translate(), Color.green, 2.5f);
// 显示粒子效果
if (ImmuneMoteDef != null)
{
MoteMaker.MakeStaticMote(pawn.DrawPos, pawn.Map, ImmuneMoteDef, 1f);
}
}
/// <summary>
/// 播放免疫音效
/// </summary>
private static void PlayImmuneSound(Pawn pawn)
{
if (!pawn.Spawned)
return;
if (ImmuneSoundDef != null)
{
ImmuneSoundDef.PlayOneShot(new TargetInfo(pawn.Position, pawn.Map));
}
}
/// <summary>
/// 显示阻挡效果
/// </summary>
private static void ShowBlockEffect(Thing target, DamageInfo dinfo)
{
if (!target.Spawned)
return;
// 显示文字效果
Vector3 textPos = target.DrawPos + new Vector3(0, 0, 1f);
MoteMaker.ThrowText(textPos, target.Map, "DD_BlockByMechArmor".Translate(), Color.yellow, 2.5f);
// 显示粒子效果
if (BlockMoteDef != null)
{
MoteMaker.MakeStaticMote(target.DrawPos, target.Map, BlockMoteDef, 1f);
}
}
/// <summary>
/// 播放阻挡音效
/// </summary>
private static void PlayBlockSound(Thing target)
{
if (!target.Spawned)
return;
if (BlockSoundDef != null)
{
BlockSoundDef.PlayOneShot(new TargetInfo(target.Position, target.Map));
}
else
{
// 备用音效
SoundDefOf.MetalHitImportant.PlayOneShot(new TargetInfo(target.Position, target.Map));
}
}
/// <summary>
/// 获取调试统计信息
/// </summary>
public static string GetDebugStats()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("伤害阻挡统计:");
foreach (var kvp in DebugStats)
{
sb.AppendLine($"{kvp.Key.LabelCap}: {kvp.Value}");
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,285 @@
using HarmonyLib;
using RimWorld;
using System;
using System.Collections.Generic;
using System.Reflection;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(Pawn), "get_CanTakeOrder")]
public class Patch_CanTakeOrder
{
[HarmonyPostfix]
public static void postfix(ref bool __result, Pawn __instance)
{
if (__instance is Wulamechunit && __instance.Drafted)
{
__result = true;
}
}
}
[HarmonyPatch(typeof(PawnComponentsUtility), "AddAndRemoveDynamicComponents")]
public class Patch_PawnTracer
{
[HarmonyPostfix]
public static void postfix(Pawn pawn)
{
if (pawn is Wulamechunit)
{
pawn.drafter = new Pawn_DraftController(pawn);
pawn.skills = new Pawn_SkillTracker(pawn);
}
}
}
[HarmonyPatch(typeof(FloatMenuOptionProvider), "SelectedPawnValid")]
public class Patch_GetSingleOption
{
[HarmonyPostfix]
public static void postfix(ref bool __result, Pawn pawn)
{
if (pawn is Wulamechunit)
{
__result = true;
}
}
}
[HarmonyPatch(typeof(FloatMenuUtility), nameof(FloatMenuUtility.GetMeleeAttackAction))]
public static class Patch_FloatMenuUtility_GetMeleeAttackAction
{
[HarmonyPrefix]
public static bool Prefix(Pawn pawn, LocalTargetInfo target, out string failStr, ref Action __result, bool ignoreControlled = false)
{
failStr = "";
if (pawn is Wulamechunit)
{
// 直接返回 true 跳过控制检查
ignoreControlled = true;
// 这里我们直接调用修改后的方法
__result = ModifiedGetMeleeAttackAction(pawn, target, out failStr, ignoreControlled);
return false; // 跳过原始方法
}
return true; // 没有组件,继续执行原始方法
}
private static Action ModifiedGetMeleeAttackAction(Pawn pawn, LocalTargetInfo target, out string failStr, bool ignoreControlled = false)
{
failStr = "";
try
{
// 直接使用原始代码,但跳过控制检查
if (!pawn.Drafted && !ignoreControlled)
{
failStr = "IsNotDraftedLower".Translate(pawn.LabelShort, pawn);
}
else if (target.IsValid && !pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly))
{
failStr = "NoPath".Translate();
}
else if (pawn.WorkTagIsDisabled(WorkTags.Violent))
{
failStr = "IsIncapableOfViolenceLower".Translate(pawn.LabelShort, pawn);
}
else if (pawn.meleeVerbs?.TryGetMeleeVerb(target.Thing) == null)
{
failStr = "Incapable".Translate();
}
else if (pawn == target.Thing)
{
failStr = "CannotAttackSelf".Translate();
}
else if (target.Thing is Pawn targetPawn && (pawn.InSameExtraFaction(targetPawn, ExtraFactionType.HomeFaction) || pawn.InSameExtraFaction(targetPawn, ExtraFactionType.MiniFaction)))
{
failStr = "CannotAttackSameFactionMember".Translate();
}
else
{
if (!(target.Thing is Pawn pawn2) || !pawn2.RaceProps.Animal || !HistoryEventUtility.IsKillingInnocentAnimal(pawn, pawn2) || new HistoryEvent(HistoryEventDefOf.KilledInnocentAnimal, pawn.Named(HistoryEventArgsNames.Doer)).DoerWillingToDo())
{
return delegate
{
Job job = JobMaker.MakeJob(JobDefOf.AttackMelee, target);
if (target.Thing is Pawn pawn3)
{
job.killIncappedTarget = pawn3.Downed;
}
pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
};
}
failStr = "IdeoligionForbids".Translate();
}
failStr = failStr.CapitalizeFirst();
return null;
}
catch (Exception ex)
{
Log.Error($"[IRMF] Error in ModifiedGetMeleeAttackAction: {ex}");
failStr = "Cannot attack";
return null;
}
}
}
[HarmonyPatch(typeof(FloatMenuUtility), nameof(FloatMenuUtility.GetRangedAttackAction))]
public static class Patch_FloatMenuUtility_GetRangedAttackAction
{
[HarmonyPrefix]
public static bool Prefix(Pawn pawn, LocalTargetInfo target, out string failStr, ref Action __result)
{
failStr = "";
if (pawn is Wulamechunit)
{
// 这里我们直接调用修改后的方法
__result = ModifiedGetRangedAttackAction(pawn, target, out failStr);
return false; // 跳过原始方法
}
return true; // 没有组件,继续执行原始方法
}
private static Action ModifiedGetRangedAttackAction(Pawn pawn, LocalTargetInfo target, out string failStr, bool ignoreControlled = false)
{
failStr = "";
try
{
if (pawn.equipment.Primary == null)
{
return null;
}
Verb primaryVerb = pawn.equipment.PrimaryEq.PrimaryVerb;
if (primaryVerb.verbProps.IsMeleeAttack)
{
return null;
}
if (!pawn.Drafted)
{
failStr = "IsNotDraftedLower".Translate(pawn.LabelShort, pawn);
}
else if (pawn.IsColonyMechPlayerControlled && target.IsValid && !MechanitorUtility.InMechanitorCommandRange(pawn, target))
{
failStr = "OutOfCommandRange".Translate();
}
else if (target.IsValid && !pawn.equipment.PrimaryEq.PrimaryVerb.CanHitTarget(target))
{
if (!pawn.Position.InHorDistOf(target.Cell, primaryVerb.EffectiveRange))
{
failStr = "OutOfRange".Translate();
}
else
{
float num = primaryVerb.verbProps.EffectiveMinRange(target, pawn);
if ((float)pawn.Position.DistanceToSquared(target.Cell) < num * num)
{
failStr = "TooClose".Translate();
}
else
{
failStr = "CannotHitTarget".Translate();
}
}
}
else if (pawn.WorkTagIsDisabled(WorkTags.Violent))
{
failStr = "IsIncapableOfViolenceLower".Translate(pawn.LabelShort, pawn);
}
else if (pawn == target.Thing)
{
failStr = "CannotAttackSelf".Translate();
}
else if (target.Thing is Pawn target2 && (pawn.InSameExtraFaction(target2, ExtraFactionType.HomeFaction) || pawn.InSameExtraFaction(target2, ExtraFactionType.MiniFaction)))
{
failStr = "CannotAttackSameFactionMember".Translate();
}
else if (target.Thing is Pawn victim && HistoryEventUtility.IsKillingInnocentAnimal(pawn, victim) && !new HistoryEvent(HistoryEventDefOf.KilledInnocentAnimal, pawn.Named(HistoryEventArgsNames.Doer)).DoerWillingToDo())
{
failStr = "IdeoligionForbids".Translate();
}
else
{
if (!(target.Thing is Pawn pawn2) || pawn.Ideo == null || !pawn.Ideo.IsVeneratedAnimal(pawn2) || new HistoryEvent(HistoryEventDefOf.HuntedVeneratedAnimal, pawn.Named(HistoryEventArgsNames.Doer)).DoerWillingToDo())
{
return delegate
{
Job job = JobMaker.MakeJob(JobDefOf.AttackStatic, target);
pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
};
}
failStr = "IdeoligionForbids".Translate();
}
failStr = failStr.CapitalizeFirst();
return null;
}
catch (Exception ex)
{
Log.Error($"[IRMF] Error in ModifiedGetRangeAttackAction: {ex}");
failStr = "Cannot attack";
return null;
}
}
[HarmonyPatch(typeof(FloatMenuOptionProvider_Romance), "GetSingleOptionFor")]
[HarmonyPrefix]
public static bool GetSingleOptionFor_Prefix(Pawn clickedPawn, ref FloatMenuOption __result)
{
if (clickedPawn is Wulamechunit)
{
__result = null;
return false; // 跳过原始方法
}
return true; // 继续执行原始方法
}
}
[HarmonyPatch]
public static class Patch_Pawn_MeleeVerbs_TryMeleeAttack
{
// 获取要修补的方法
[HarmonyTargetMethod]
public static MethodBase TargetMethod()
{
// 查找 Pawn_MeleeVerbs.TryMeleeAttack 方法
return AccessTools.Method(typeof(Pawn_MeleeVerbs), nameof(Pawn_MeleeVerbs.TryMeleeAttack));
}
// 前置补丁:在原始方法执行前检查
[HarmonyPrefix]
public static bool Prefix(ref bool __result, Pawn_MeleeVerbs __instance, Thing target, Verb verbToUse, bool surpriseAttack)
{
try
{
// 获取 Pawn
var pawnField = AccessTools.Field(typeof(Pawn_MeleeVerbs), "pawn");
if (pawnField == null)
return true; // 如果找不到字段,继续执行原方法
Pawn pawn = pawnField.GetValue(__instance) as Pawn;
if (pawn == null)
return true;
// 检查是否为机甲
if (pawn is Wulamechunit)
{
// 检查是否有驾驶员
var pilotComp = pawn.TryGetComp<CompMechPilotHolder>();
if (pilotComp != null && !pilotComp.HasPilots)
{
// 没有驾驶员,阻止近战攻击
__result = false;
return false; // 跳过原始方法
}
}
return true; // 继续执行原始方法
}
catch (Exception ex)
{
Log.Error($"[DD] Harmony patch error in TryMeleeAttack: {ex}");
return true; // 出错时继续执行原始方法
}
}
}
}

View File

@@ -0,0 +1,28 @@
// File: HarmonyPatches/SkillSystemPatches.cs
using HarmonyLib;
using RimWorld;
using Verse;
namespace WulaFallenEmpire
{
/// <summary>
/// 针对SkillRecord.Interval()的补丁,防止在机甲上出现空引用
/// </summary>
[HarmonyPatch(typeof(SkillRecord))]
[HarmonyPatch("Interval")]
public static class Patch_SkillRecord_Interval
{
[HarmonyPrefix]
public static bool Prefix(SkillRecord __instance)
{
// 额外检查如果pawn.story为null也跳过
if (__instance?.Pawn?.story == null)
{
return false; // 跳过原方法
}
return true; // 执行原方法
}
}
}