diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 4d620e5..98f7418 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml index 5a67720..4e73614 100644 --- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml +++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml @@ -663,8 +663,7 @@ ArachnaeNode_Race_Myrmecocystus - - 阿拉克涅督虫之一,拥有广泛食谱的大型虫族,可以吞下许多未经处理的生物并将其分解为阿拉克涅虫蜜,以滋养虫群。\n\n她可以进行搬运、烹饪和种植工作,战斗技能非常差。\n\n作为督虫,她可以繁育并监管若干阿拉克涅食腐种辅虫,以协助巢穴进行收割和播种工作。 + 阿拉克涅督虫之一,拥有广泛食谱的大型虫族,可以吞下许多未经处理的生物并将其分解为阿拉克涅虫蜜,以滋养虫群。\n\n她可以进行搬运、烹饪和种植工作,战斗技能非常差。\n\n作为督虫,她可以繁育并监管若干阿拉克涅食腐种辅虫,以协助巢穴进行收割和播种工作。 @@ -758,8 +757,7 @@ ArachnaeNode_Race_ShieldHead - - 阿拉克涅督虫之一,拥有过度生长而覆盖头部和腿部的甲壳,可以定时剥落甲壳素供虫巢使用。\n\n她可以进行搬运、采矿和建筑工作,战斗技能平平无奇,但是拥有较好的防御。\n\n作为督虫,她可以繁育并监管若干阿拉克涅坚颚种辅虫,以协助巢穴开采矿脉。 + 阿拉克涅督虫之一,拥有过度生长而覆盖头部和腿部的甲壳,可以定时剥落甲壳素供虫巢使用。\n\n她可以进行搬运、采矿和建筑工作,战斗技能平平无奇,但是拥有较好的防御。\n\n作为督虫,她可以繁育并监管若干阿拉克涅坚颚种辅虫,以协助巢穴开采矿脉。 @@ -879,8 +877,7 @@ ArachnaeNode_Race_WeaponSmith - - 阿拉克涅督虫之一,是少数拥有结茧能力的非女皇种阿拉克涅虫族——她们可以排出一枚器官茧,这枚茧将按照其信息素所标定的方向定向演化出一个武装器官,以供虫群使用。\n\n她可以进行搬运、手工和艺术工作,战斗技能平平无奇,但本身极度脆弱。\n\n作为督虫,她可以繁育并监管若干阿拉克涅家政种辅虫,以协助巢穴进行清洁和搬运工作。 + 阿拉克涅督虫之一,是少数拥有结茧能力的非女皇种阿拉克涅虫族——她们可以排出一枚器官茧,这枚茧将按照其信息素所标定的方向定向演化出一个武装器官,以供虫群使用。\n\n她可以进行搬运、手工和艺术工作,战斗技能平平无奇,但本身极度脆弱。\n\n作为督虫,她可以繁育并监管若干阿拉克涅家政种辅虫,以协助巢穴进行清洁和搬运工作。 @@ -964,8 +961,7 @@ ArachnaeNode_Race_Fighter - - 阿拉克涅督虫之一,是巢穴中真正的战士,其拥有强大的可塑性基因,随着科技的解锁其将获得更多的能力。\n\n她可以进行搬运、狩猎和驯兽工作,战斗技能非常亮眼,并且移动敏捷。\n\n作为督虫,她可以向敌人投射寿命有限但是非常恼人的阿拉克涅酸噬种辅虫,以阻止敌人的远程火力开火。 + 阿拉克涅督虫之一,是巢穴中真正的战士,其拥有强大的可塑性基因,随着科技的解锁其将获得更多的能力。\n\n她可以进行搬运、狩猎和驯兽工作,战斗技能非常亮眼,并且移动敏捷。\n\n作为督虫,她可以向敌人投射寿命有限但是非常恼人的阿拉克涅酸噬种辅虫,以阻止敌人的远程火力开火。 @@ -1050,8 +1046,7 @@ ArachnaeNode_Race_Facehugger - - 阿拉克涅督虫之一,呈现高度未分化状态的特殊督虫,可以通过独特的神经链接管控制受害者的身体,并释放灵能信号以使得周围的人忽略其存在。然而她本身实在过于脆弱,在完成寄生前难以胜任任何工作。\n\n她可以进行所有非研究工作,战斗技能约等于无。\n\n不同于普通阿拉克涅虫族,高度未分化的身体决定了其无法孕育任何辅虫。 + 阿拉克涅督虫之一,呈现高度未分化状态的特殊督虫,可以通过独特的神经链接管控制受害者的身体,并释放灵能信号以使得周围的人忽略其存在。然而她本身实在过于脆弱,在完成寄生前难以胜任任何工作。\n\n她可以进行所有非研究工作,战斗技能约等于无。\n\n不同于普通阿拉克涅虫族,高度未分化的身体决定了其无法孕育任何辅虫。 @@ -1110,8 +1105,7 @@ ArachnaeNode_Race_Smokepop - - 阿拉克涅督虫之一,身披厚重甲壳的大型虫族,拥有在大范围内喷射烟雾、阻燃物和铺设菌毯的能力,虽然移动速度比较慢,但是在战斗中就如同装甲车一样难以撼动。\n\n她可以进行搬运和医护工作,拥有不错的战斗技能,防御力和伤害耐受能力强大。\n\n作为督虫,她可以繁育并监管大量阿拉克涅家政种辅虫,以协助巢穴进行清洁和搬运工作。 + 阿拉克涅督虫之一,身披厚重甲壳的大型虫族,拥有在大范围内喷射烟雾、阻燃物和铺设菌毯的能力,虽然移动速度比较慢,但是在战斗中就如同装甲车一样难以撼动。\n\n她可以进行搬运和医护工作,拥有不错的战斗技能,防御力和伤害耐受能力强大。\n\n作为督虫,她可以繁育并监管大量阿拉克涅家政种辅虫,以协助巢穴进行清洁和搬运工作。 @@ -1202,8 +1196,7 @@ ArachnaeNode_Race_Skyraider - - 阿拉克涅督虫之一,众督虫中的精锐,进化出了强大的飞行能力,是巢穴中无可争议的空中霸主。\n\n她可以进行搬运工作,拥有不错的战斗技能,非常灵活。\n\n作为为数不多拥有飞行能力的虫族,她可以从空中掠袭猎物并将其带至千米高空之上俯冲投下,只留其余猎物在地面无助的挣扎。 + 阿拉克涅督虫之一,众督虫中的精锐,进化出了强大的飞行能力,是巢穴中无可争议的空中霸主。\n\n她可以进行搬运工作,拥有不错的战斗技能,非常灵活。\n\n作为为数不多拥有飞行能力的虫族,她可以从空中掠袭猎物并将其带至千米高空之上俯冲投下,只留其余猎物在地面无助的挣扎。 diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index 514182c..36c9596 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -184,6 +184,12 @@ + + + + + + diff --git a/Source/ArachnaeSwarm/HediffComp_NecroticTransformation.cs b/Source/ArachnaeSwarm/HediffComp_NecroticTransformation.cs new file mode 100644 index 0000000..ac96aa0 --- /dev/null +++ b/Source/ArachnaeSwarm/HediffComp_NecroticTransformation.cs @@ -0,0 +1,28 @@ +using Verse; +using RimWorld; + +namespace ArachnaeSwarm +{ + /// + /// XML配置类,用于在HediffDef的comp中指定转化后的MutantDef + /// + public class HediffCompProperties_NecroticTransformation : HediffCompProperties + { + // 在XML中需要指定的MutantDef的defName + public MutantDef mutantDef; + + public HediffCompProperties_NecroticTransformation() + { + compClass = typeof(HediffComp_NecroticTransformation); + } + } + + /// + /// HediffComp,用于在运行时存储和提供由XML定义的MutantDef + /// + public class HediffComp_NecroticTransformation : HediffComp + { + // 属性,用于方便地从Comp中获取配置 + public HediffCompProperties_NecroticTransformation Props => (HediffCompProperties_NecroticTransformation)props; + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/Hediff_NecroticVirus_Configurable.cs b/Source/ArachnaeSwarm/Hediff_NecroticVirus_Configurable.cs new file mode 100644 index 0000000..8192b5c --- /dev/null +++ b/Source/ArachnaeSwarm/Hediff_NecroticVirus_Configurable.cs @@ -0,0 +1,118 @@ +using RimWorld; +using Verse; +using UnityEngine; +using System.Linq; + +namespace ArachnaeSwarm +{ + public class Hediff_NecroticVirus : HediffWithComps + { + private const int EffectInterval = 600; + + // 属性来获取我们的自定义Comp + private HediffComp_NecroticTransformation PropsComp => this.TryGetComp(); + + public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null) + { + base.Notify_PawnDied(dinfo, culprit); + TransformToMutant(); + } + + public override void PostTick() + { + base.PostTick(); + if (pawn.IsHashIntervalTick(EffectInterval) && pawn.Spawned) + { + ShowVirusEffects(); + } + } + + private void TransformToMutant() + { + var comp = PropsComp; + if (comp == null || comp.Props.mutantDef == null) + { + Log.Error($"[NecroticVirus] HediffComp_NecroticTransformation or its mutantDef is not configured in XML for {this.def.defName}."); + return; + } + + try + { + if (pawn.Corpse == null || pawn.Corpse.Destroyed) + { + return; + } + + Map map = pawn.Corpse.Map; + IntVec3 position = pawn.Corpse.Position; + + if (!MutantUtility.CanResurrectAsShambler(pawn.Corpse)) + { + Log.Warning($"[NecroticVirus] Cannot resurrect {pawn.LabelShort} as a shambler-like creature."); + return; + } + + Faction faction = GetHostileFaction(); + + // **调用我们自己的工具方法,传入从XML获取的mutantDef** + NecroticTransformationUtility.ResurrectAsCustomMutant(pawn, comp.Props.mutantDef, faction); + + // 添加转化特效 + FleckMaker.ThrowSmoke(position.ToVector3Shifted(), map, 1.5f); + FleckMaker.ThrowDustPuff(position.ToVector3Shifted(), map, 1.2f); + + // 发送转化消息 + if (PawnUtility.ShouldSendNotificationAbout(pawn)) + { + Messages.Message( + "NecroticVirus_TransformationMessage".Translate(pawn.LabelShortCap, pawn.LabelShortCap), + new LookTargets(position, map), + MessageTypeDefOf.NegativeEvent + ); + } + } + catch (System.Exception ex) + { + Log.Error($"[NecroticVirus] Error during transformation: {ex}"); + } + } + + private Faction GetHostileFaction() + { + if (pawn.Faction != null && pawn.Faction.HostileTo(Faction.OfPlayer)) + { + return pawn.Faction; + } + + Faction entitiesFaction = Find.FactionManager.AllFactions.FirstOrDefault(f => f.def.defName == "Entities"); + if (entitiesFaction != null && !entitiesFaction.defeated) + { + return entitiesFaction; + } + + return Find.FactionManager.RandomEnemyFaction(allowNonHumanlike: true, allowHidden: false, allowDefeated: false); + } + + private void ShowVirusEffects() + { + if (pawn == null || !pawn.Spawned) return; + + Vector3 pos = pawn.DrawPos; + Map map = pawn.Map; + float sizeMultiplier = 1f; + if (CurStageIndex == 1) sizeMultiplier = 1.2f; + if (CurStageIndex == 2) sizeMultiplier = 1.5f; + + FleckMaker.ThrowMicroSparks(pos, map); + FleckMaker.ThrowDustPuff(pos, map, 0.8f * sizeMultiplier); + } + + public override string TipStringExtra + { + get + { + return base.TipStringExtra + "\n" + "NecroticVirus_EffectTip".Translate(); + } + } + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/NecroticTransformationUtility.cs b/Source/ArachnaeSwarm/NecroticTransformationUtility.cs new file mode 100644 index 0000000..ba24fca --- /dev/null +++ b/Source/ArachnaeSwarm/NecroticTransformationUtility.cs @@ -0,0 +1,65 @@ +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public static class NecroticTransformationUtility + { + /// + /// 将一个Pawn复活为指定的自定义变异体. + /// 这个方法是模仿原版 MutantUtility.ResurrectAsShambler, + /// 但允许传入一个自定义的 MutantDef. + /// + public static void ResurrectAsCustomMutant(Pawn pawn, MutantDef mutantDef, Faction faction = null, int lifespanTicks = -1) + { + if (pawn?.Corpse == null || mutantDef == null) + { + return; + } + + RotStage rotStage = pawn.Corpse.GetRotStage(); + + // 创建并附加Pawn_MutantTracker,使用我们从XML传入的mutantDef + pawn.mutant = new Pawn_MutantTracker(pawn, mutantDef, rotStage); + + // 添加变异体核心Hediff + Hediff hediff = pawn.health.AddHediff(mutantDef.hediff); + + // 如果是蹒跚者类型的Hediff,则调用其上升动画 + if (hediff is Hediff_Shambler shamblerHediff) + { + shamblerHediff.StartRising(lifespanTicks); + } + + // 设置生命周期 + var disappearsComp = hediff.TryGetComp(); + if (disappearsComp != null) + { + if (lifespanTicks > 0) + { + disappearsComp.disappearsAfterTicks = lifespanTicks; + disappearsComp.ticksToDisappear = lifespanTicks; + } + else + { + disappearsComp.disabled = true; + } + } + + // 如果没有提供派系,则尝试使用变异体定义的默认派系 + if (faction == null && mutantDef.defaultFaction != null) + { + faction = Find.FactionManager.FirstFactionOfDef(mutantDef.defaultFaction); + } + + // 设置派系 + if (faction != null && pawn.Faction != faction) + { + pawn.SetFaction(faction); + } + + // 立即执行转变 + pawn.mutant.Turn(clearLord: true); + } + } +} \ No newline at end of file diff --git a/Source/ArachnaeSwarm/ProphecyGearEffect.cs b/Source/ArachnaeSwarm/ProphecyGearEffect.cs new file mode 100644 index 0000000..470c82b --- /dev/null +++ b/Source/ArachnaeSwarm/ProphecyGearEffect.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using HarmonyLib; +using RimWorld; +using UnityEngine; +using Verse; + +namespace ArachnaeSwarm +{ + public class ProphecyGearEffect : DefModExtension + { + public HediffDef hediffToApply; + public float severityPerDamage = 0f; + public float minSeverity = 0f; + public float maxSeverity = 1f; + public bool enableHediffEffect = true; + + public float extraDamageFactor = 0f; + public DamageDef extraDamageType; + public float armorPenetration = 0f; + public BodyPartDef targetBodyPart; + public bool enableExtraDamage = true; + + // 新添加:触发效果所需的仿生体 Hediff + public HediffDef requiredBionicHediff; + } + + [HarmonyPatch(typeof(Pawn), "PostApplyDamage")] + public static class DRM_ProphecyGear_Patch + { + private static readonly FieldInfo damageInfoWeaponField = + typeof(DamageInfo).GetField("weapon", BindingFlags.Instance | BindingFlags.NonPublic); + + private static bool isApplyingExtraDamage = false; + + public static void Postfix(Pawn __instance, DamageInfo dinfo, float totalDamageDealt) + { + if (isApplyingExtraDamage) return; + + try + { + if (__instance == null || __instance.Dead || __instance.health == null) return; + if (!(dinfo.Instigator is Pawn attacker) || attacker.apparel == null) return; + if (totalDamageDealt <= 0) return; + + // 收集所有可能的效果来源 + var effectsToApply = new List(); + + // 1. 从装备收集效果 + foreach (var apparel in attacker.apparel.WornApparel) + { + var effect = apparel.def.GetModExtension(); + if (effect != null && IsEffectValid(effect, attacker)) + { + effectsToApply.Add(effect); + } + } + + // 2. 从仿生体 Hediff 收集效果 + foreach (var hediff in attacker.health.hediffSet.hediffs) + { + var effect = hediff.def.GetModExtension(); + if (effect != null && IsEffectValid(effect, attacker)) + { + effectsToApply.Add(effect); + } + } + + // 应用所有效果 + foreach (var effect in effectsToApply) + { + if (effect.enableHediffEffect && effect.hediffToApply != null) + { + ApplyHediffEffect(__instance, effect, totalDamageDealt); + } + + if (effect.enableExtraDamage && + effect.extraDamageFactor > 0 && + effect.extraDamageType != null) + { + isApplyingExtraDamage = true; + ApplyExtraDamage(__instance, effect, totalDamageDealt, dinfo); + isApplyingExtraDamage = false; + } + } + } + catch (Exception ex) + { + isApplyingExtraDamage = false; + Log.Error($"[ArachnaeSwarm] Error in PostApplyDamage patch: {ex}"); + } + } + + // 检查效果是否有效(满足仿生体要求) + private static bool IsEffectValid(ProphecyGearEffect effect, Pawn attacker) + { + // 如果没有要求仿生体,则始终有效 + if (effect.requiredBionicHediff == null) + return true; + + // 检查攻击者是否拥有所需的仿生体 + return attacker.health.hediffSet.HasHediff(effect.requiredBionicHediff); + } + + private static void ApplyHediffEffect(Pawn target, ProphecyGearEffect effect, float damageDealt) + { + try + { + double severityToAdd = (double)damageDealt * (double)effect.severityPerDamage; + float finalSeverity = (float)severityToAdd; + + if (finalSeverity < 0.001f) return; + + var existingHediff = target.health.hediffSet.GetFirstHediffOfDef(effect.hediffToApply); + + if (existingHediff == null) + { + Hediff newHediff = HediffMaker.MakeHediff(effect.hediffToApply, target); + if (newHediff != null) + { + newHediff.Severity = finalSeverity; + + if (effect.minSeverity > 0) + newHediff.Severity = Math.Max(newHediff.Severity, effect.minSeverity); + if (effect.maxSeverity > 0) + newHediff.Severity = Math.Min(newHediff.Severity, effect.maxSeverity); + + target.health.AddHediff(newHediff); + } + } + else + { + float newSeverity = existingHediff.Severity + finalSeverity; + + if (effect.minSeverity > 0) + newSeverity = Math.Max(newSeverity, effect.minSeverity); + if (effect.maxSeverity > 0) + newSeverity = Math.Min(newSeverity, effect.maxSeverity); + + existingHediff.Severity = newSeverity; + + if (existingHediff is HediffWithComps hwc) + { + var comp = hwc.TryGetComp(); + if (comp != null) + { + comp.ticksToDisappear = comp.Props.disappearsAfterTicks.max; + } + } + } + } + catch (Exception ex) + { + Log.Error($"[ArachnaeSwarm] Error in ApplyHediffEffect: {ex}"); + } + } + + private static void ApplyExtraDamage( + Pawn target, + ProphecyGearEffect effect, + float baseDamage, + DamageInfo originalDinfo) + { + try + { + float extraDamageAmount = baseDamage * effect.extraDamageFactor; + if (extraDamageAmount < 0.5f) extraDamageAmount = 0.5f; + if (extraDamageAmount <= 0) return; + + Thing weapon = null; + if (damageInfoWeaponField != null) + { + weapon = damageInfoWeaponField.GetValue(originalDinfo) as Thing; + } + + BodyPartRecord hitPart = null; + if (effect.targetBodyPart != null) + { + var bodyPartDef = DefDatabase.GetNamedSilentFail(effect.targetBodyPart.defName); + if (bodyPartDef != null) + { + hitPart = target.RaceProps.body.GetPartsWithDef(bodyPartDef).FirstOrFallback(); + } + } + else + { + hitPart = originalDinfo.HitPart; + } + + DamageInfo extraDinfo = new DamageInfo( + def: effect.extraDamageType, + amount: extraDamageAmount, + armorPenetration: effect.armorPenetration, + angle: -1f, + instigator: originalDinfo.Instigator, + hitPart: hitPart, + weapon: originalDinfo.Weapon, + category: DamageInfo.SourceCategory.ThingOrUnknown, + intendedTarget: target + ); + + target.TakeDamage(extraDinfo); + } + catch (Exception ex) + { + Log.Error($"[ArachnaeSwarm] Error in ApplyExtraDamage: {ex}"); + } + } + } +} \ No newline at end of file