diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index af51cdd..8f71447 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/DamageDefs/ARA_Damage_Freeze.xml b/1.6/1.6/Defs/DamageDefs/ARA_Damage_Freeze.xml
new file mode 100644
index 0000000..9befb28
--- /dev/null
+++ b/1.6/1.6/Defs/DamageDefs/ARA_Damage_Freeze.xml
@@ -0,0 +1,280 @@
+
+
+
+
+
+ ARA_Hediff_Frozen
+
+ 这个身体部位正在被冷冻。移动会因此减慢。如果该部位被完全冷冻,它将在下一次受到冲击时碎裂。
+ ArachnaeSwarm.Hediff_Frozen
+ true
+
+
+ -6
+
+
+ 0.3
+
+
+
+
+ 0
+ true
+ 已碎裂
+
+
+
+
+ true
+
+
+
+ 0.2
+
+ 40
+
+
+
+
+
+
+ 0.35
+
+ 80
+
+
+
+ Moving
+ -0.1
+
+
+ Manipulation
+ -0.2
+
+
+
+
+
+ 0.5
+
+ 120
+
+
+
+ Moving
+ -0.3
+
+
+ Manipulation
+ -0.4
+
+
+
+
+
+ 0.65
+
+ 160
+
+
+
+ Moving
+ -0.5
+
+
+ Manipulation
+ -0.6
+
+
+
+
+
+ 0.85
+
+ 200
+
+
+
+ Moving
+ 0.2
+
+
+ Manipulation
+ 0.2
+
+
+
+
+
+
+
+ ARA_Hediff_FrostCoverd_after
+
+ 此人被一片冰霜之云所覆盖。
+ (1, 1, 0.8)
+ HediffWithComps
+
+
+ -4
+
+
+ ARA_Damage_Freeze
+ Explosion_Stun
+ 3
+ true
+ 5
+ 0.10
+ 60~120
+ ARA_FrostGasCloud
+ 1
+ 1
+
+
+
+
+
+
+
+
+ ARA_CryoShock
+
+ 此人正处于低温休克状态。
+ (1, 1, 0.8)
+ ArachnaeSwarm.HediffCurseFlame
+
+
+ -6
+
+
+
+
+ Stun
+ 1~2
+ 80
+
+
+
+ 0.02
+
+
+
+
+ true
+
+
+
+ 0.2
+
+ 40
+
+
+
+ Consciousness
+ -0.10
+
+
+
+
+
+ 0.35
+
+ 80
+
+
+
+ Consciousness
+ -0.20
+
+
+
+
+
+ 0.5
+
+ 120
+
+
+
+ Consciousness
+ -0.20
+
+
+
+
+
+ 0.65
+
+ 160
+
+
+
+ Consciousness
+ -0.30
+
+
+
+
+
+ 0.85
+
+ 200
+
+
+
+ Consciousness
+ -0.30
+
+
+
+
+
+
+
+
+ ARA_Damage_Freeze
+
+ DamageWorker_AddInjury
+ true
+ {0}的身体在极寒中化为了冰雕,随后碎裂四散。
+ ARA_Hediff_Frozen
+ ARA_Hediff_Frozen
+ false
+ Heat
+ 0
+ 3
+ 0
+ 0
+ 0
+
+
+
+
+ ARA_Damage_Freeze_ex
+
+ DamageWorker_AddInjury
+ true
+ {0}的身体在极寒中化为了冰雕,随后碎裂四散。
+ ARA_Hediff_Frozen
+ ARA_Hediff_Frozen
+ false
+ Heat
+ 0
+ 3
+ 0
+ 0
+ 0
+
+
+ ARA_CryoShock
+ 0.01
+
+
+ ARA_Hediff_FrostCoverd_after
+ 0.01
+ true
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml b/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
index cbf1f62..777653d 100644
--- a/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
+++ b/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
@@ -66,6 +66,7 @@
ARA_Building_SpiderOne
ARA_PowerArmor_NoFuel
0.5
+ ARA_RW_Icez_Mortar
diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_Things_Gas.xml b/1.6/1.6/Defs/Thing_Misc/ARA_Things_Gas.xml
index 6cb81c8..433afbf 100644
--- a/1.6/1.6/Defs/Thing_Misc/ARA_Things_Gas.xml
+++ b/1.6/1.6/Defs/Thing_Misc/ARA_Things_Gas.xml
@@ -41,31 +41,86 @@
-
- ARA_AcidGasCloud
-
-
- Things/Gas/Puff
- 2.6
- (0.56, 1, 0.03,0.5)
-
-
-
- 30
- 50
-
-
- 20
-
- ArachnaeSwarm.OPToxicGas
-
-
- ARA_AcidCoverd
- 0.1
- 240
-
-
-
+ 20
+
+ ArachnaeSwarm.OPToxicGas
+
+
+ ARA_AcidCoverd
+ 0.1
+ 240
+
+
+
+
+
+
+ ARA_FrostGasCloud_Ex
+
+
+ Things/Gas/Puff
+ 2.6
+ (0.52, 1, 0.95,0.5)
+
+
+
+ 5
+ 10
+
+
+ 5
+
+ ArachnaeSwarm.OPToxicGas
+
+
+ ARA_Hediff_FrostCoverd_after
+ 0.1
+ 240
+
+
+
+
+
+ ARA_FrostGasCloud
+
+
+ Things/Gas/Puff
+ 2.6
+ (0.52, 1, 0.95,0.5)
+
+
+
+ 5
+ 10
+
+
+ 5
+
+ ArachnaeSwarm.OPToxicGas
+
+
+ ARA_CryoShock
+ 0.1
+ 240
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
index 7b60faa..16af3ca 100644
--- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
@@ -1093,7 +1093,7 @@
true
false
5
- 120
+ 80
1
SpitterSpit
diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Icez.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Icez.xml
new file mode 100644
index 0000000..536373e
--- /dev/null
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_Icez.xml
@@ -0,0 +1,122 @@
+
+
+
+ ARA_RW_Icez_Mortar
+
+ 阿拉克涅虫群督虫使用大型远程武装器官,可以发射极度冰冷的霜冻气团,被接触到的敌人会产生霜冻爆炸,一旦被冻结不会立即致死,但随之而来的任何外来伤害都会立刻摧毁脆弱的冰雕。
+ Normal
+ Animal
+
+ ARA_Cocoon_Weapon_2Stage
+
+
+ ArachnaeSwarm/Weapon/ARA_RW_Acid_Mortar
+ Graphic_Single
+ 1.5
+
+ 0.75
+ SpitterSpawn
+
+
+ ARA_Technology_9VXI
+ UnfinishedWeapon
+
+
+ 2500
+ 1300
+
+ 3.5
+ 0.3
+ 0.3
+ 0.25
+ 0.1
+ 3.5
+ 450
+ 15
+
+
+
+ Verb_Shoot
+ true
+ false
+ 1.5
+ 3
+ Bullet_ARA_RW_Icez_Mortar
+ true
+ false
+ 5
+ 80
+ 1
+ SpitterSpit
+
+ true
+
+
+
+
+ 50
+
+
+ ARA_Armed_Organ
+ ARA_Armed_Organ_Ranged
+ ARA_Armed_Organ_T2
+
+ 0
+ None
+
+
+
+
+
+ ARA_Huge_Weapon
+ ARA_Weapon_Damage_Acid
+
+
+ 2
+ 2
+
+
+
+
+
+ Bullet_ARA_RW_Icez_Mortar
+
+
+ Graphic_Single_AgeSecs
+ Things/Projectile/FleshmassSpitterProjectileSheet
+ (.75, .75)
+ MoteGlow
+
+ 0.8
+ Projectile_Explosive
+
+ True
+ 1
+ ARA_Damage_Freeze_ex
+ 15
+ 25
+ 45
+ 1
+ 3.5
+ true
+ ARA_FrostGasCloud_Ex
+ 1
+ 1
+ Explosion_Stun
+ false
+
+
+
+ Shell_AcidSpitStream
+
+
+ Shell_AcidSpitLaunched
+
+
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
index 611ee5c..4cc24b8 100644
--- a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
+++ b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
@@ -1,19 +1,21 @@
using RimWorld;
using Verse;
-using Verse.Sound;
namespace ArachnaeSwarm
{
[DefOf]
public static class ARA_HediffDefOf
{
- public static HediffDef ARA_AcidCoverd;
+ public static HediffDef ARA_Hediff_Frozen;
+ public static HediffDef ARA_Hediff_FrostCoverd_after;
+ public static HediffDef ARA_CryoShock;
public static HediffDef ARA_HiveMindMaster;
public static HediffDef ARA_HiveMindDrone;
- public static HediffDef ARA_HiveMindWorker;
+ public static HediffDef ARA_HiveMindWorker; // 如果存在这个Def
+
static ARA_HediffDefOf()
{
- DefOfHelper.EnsureInitializedInCtor(typeof(HediffDefOf));
+ DefOfHelper.EnsureInitializedInCtor(typeof(ARA_HediffDefOf));
}
}
}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index c3a7155..c1f9dcb 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -192,6 +192,9 @@
+
+
+
@@ -272,12 +275,12 @@
+
-
diff --git a/Source/ArachnaeSwarm/HarmonyPatch_Pawn_HealthTracker_PreApplyDamage.cs b/Source/ArachnaeSwarm/HarmonyPatch_Pawn_HealthTracker_PreApplyDamage.cs
new file mode 100644
index 0000000..644bc80
--- /dev/null
+++ b/Source/ArachnaeSwarm/HarmonyPatch_Pawn_HealthTracker_PreApplyDamage.cs
@@ -0,0 +1,73 @@
+using HarmonyLib;
+using RimWorld;
+using Verse;
+using System.Linq;
+using UnityEngine; // For FleckMaker
+
+namespace ArachnaeSwarm
+{
+ // Harmony 入口点,将在 Mod 加载时自动初始化
+ [StaticConstructorOnStartup]
+ public static class HarmonyPatches
+ {
+ static HarmonyPatches()
+ {
+ var harmony = new Harmony("ArachnaeSwarm.FreezeMod");
+ harmony.PatchAll();
+ }
+ }
+
+ // 补丁目标:Pawn_HealthTracker 类的 PreApplyDamage 方法
+ [HarmonyPatch(typeof(Pawn_HealthTracker), "PreApplyDamage")]
+ public static class HarmonyPatch_Pawn_HealthTracker_PreApplyDamage
+ {
+ // Postfix 补丁:在原方法执行后运行
+ // __instance 是 Pawn_HealthTracker 的实例
+ // dinfo 是 DamageInfo 的引用
+ // absorbed 是 out bool 参数的引用
+ public static void Postfix(Pawn_HealthTracker __instance, ref DamageInfo dinfo, ref bool absorbed)
+ {
+ // 如果伤害已经被吸收,或者没有击中任何部位,则不处理
+ if (absorbed || dinfo.HitPart == null)
+ {
+ return;
+ }
+
+ Pawn pawn = (Pawn)AccessTools.Field(typeof(Pawn_HealthTracker), "pawn").GetValue(__instance);
+ if (pawn == null)
+ {
+ return;
+ }
+
+ // 复制一份 dinfo,避免 ref 参数在 lambda 中使用的问题
+ DamageInfo currentDinfo = dinfo;
+
+ // 获取被击中部位上的 Hediff_Frozen
+ Hediff_Frozen frozenHediff = pawn.health.hediffSet.hediffs.OfType()
+ .FirstOrDefault(h => h.Part == currentDinfo.HitPart);
+
+ // 如果该部位存在 Hediff_Frozen 并且已经完全冷冻
+ if (frozenHediff != null && frozenHediff.Severity >= currentDinfo.HitPart.def.GetMaxHealth(pawn))
+ {
+ // 检查伤害是否是我们的冷冻伤害(防止循环触发)
+ if (currentDinfo.Def.hediff == ARA_HediffDefOf.ARA_Hediff_Frozen)
+ {
+ return; // 忽略我们自己的冷冻伤害
+ }
+
+ // 检查伤害是否是会造成生命值损伤的普通伤害
+ if (currentDinfo.Def.harmsHealth && currentDinfo.Amount > 0.01f)
+ {
+ // 施加一个巨大的、足以摧毁该部位的伤害
+ DamageInfo fatalDamage = new DamageInfo(DamageDefOf.Crush, 99999f, 999f, -1f, currentDinfo.Instigator, currentDinfo.HitPart);
+ pawn.TakeDamage(fatalDamage);
+
+ // 播放一个破碎的特效
+ FleckMaker.Static(pawn.Position, pawn.Map, FleckDefOf.ExplosionFlash, 2f);
+
+ absorbed = true; // 标记原伤害已被处理,阻止其继续执行
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/HediffComp_GlobalFreeze.cs b/Source/ArachnaeSwarm/HediffComp_GlobalFreeze.cs
new file mode 100644
index 0000000..6d8bd07
--- /dev/null
+++ b/Source/ArachnaeSwarm/HediffComp_GlobalFreeze.cs
@@ -0,0 +1,72 @@
+using RimWorld;
+using Verse;
+using System.Linq;
+
+namespace ArachnaeSwarm
+{
+ public class HediffComp_GlobalFreeze : HediffComp
+ {
+ private const int CheckInterval = 60; // 每60 ticks检查一次 (1秒)
+ private bool isStunnedByFreeze = false; // 用于追踪是否是由我们这个组件造成的眩晕
+
+ public HediffCompProperties_GlobalFreeze Props => (HediffCompProperties_GlobalFreeze)props;
+
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ base.CompPostTick(ref severityAdjustment);
+
+ // 每隔一段时间才执行一次,避免性能问题
+ if (Pawn.IsHashIntervalTick(CheckInterval))
+ {
+ // 计算全身所有Hediff_Frozen的总严重性
+ float totalFreezeSeverity = Pawn.health.hediffSet.hediffs
+ .OfType()
+ .Sum(h => h.Severity);
+
+ // 获取Pawn的总生命值作为参考
+ float totalBodyHealth = Pawn.health.summaryHealth.SummaryHealthPercent * Pawn.MaxHitPoints;
+
+ // 计算冷冻阈值
+ float stunThreshold = totalBodyHealth * Props.stunThreshold;
+
+ // 如果总冷冻值超过阈值
+ if (totalFreezeSeverity >= stunThreshold)
+ {
+ // 如果Pawn当前没有被眩晕,则施加一个“永久”的眩晕
+ // StunFor会取最大值,所以我们给一个足够长的时间(5秒),它会在下一轮检查时被刷新
+ if (!Pawn.stances.stunner.Stunned)
+ {
+ Pawn.stances.stunner.StunFor(300, Pawn, false, true);
+ isStunnedByFreeze = true;
+ }
+ }
+ // 如果总冷冻值低于阈值,并且之前是由我们造成的眩晕
+ else if (isStunnedByFreeze)
+ {
+ // 立即停止眩晕
+ // 我们通过将stunTicksLeft设置为0来直接唤醒它
+ Pawn.stances.stunner.StunFor(0, Pawn, false, false);
+ isStunnedByFreeze = false;
+ }
+ }
+ }
+
+ // 保存和加载我们的状态,确保读档后逻辑正确
+ public override void CompExposeData()
+ {
+ base.CompExposeData();
+ Scribe_Values.Look(ref isStunnedByFreeze, "isStunnedByFreeze", false);
+ }
+ }
+
+ public class HediffCompProperties_GlobalFreeze : HediffCompProperties
+ {
+ // XML中可配置的阈值,默认为全身健康的30%
+ public float stunThreshold = 0.3f;
+
+ public HediffCompProperties_GlobalFreeze()
+ {
+ compClass = typeof(HediffComp_GlobalFreeze);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/HediffComp_TimedExplosion.cs b/Source/ArachnaeSwarm/HediffComp_TimedExplosion.cs
new file mode 100644
index 0000000..450399e
--- /dev/null
+++ b/Source/ArachnaeSwarm/HediffComp_TimedExplosion.cs
@@ -0,0 +1,244 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+using Verse.Noise;
+
+namespace ArachnaeSwarm // 修正命名空间
+{
+ public class HediffComp_TimedExplosion : HediffComp
+ {
+ // 倒计时相关字段
+ public int ticksToDisappear;
+ public int disappearsAfterTicks;
+ public int seed;
+
+ // 配置属性快捷访问
+ public HediffCompProperties_TimedExplosion Props =>
+ (HediffCompProperties_TimedExplosion)props;
+
+ // 消失判定属性
+ public override bool CompShouldRemove
+ {
+ get
+ {
+ if (ticksToDisappear > 0) return false;
+ if (Props.requiredMentalState != null)
+ {
+ return parent.pawn.MentalStateDef != Props.requiredMentalState;
+ }
+ return true;
+ }
+ }
+
+ // 进度计算
+ public float Progress =>
+ 1f - (float)ticksToDisappear / Mathf.Max(1, disappearsAfterTicks);
+
+ public int EffectiveTicksToDisappear => ticksToDisappear / TicksLostPerTick;
+
+ public float NoisyProgress => AddNoiseToProgress(Progress, seed);
+
+ public virtual int TicksLostPerTick => 1;
+
+ public override string CompLabelInBracketsExtra
+ {
+ get
+ {
+ if (Props.showRemainingTime)
+ {
+ if (EffectiveTicksToDisappear < 2500)
+ {
+ return EffectiveTicksToDisappear.ToStringSecondsFromTicks("F0");
+ }
+ return EffectiveTicksToDisappear.ToStringTicksToPeriod(allowSeconds: true, shortForm: true, canUseDecimals: true, allowYears: true, Props.canUseDecimalsShortForm);
+ }
+ return base.CompLabelInBracketsExtra;
+ }
+ }
+
+ private static float AddNoiseToProgress(float progress, int seed)
+ {
+ float num = (float)Perlin.GetValue(progress, 0.0, 0.0, 9.0, seed);
+ float num2 = 0.25f * (1f - progress);
+ return Mathf.Clamp01(progress + num2 * num);
+ }
+
+ // 初始化
+ public override void CompPostMake()
+ {
+ base.CompPostMake();
+ disappearsAfterTicks = Props.disappearsAfterTicks.RandomInRange;
+ seed = Rand.Int;
+ ticksToDisappear = disappearsAfterTicks;
+ }
+
+ // 每帧更新
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ ticksToDisappear--;
+ if (CompShouldRemove)
+ {
+ parent.pawn.health.RemoveHediff(parent);
+ }
+ }
+
+ // 移除后处理
+ public override void CompPostPostRemoved()
+ {
+ base.CompPostPostRemoved();
+
+ // 处理新鲜伤口状态
+ if (!Props.leaveFreshWounds && parent.Part != null)
+ {
+ foreach (BodyPartRecord part in parent.Part.GetPartAndAllChildParts())
+ {
+ Hediff_MissingPart hediff = parent.pawn.health.hediffSet.GetMissingPartFor(part) as Hediff_MissingPart;
+ if (hediff != null)
+ {
+ hediff.IsFresh = false;
+ }
+ }
+ }
+
+ // 触发爆炸逻辑
+ if (ShouldTriggerExplosion())
+ {
+ TriggerExplosion();
+ DestroyGearIfNeeded();
+ }
+
+ // 发送消息通知
+ if (!Props.messageOnDisappear.NullOrEmpty() && PawnUtility.ShouldSendNotificationAbout(parent.pawn))
+ {
+ Messages.Message(
+ Props.messageOnDisappear.Formatted(parent.pawn.Named("PAWN")),
+ parent.pawn,
+ MessageTypeDefOf.NeutralEvent
+ );
+ }
+
+ // 发送信件通知
+ if (!Props.letterTextOnDisappear.NullOrEmpty() &&
+ !Props.letterLabelOnDisappear.NullOrEmpty() &&
+ PawnUtility.ShouldSendNotificationAbout(parent.pawn))
+ {
+ Find.LetterStack.ReceiveLetter(
+ Props.letterLabelOnDisappear.Formatted(parent.pawn.Named("PAWN")),
+ Props.letterTextOnDisappear.Formatted(parent.pawn.Named("PAWN")),
+ LetterDefOf.NegativeEvent,
+ parent.pawn
+ );
+ }
+ }
+
+ // 爆炸条件检查
+ private bool ShouldTriggerExplosion()
+ {
+ return parent.pawn.Spawned &&
+ Props.explosionRadius > 0.01f &&
+ Props.damageDef != null &&
+ parent.pawn.Map != null;
+ }
+
+ // 执行爆炸
+ private void TriggerExplosion()
+ {
+ GenExplosion.DoExplosion(
+ center: parent.pawn.Position,
+ map: parent.pawn.Map,
+ radius: Props.explosionRadius,
+ damType: Props.damageDef,
+ instigator: parent.pawn,
+ damAmount: Props.damageAmount,
+ armorPenetration: Props.armorPenetration,
+ explosionSound: Props.soundDef,
+ weapon: null,
+ projectile: null,
+ intendedTarget: null,
+ postExplosionSpawnThingDef: Props.postExplosionSpawnThingDef,
+ postExplosionSpawnChance: Props.postExplosionSpawnChance,
+ postExplosionSpawnThingCount: Props.postExplosionSpawnThingCount,
+ postExplosionGasType: null,
+ applyDamageToExplosionCellsNeighbors: false,
+ chanceToStartFire: Props.chanceToStartFire,
+ damageFalloff: Props.damageFalloff,
+ direction: null,
+ ignoredThings: new List { parent.pawn }
+ );
+ }
+
+ // 装备销毁
+ private void DestroyGearIfNeeded()
+ {
+ if (!Props.destroyGear) return;
+
+ if (parent.pawn.equipment != null)
+ {
+ parent.pawn.equipment.DestroyAllEquipment(DestroyMode.Vanish);
+ }
+ if (parent.pawn.apparel != null)
+ {
+ parent.pawn.apparel.DestroyAll(DestroyMode.Vanish);
+ }
+ }
+
+ // 数据持久化
+ public override void CompExposeData()
+ {
+ Scribe_Values.Look(ref ticksToDisappear, "ticksToDisappear", 0);
+ Scribe_Values.Look(ref disappearsAfterTicks, "disappearsAfterTicks", 0);
+ Scribe_Values.Look(ref seed, "seed", 0);
+ }
+
+ // 调试信息
+ public override string CompDebugString()
+ {
+ return $"倒计时: {ticksToDisappear}\n爆炸半径: {Props.explosionRadius}";
+ }
+ }
+
+ public class HediffCompProperties_TimedExplosion : HediffCompProperties
+ {
+ [Header("消失设置")]
+ public IntRange disappearsAfterTicks = new IntRange(600, 1200);
+ public bool showRemainingTime = true;
+ public bool canUseDecimalsShortForm;
+ public MentalStateDef requiredMentalState;
+ public bool leaveFreshWounds = true;
+
+ [Header("爆炸设置")]
+ public float explosionRadius = 3f;
+ public DamageDef damageDef;
+ public int damageAmount = 20;
+ public float armorPenetration;
+ public SoundDef soundDef;
+ public float chanceToStartFire;
+ public bool damageFalloff = true;
+
+ [Header("后续效果")]
+ public bool destroyGear;
+ public GasType gasType;
+ public ThingDef postExplosionSpawnThingDef;
+ public float postExplosionSpawnChance;
+ public int postExplosionSpawnThingCount = 1;
+
+ [Header("通知设置")]
+ [MustTranslate]
+ public string messageOnDisappear;
+ [MustTranslate]
+ public string letterLabelOnDisappear;
+ [MustTranslate]
+ public string letterTextOnDisappear;
+ public bool sendLetterOnDisappearIfDead = true;
+
+ public HediffCompProperties_TimedExplosion()
+ {
+ compClass = typeof(HediffComp_TimedExplosion);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediff_Frozen.cs b/Source/ArachnaeSwarm/Hediff_Frozen.cs
new file mode 100644
index 0000000..b9adecc
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediff_Frozen.cs
@@ -0,0 +1,46 @@
+using RimWorld;
+using Verse;
+using UnityEngine;
+
+namespace ArachnaeSwarm
+{
+ public class Hediff_Frozen : Hediff_Injury
+ {
+ // 我们需要覆盖这个方法来改变在健康面板上显示的标签
+ public override string LabelInBrackets
+ {
+ get
+ {
+ // 如果严重性达到了部位的满生命值,就显示“完全冷冻”
+ if (Severity >= Part.def.GetMaxHealth(pawn))
+ {
+ return "Fully Frozen";
+ }
+ return base.LabelInBrackets;
+ }
+ }
+
+ // 当部位的疼痛感,可以根据严重性调整
+ public override float PainOffset
+ {
+ get
+ {
+ // 冷冻不造成额外疼痛
+ return 0f;
+ }
+ }
+
+ // 当一个部位的伤害被治疗(在这里就是冷冻值减少)时调用
+ public override void Heal(float amount)
+ {
+ // 减少严重性,但不让它低于0
+ Severity -= amount;
+ if (Severity < 0)
+ {
+ Severity = 0;
+ }
+ }
+
+ // 伤害拦截逻辑将通过 Harmony 补丁实现,不在 Hediff 内部处理
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs b/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
index 646af0a..2b48001 100644
--- a/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
+++ b/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
@@ -19,6 +19,7 @@ namespace ArachnaeSwarm
public float structurePointsMax = 500f;
public HediffDef hediffOnEmptyFuel;
public float fuelConsumptionRate = 0.5f; // Nutrition per day
+ public ThingDef powerArmorWeapon;
}
[StaticConstructorOnStartup]
@@ -51,6 +52,12 @@ namespace ArachnaeSwarm
public float StructurePointsPercent => StructurePoints / StructurePointsMax;
public Building sourceBuilding;
+ private ThingWithComps originalWeapon;
+
+ public void SetOriginalWeapon(ThingWithComps weapon)
+ {
+ originalWeapon = weapon;
+ }
#endregion
#region Ticker
@@ -110,6 +117,7 @@ namespace ArachnaeSwarm
base.ExposeData();
Scribe_Values.Look(ref structurePoints, "structurePoints", -1f);
Scribe_References.Look(ref sourceBuilding, "sourceBuilding");
+ Scribe_References.Look(ref originalWeapon, "originalWeapon");
}
#endregion
@@ -143,6 +151,25 @@ namespace ArachnaeSwarm
{
base.Notify_Unequipped(pawn);
+ // Handle weapon restoration
+ if (Ext?.powerArmorWeapon != null && pawn?.equipment != null)
+ {
+ ThingWithComps primaryWeapon = pawn.equipment.Primary;
+ if (primaryWeapon != null && primaryWeapon.def == Ext.powerArmorWeapon)
+ {
+ // Destroy the power armor's weapon instead of dropping it.
+ pawn.equipment.Remove(primaryWeapon);
+ primaryWeapon.Destroy();
+ }
+ }
+
+ if (originalWeapon != null && pawn?.equipment != null)
+ {
+ pawn.equipment.MakeRoomFor(originalWeapon);
+ pawn.equipment.AddEquipment(originalWeapon);
+ originalWeapon = null;
+ }
+
Building building = sourceBuilding;
// If the source building reference is lost, create a new one as a fallback.
@@ -171,6 +198,12 @@ namespace ArachnaeSwarm
buildingFuelComp.ReceiveFuel(apparelFuelComp.Fuel);
}
+ // Sync quality back to building
+ if (this.TryGetComp() is CompQuality apparelQuality && building.TryGetComp() is CompQuality buildingQuality)
+ {
+ buildingQuality.SetQuality(apparelQuality.Quality, ArtGenerationContext.Colony);
+ }
+
Log.Message($"[PA_Debug] Notify_Unequipped: Before spawning building (ID: {building.thingIDNumber}) - HitPoints: {building.HitPoints}, StackCount: {building.stackCount}");
// Ensure stackCount is at least 1 for buildings, as 0 stackCount causes errors during spawning
diff --git a/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
index 7515614..9ed75c4 100644
--- a/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
+++ b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
@@ -1,5 +1,8 @@
using RimWorld;
using Verse;
+using System.Collections.Generic;
+using Verse.AI; // For PathEndMode and Danger
+using UnityEngine; // For Texture2D
namespace ArachnaeSwarm
{
@@ -16,5 +19,34 @@ namespace ArachnaeSwarm
public class CompPowerArmorStation : ThingComp
{
public CompProperties_PowerArmorStation Props => (CompProperties_PowerArmorStation)props;
+
+ public override IEnumerable CompFloatMenuOptions(Pawn selPawn)
+ {
+ foreach (FloatMenuOption option in base.CompFloatMenuOptions(selPawn))
+ {
+ yield return option;
+ }
+
+ // Check if there's an apparelDef defined
+ if (Props.apparelDef == null)
+ {
+ yield break; // No apparel to wear
+ }
+
+ // Check if the pawn can interact with the building
+ if (!selPawn.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
+ {
+ yield return new FloatMenuOption("CannotEnterPowerArmor".Translate() + ": " + "CannotReach".Translate(), null);
+ }
+ else
+ {
+ void enterAction()
+ {
+ Job job = JobMaker.MakeJob(DefDatabase.GetNamed("ARA_EnterPowerArmor"), parent);
+ selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+ }
+ yield return new FloatMenuOption("EnterPowerArmor".Translate(parent.Label), enterAction);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs b/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs
deleted file mode 100644
index 0ec7543..0000000
--- a/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using HarmonyLib;
-using RimWorld;
-using System.Collections.Generic;
-using Verse;
-using Verse.AI;
-
-namespace ArachnaeSwarm
-{
- [HarmonyPatch(typeof(ThingWithComps), "GetFloatMenuOptions")]
- public static class Harmony_ThingWithComps_GetFloatMenuOptions
- {
- [HarmonyPostfix]
- public static IEnumerable Postfix(IEnumerable values, ThingWithComps __instance, Pawn selPawn)
- {
- // First, return all original options
- foreach (var value in values)
- {
- yield return value;
- }
-
- // --- DEBUG LOGGING ---
- // Use a more specific check to avoid log spam
- if (__instance.def.defName != null && __instance.def.defName.StartsWith("ARA_"))
- {
- Log.Message($"[PA_Debug] GetFloatMenuOptions Postfix triggered for: {__instance.def.defName}");
- }
-
- // Check if the thing is our power armor building
- var comp = __instance.GetComp();
-
- if (comp == null && __instance.def.defName != null && __instance.def.defName.StartsWith("ARA_"))
- {
- Log.Message($"[PA_Debug] CompPowerArmorStation is NULL for {__instance.def.defName}");
- }
-
- if (comp != null)
- {
- Log.Message($"[PA_Debug] CompPowerArmorStation FOUND for {__instance.def.defName}. Checking reachability.");
-
- // Check if the pawn can interact
- if (!selPawn.CanReserveAndReach(__instance, PathEndMode.InteractionCell, Danger.Deadly))
- {
- yield return new FloatMenuOption("CannotEnterPowerArmor".Translate() + ": " + "CannotReach".Translate(), null);
- }
- else
- {
- // Action to give the job
- void enterAction()
- {
- Job job = JobMaker.MakeJob(DefDatabase.GetNamed("ARA_EnterPowerArmor"), __instance);
- selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
- }
-
- yield return new FloatMenuOption("EnterPowerArmor".Translate(__instance.Label), enterAction);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs b/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
index 29bc532..007247a 100644
--- a/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
+++ b/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
@@ -50,11 +50,38 @@ namespace ArachnaeSwarm
apparelFuelComp.ReceiveFuel(buildingFuelComp.Fuel);
}
+ // Sync quality
+ if (building.TryGetComp() is CompQuality buildingQuality && apparel.TryGetComp() is CompQuality apparelQuality)
+ {
+ apparelQuality.SetQuality(buildingQuality.Quality, ArtGenerationContext.Colony);
+ }
+
// Wear the apparel. The second argument 'false' is lockWhileWorn.
// The third argument 'false' is playerForced, which is CRITICAL.
// If playerForced is true, the game automatically locks the apparel.
actor.apparel.Wear(apparel, false, false);
-
+
+ // Handle weapon switching
+ if (apparel.Ext.powerArmorWeapon != null)
+ {
+ if (actor.equipment.Primary != null)
+ {
+ apparel.SetOriginalWeapon(actor.equipment.Primary);
+ actor.equipment.TryDropEquipment(actor.equipment.Primary, out _, actor.Position, false);
+ }
+
+ ThingWithComps weapon = (ThingWithComps)ThingMaker.MakeThing(apparel.Ext.powerArmorWeapon);
+
+ // Sync weapon quality with armor quality
+ if (apparel.TryGetComp() is CompQuality existingApparelQuality && weapon.TryGetComp() is CompQuality weaponQuality)
+ {
+ weaponQuality.SetQuality(existingApparelQuality.Quality, ArtGenerationContext.Colony);
+ }
+
+ actor.equipment.MakeRoomFor(weapon);
+ actor.equipment.AddEquipment(weapon);
+ }
+
// Despawn the building
building.DeSpawn();
}