1
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
using Verse.Sound;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompDamageInterceptor : ThingComp
|
||||
{
|
||||
private CompProperties_DamageInterceptor Props => (CompProperties_DamageInterceptor)props;
|
||||
private Pawn Pawn => (Pawn)parent;
|
||||
|
||||
// 使用Harmony补丁在伤害应用前完全拦截
|
||||
public bool PreApplyDamage(ref DamageInfo dinfo)
|
||||
{
|
||||
if (!ShouldInterceptDamage(dinfo))
|
||||
return true; // 继续应用伤害
|
||||
|
||||
// 计算要转移的伤害量(完全拦截)
|
||||
float transferDamage = dinfo.Amount * Props.damageTransferRatio;
|
||||
|
||||
// 寻找可用的目标建筑
|
||||
Building targetBuilding = FindTargetBuilding();
|
||||
if (targetBuilding != null)
|
||||
{
|
||||
// 将伤害完全转移到建筑
|
||||
ApplyDamageToBuilding(transferDamage, targetBuilding, dinfo);
|
||||
OnDamageIntercepted(dinfo, transferDamage, targetBuilding);
|
||||
|
||||
// 完全拦截伤害 - 将伤害设置为0
|
||||
dinfo.SetAmount(0f);
|
||||
|
||||
Log.Message($"[DamageInterceptor] {Pawn.LabelShort} 完全拦截 {transferDamage} 点伤害并转移至 {targetBuilding.Label},自身承受0伤害");
|
||||
|
||||
return true; // 继续应用修改后的伤害(0伤害)
|
||||
}
|
||||
|
||||
return true; // 没有找到建筑,正常应用伤害
|
||||
}
|
||||
|
||||
private bool ShouldInterceptDamage(DamageInfo dinfo)
|
||||
{
|
||||
if (parent == null || !parent.Spawned || Pawn.Dead)
|
||||
return false;
|
||||
|
||||
// 检查生命值阈值
|
||||
if (Pawn.health != null)
|
||||
{
|
||||
float healthRatio = Pawn.health.summaryHealth.SummaryHealthPercent;
|
||||
if (healthRatio < Props.healthThreshold.min || healthRatio > Props.healthThreshold.max)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Building FindTargetBuilding()
|
||||
{
|
||||
if (parent?.Map == null)
|
||||
return null;
|
||||
|
||||
var map = parent.Map;
|
||||
var faction = parent.Faction;
|
||||
|
||||
// 在全图范围内搜索目标建筑
|
||||
List<Building> targetBuildings = new List<Building>();
|
||||
foreach (var building in map.listerBuildings.allBuildingsColonist)
|
||||
{
|
||||
if (building.def.defName == Props.targetBuildingDefName &&
|
||||
!building.Destroyed)
|
||||
{
|
||||
// 检查派系(如果需要)
|
||||
if (Props.requireSameFaction && building.Faction != faction)
|
||||
continue;
|
||||
|
||||
targetBuildings.Add(building);
|
||||
}
|
||||
}
|
||||
|
||||
// 随机选择一个建筑
|
||||
if (targetBuildings.Count > 0)
|
||||
{
|
||||
return targetBuildings.RandomElement();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将伤害直接应用到目标建筑的生命值上
|
||||
/// </summary>
|
||||
private void ApplyDamageToBuilding(float damageAmount, Building building, DamageInfo originalDinfo)
|
||||
{
|
||||
// 创建新的伤害信息,使用原始伤害类型
|
||||
DamageInfo buildingDamage = new DamageInfo(
|
||||
originalDinfo.Def, // 使用相同的伤害类型
|
||||
damageAmount,
|
||||
originalDinfo.ArmorPenetrationInt,
|
||||
originalDinfo.Angle,
|
||||
originalDinfo.Instigator,
|
||||
originalDinfo.HitPart,
|
||||
originalDinfo.Weapon,
|
||||
originalDinfo.Category,
|
||||
originalDinfo.IntendedTarget
|
||||
);
|
||||
|
||||
// 对建筑造成伤害
|
||||
building.TakeDamage(buildingDamage);
|
||||
|
||||
Log.Message($"[DamageInterceptor] 对建筑 {building.Label} 造成 {damageAmount} 点伤害,剩余生命值: {building.HitPoints}/{building.MaxHitPoints}");
|
||||
}
|
||||
|
||||
private void OnDamageIntercepted(DamageInfo dinfo, float interceptDamage, Building targetBuilding)
|
||||
{
|
||||
// 创建拦截效果
|
||||
if (Props.interceptEffecter != null)
|
||||
{
|
||||
Effecter effect = Props.interceptEffecter.Spawn();
|
||||
effect.Trigger(new TargetInfo(parent.Position, parent.Map), new TargetInfo(targetBuilding.Position, parent.Map));
|
||||
effect.Cleanup();
|
||||
}
|
||||
|
||||
// 播放音效
|
||||
if (Props.interceptSound != null)
|
||||
{
|
||||
Props.interceptSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取组件状态
|
||||
public string GetStatusString()
|
||||
{
|
||||
return $"伤害拦截: {Props.damageTransferRatio * 100}% → {Props.targetBuildingDefName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompDamageRelay : ThingComp
|
||||
{
|
||||
private CompProperties_DamageRelay Props => (CompProperties_DamageRelay)props;
|
||||
private Building Building => (Building)parent;
|
||||
|
||||
public override void PostPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
base.PostPostApplyDamage(dinfo, totalDamageDealt);
|
||||
|
||||
// 检查是否应该传递伤害
|
||||
if (ShouldRelayDamage(dinfo, totalDamageDealt))
|
||||
{
|
||||
TryRelayDamage(dinfo, totalDamageDealt);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldRelayDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
if (parent == null || !parent.Spawned || parent.Destroyed)
|
||||
return false;
|
||||
|
||||
// 检查生命值阈值
|
||||
float healthRatio = (float)Building.HitPoints / Building.MaxHitPoints;
|
||||
if (healthRatio < Props.healthThreshold.min || healthRatio > Props.healthThreshold.max)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TryRelayDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
// 计算传递的伤害量
|
||||
float relayDamage = totalDamageDealt * Props.damageRelayRatio;
|
||||
|
||||
// 寻找可用的同派系建筑
|
||||
Building targetBuilding = FindAvailableBuilding();
|
||||
if (targetBuilding != null)
|
||||
{
|
||||
// 执行伤害传递
|
||||
ApplyDamageToBuilding(relayDamage, targetBuilding, dinfo);
|
||||
OnDamageRelayed(dinfo, relayDamage, targetBuilding);
|
||||
|
||||
// 记录日志
|
||||
Log.Message($"[DamageRelay] {Building.Label} 将 {relayDamage} 点伤害传递给 {targetBuilding.Label}");
|
||||
}
|
||||
}
|
||||
|
||||
private Building FindAvailableBuilding()
|
||||
{
|
||||
if (parent?.Map == null)
|
||||
return null;
|
||||
|
||||
var map = parent.Map;
|
||||
var faction = parent.Faction;
|
||||
|
||||
// 在全图范围内搜索建筑
|
||||
List<Building> availableBuildings = new List<Building>();
|
||||
foreach (var building in map.listerBuildings.allBuildingsColonist)
|
||||
{
|
||||
if (building != parent && !building.Destroyed)
|
||||
{
|
||||
// 检查派系(如果需要)
|
||||
if (Props.relayOnlyToSameFaction && building.Faction != faction)
|
||||
continue;
|
||||
|
||||
availableBuildings.Add(building);
|
||||
}
|
||||
}
|
||||
|
||||
// 随机选择一个建筑
|
||||
if (availableBuildings.Count > 0)
|
||||
{
|
||||
return availableBuildings.RandomElement();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将伤害直接应用到目标建筑的生命值上
|
||||
/// </summary>
|
||||
private void ApplyDamageToBuilding(float damageAmount, Building building, DamageInfo originalDinfo)
|
||||
{
|
||||
// 创建新的伤害信息,使用原始伤害类型
|
||||
DamageInfo buildingDamage = new DamageInfo(
|
||||
originalDinfo.Def, // 使用相同的伤害类型
|
||||
damageAmount,
|
||||
originalDinfo.ArmorPenetrationInt,
|
||||
originalDinfo.Angle,
|
||||
originalDinfo.Instigator,
|
||||
originalDinfo.HitPart,
|
||||
originalDinfo.Weapon,
|
||||
originalDinfo.Category,
|
||||
originalDinfo.IntendedTarget
|
||||
);
|
||||
|
||||
// 对建筑造成伤害
|
||||
building.TakeDamage(buildingDamage);
|
||||
|
||||
Log.Message($"[DamageRelay] 对建筑 {building.Label} 造成 {damageAmount} 点伤害,剩余生命值: {building.HitPoints}/{building.MaxHitPoints}");
|
||||
}
|
||||
|
||||
private void OnDamageRelayed(DamageInfo dinfo, float relayDamage, Building targetBuilding)
|
||||
{
|
||||
// 创建传递效果
|
||||
if (Props.relayEffecter != null)
|
||||
{
|
||||
Effecter effect = Props.relayEffecter.Spawn();
|
||||
effect.Trigger(new TargetInfo(parent.Position, parent.Map), new TargetInfo(targetBuilding.Position, parent.Map));
|
||||
effect.Cleanup();
|
||||
}
|
||||
|
||||
// 播放音效
|
||||
if (Props.relaySound != null)
|
||||
{
|
||||
Props.relaySound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取组件状态
|
||||
public string GetStatusString()
|
||||
{
|
||||
return $"伤害传递: {Props.damageRelayRatio * 100}%";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompProperties_DamageInterceptor : CompProperties
|
||||
{
|
||||
public float damageTransferRatio = 1f; // 完全拦截并转移伤害
|
||||
public string targetBuildingDefName = "WULA_Sky_Lock"; // 目标建筑类型
|
||||
public bool requireSameFaction = true; // 是否需要同派系
|
||||
public FloatRange healthThreshold = new FloatRange(0f, 1f); // 生命值阈值范围
|
||||
|
||||
// 效果设置
|
||||
public EffecterDef interceptEffecter;
|
||||
public SoundDef interceptSound;
|
||||
|
||||
public CompProperties_DamageInterceptor()
|
||||
{
|
||||
compClass = typeof(CompDamageInterceptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class CompProperties_DamageRelay : CompProperties
|
||||
{
|
||||
public float damageRelayRatio = 0.3f; // 继续传递伤害的比例
|
||||
public bool relayOnlyToSameFaction = true; // 是否只传递给同派系建筑
|
||||
public FloatRange healthThreshold = new FloatRange(0.1f, 1f); // 生命值阈值(低于此值才开始传递)
|
||||
|
||||
// 效果设置
|
||||
public EffecterDef relayEffecter;
|
||||
public SoundDef relaySound;
|
||||
|
||||
public CompProperties_DamageRelay()
|
||||
{
|
||||
compClass = typeof(CompDamageRelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using HarmonyLib;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
[HarmonyPatch(typeof(Pawn), "PreApplyDamage")]
|
||||
public static class Patch_Pawn_PreApplyDamage
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static bool Prefix(Pawn __instance, ref DamageInfo dinfo)
|
||||
{
|
||||
// 检查Pawn是否有伤害拦截组件
|
||||
var interceptorComp = __instance.TryGetComp<CompDamageInterceptor>();
|
||||
if (interceptorComp != null)
|
||||
{
|
||||
Log.Message($"[DamageInterceptor] {__instance.LabelShort} 即将受到 {dinfo.Amount} 点伤害,拦截组件激活");
|
||||
|
||||
// 让拦截组件处理伤害
|
||||
return interceptorComp.PreApplyDamage(ref dinfo);
|
||||
}
|
||||
|
||||
return true; // 继续正常处理伤害
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Pawn), "PostApplyDamage")]
|
||||
public static class Patch_Pawn_PostApplyDamage
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void Postfix(Pawn __instance, DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
// 记录实际承受的伤害
|
||||
var interceptorComp = __instance.TryGetComp<CompDamageInterceptor>();
|
||||
if (interceptorComp != null && totalDamageDealt == 0f)
|
||||
{
|
||||
Log.Message($"[DamageInterceptor] {__instance.LabelShort} 成功拦截所有伤害,实际承受0点伤害");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user