diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index e2ba914..cc40cab 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/Thing_Misc/Weapons/ARA_Missile_Weapon.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Missile_Weapon.xml
index 7f4a573..923bccc 100644
--- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Missile_Weapon.xml
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Missile_Weapon.xml
@@ -141,7 +141,7 @@
25
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T1
@@ -234,7 +234,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
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 b9ace96..ae011f5 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
@@ -8,7 +8,7 @@
ARA_Cocoon_Weapon
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Melee
ARA_Armed_Organ_T1
@@ -81,7 +81,7 @@
ARA_Cocoon_Weapon_1Stage
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Melee
ARA_Armed_Organ_T2
@@ -164,7 +164,7 @@
ARA_Cocoon_Weapon_2Stage
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Melee
ARA_Armed_Organ_T3
@@ -302,7 +302,7 @@
25
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T1
@@ -420,7 +420,7 @@
25
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
@@ -493,7 +493,7 @@
25
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
@@ -563,7 +563,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
@@ -664,7 +664,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T1
@@ -772,7 +772,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
@@ -852,7 +852,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T2
@@ -969,7 +969,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T1
@@ -1045,7 +1045,7 @@
ARA_MW_Mimic_Niddle
阿拉克涅虫群督虫使用基础近战武装器官,通过多根外露神经束与督虫的辅肢相连。这根毒针中藏有休眠中的阿拉克涅拟线种虫卵,攻击将感染受害者使其最终成为被拟线虫操控的寄生体。
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Melee
ARA_Armed_Organ_T1
diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_FireSpew.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_FireSpew.xml
index f239743..d4ad35b 100644
--- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_FireSpew.xml
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon_FireSpew.xml
@@ -57,7 +57,7 @@
50
-
+
ARA_Armed_Organ
ARA_Armed_Organ_Ranged
ARA_Armed_Organ_T1
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml
new file mode 100644
index 0000000..0b549d1
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml
@@ -0,0 +1,7 @@
+
+
+
+
+ 守护者力场
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs b/Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs
index 43f34bb..52e019a 100644
--- a/Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs
+++ b/Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs
@@ -22,8 +22,8 @@ namespace ArachnaeSwarm
// Our comp is directly on the pawn, not on apparel
if (pawn.TryGetComp(out var interceptor))
{
- // Call our custom intercept method
- if (interceptor.TryIntercept(__instance))
+ // Call our custom intercept method, passing in the projectile's path
+ if (interceptor.TryIntercept(__instance, lastExactPos, newExactPos))
{
// If interception is successful, destroy the projectile
__instance.Destroy(DestroyMode.Vanish);
diff --git a/Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs b/Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs
index 33dde60..932e349 100644
--- a/Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs
+++ b/Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs
@@ -5,7 +5,6 @@ using Verse.Sound;
namespace ArachnaeSwarm
{
- // 1. Expanded CompProperties to match the user's example
public class CompProperties_GuardianPsyField : CompProperties
{
public float radius = 5.9f;
@@ -13,16 +12,12 @@ namespace ArachnaeSwarm
public int rechargeDelay = 3200; // Ticks after breaking
public int rechargeHitPointsIntervalTicks = 60; // Ticks to restore 1 HP
- // New properties for psyfocus/entropy mechanics
- public float psyfocusCostPerInterval = 0.001f; // e.g., 0.1% of max psyfocus per recharge interval
- public float entropyGainPerDamage = 0.5f; // For self
- // Removed entropyGainPerAllyDamage
- public float hitPointsPctPerInterval = 0.01f; // Restore 1% of max HP per interval
+ public float psyfocusCostPerInterval = 0.001f;
+ public float entropyGainPerDamage = 0.5f;
+ public float hitPointsPctPerInterval = 0.01f;
public EffecterDef absorbEffecter;
- // Removed transferAllyDamage
-
- // Projectile interception properties
- public bool interceptGroundProjectiles = false;
+
+ public bool interceptGroundProjectiles = true;
public bool interceptNonHostileProjectiles = false;
public bool interceptAirProjectiles = true;
@@ -41,19 +36,16 @@ namespace ArachnaeSwarm
[StaticConstructorOnStartup]
public class ThingComp_GuardianPsyField : ThingComp
{
- // --- State Variables ---
private int lastInterceptTicks = -999999;
- private int ticksToReset = 0; // Cooldown timer
+ private int ticksToReset = 0;
public int currentHitPoints;
- private bool wasNotAtFullHp = false; // Tracks if shield was damaged before recharge
+ private bool wasNotAtFullHp = false;
- // --- Properties ---
public CompProperties_GuardianPsyField Props => (CompProperties_GuardianPsyField)props;
private Pawn PawnOwner => parent as Pawn;
public bool IsOnCooldown => ticksToReset > 0;
public int HitPointsMax => Props.hitPoints;
- // --- Visuals ---
private static readonly Material ForceFieldMat = MaterialPool.MatFrom("Other/ForceField", ShaderDatabase.MoteGlow);
private static readonly MaterialPropertyBlock MatPropertyBlock = new MaterialPropertyBlock();
@@ -61,15 +53,12 @@ namespace ArachnaeSwarm
{
get
{
- // Shield is active if pawn is valid, hediff is present, not on cooldown, and has psyfocus.
- // currentHitPoints <= 0 should NOT prevent activation for recharge.
if (PawnOwner == null || !PawnOwner.Spawned || PawnOwner.Dead || PawnOwner.Downed || IsOnCooldown)
return false;
var hediff = PawnOwner.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("ARA_GuardianPsyField"));
if (hediff == null) return false;
- // Shield is only active if pawn has psyfocus
if (PawnOwner.psychicEntropy == null || PawnOwner.psychicEntropy.CurrentPsyfocus <= 0) return false;
return true;
@@ -103,134 +92,79 @@ namespace ArachnaeSwarm
Reset();
}
}
- // Only allow recharge if the shield is 'Active' (i.e., has psyfocus) and not on cooldown
else if (Active && currentHitPoints < HitPointsMax)
{
- // Check if there's enough psyfocus to pay for this interval's recharge
if (PawnOwner.psychicEntropy != null && PawnOwner.psychicEntropy.CurrentPsyfocus >= Props.psyfocusCostPerInterval)
{
- wasNotAtFullHp = true; // Mark that the shield was damaged
+ wasNotAtFullHp = true;
if(this.parent.IsHashIntervalTick(Props.rechargeHitPointsIntervalTicks))
{
currentHitPoints += (int)(HitPointsMax * Props.hitPointsPctPerInterval);
if(currentHitPoints > HitPointsMax) currentHitPoints = HitPointsMax;
-
- // Deduct psyfocus for this interval
PawnOwner.psychicEntropy.OffsetPsyfocusDirectly(-Props.psyfocusCostPerInterval);
}
}
- else
- {
- // Not enough psyfocus to recharge, log for debugging
- Log.Message($"[GuardianFieldComp] {PawnOwner.LabelShort} has insufficient psyfocus ({PawnOwner.psychicEntropy?.CurrentPsyfocus ?? 0}) to recharge shield (cost: {Props.psyfocusCostPerInterval}).");
- }
}
- // The full recharge psyfocus deduction is removed, as it's now gradual.
- // The wasNotAtFullHp check is still useful for other potential effects when full.
else if (wasNotAtFullHp && currentHitPoints >= HitPointsMax)
{
- wasNotAtFullHp = false; // Reset flag when full
+ wasNotAtFullHp = false;
}
}
- // Projectile interception logic remains the same, as it's a separate Harmony patch
- public bool TryIntercept(Projectile projectile)
+ // Helper method to apply costs
+ private void ApplyCosts(float damageAmount)
{
- if (!Active) return false;
-
- // Filter projectile types based on properties
- if (projectile.def.projectile.flyOverhead && !Props.interceptAirProjectiles) return false;
- if (!projectile.def.projectile.flyOverhead && !Props.interceptGroundProjectiles) return false;
- if (projectile.Launcher != null && !projectile.Launcher.HostileTo(PawnOwner.Faction) && !Props.interceptNonHostileProjectiles) return false;
-
- // --- Interception Success ---
- lastInterceptTicks = Find.TickManager.TicksGame;
-
- // Spawn effect at the point of interception, not the shield center
- Props.interceptEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), PawnOwner.Map).Cleanup();
-
- // No longer consuming hitpoints here, PostPreApplyDamage will handle it for self.
- // The Harmony_DamageWorker for allies will handle it for allies.
-
- return true;
- }
-
- // --- NEW: PostPreApplyDamage for self-protection (all damage types) ---
- public override void PostPreApplyDamage(ref DamageInfo dinfo, out bool absorbed)
- {
- absorbed = false;
- if (!Active || PawnOwner == null) return; // Only intercept if shield is active and for the owner
-
- // We intercept ALL damage types for the owner
- if (currentHitPoints < dinfo.Amount) return; // Not enough HP to absorb
-
- // --- Absorption Success for self ---
- Props.absorbEffecter?.Spawn(PawnOwner.Position, PawnOwner.Map).Cleanup(); // Effect at center for self-damage
-
- // Add entropy based on damage taken for self
if (PawnOwner.psychicEntropy != null && Props.entropyGainPerDamage > 0)
{
- PawnOwner.psychicEntropy.TryAddEntropy(dinfo.Amount * Props.entropyGainPerDamage, overLimit: true);
+ PawnOwner.psychicEntropy.TryAddEntropy(damageAmount * Props.entropyGainPerDamage, overLimit: true);
}
-
- // Consume Hitpoints
- currentHitPoints -= (int)dinfo.Amount;
+ currentHitPoints -= (int)damageAmount;
if (currentHitPoints <= 0)
{
Break();
}
- absorbed = true; // Damage was absorbed
}
+ public bool TryIntercept(Projectile projectile, Vector3 lastExactPos, Vector3 newExactPos)
+ {
+ if (!Active) return false;
+ if (currentHitPoints <= 0) return false;
- // --- REMOVED: Method for allies, called by Harmony patch ---
- // public bool TryAbsorbDamageForAllyOnly(DamageInfo dinfo, Pawn allyPawn)
- // {
- // Log.Message($"[GuardianFieldComp] TryAbsorbDamageForAllyOnly for {allyPawn.LabelShort} (target) by {PawnOwner.LabelShort} (caster).");
- // Log.Message($" - transferAllyDamage: {Props.transferAllyDamage}");
- // Log.Message($" - Active: {Active}");
- // Log.Message($" - allyPawn == PawnOwner: {allyPawn == PawnOwner}");
- // Log.Message($" - allyPawn.Faction: {allyPawn.Faction?.Name ?? "Null"}, PawnOwner.Faction: {PawnOwner.Faction?.Name ?? "Null"}, FactionMatch: {allyPawn.Faction == PawnOwner.Faction}");
- // Log.Message($" - InRange: {Vector3.Distance(allyPawn.TrueCenter(), PawnOwner.TrueCenter()) <= Props.radius}");
- // Log.Message($" - HasHP: {currentHitPoints >= dinfo.Amount}");
+ if (!GenGeo.IntersectLineCircleOutline(PawnOwner.Position.ToVector2(), Props.radius, lastExactPos.ToVector2(), newExactPos.ToVector2()))
+ {
+ return false;
+ }
- // // Check if ally damage transfer is enabled
- // if (!Props.transferAllyDamage) { Log.Message(" -> transferAllyDamage is false."); return false; }
-
- // // Shield must be active
- // if (!Active) { Log.Message(" -> Shield is not Active."); return false; }
-
- // // Cannot absorb damage for self (handled by PostPreApplyDamage)
- // if (allyPawn == PawnOwner) { Log.Message(" -> Target is self."); return false; }
-
- // // Only protect friendly pawns (same faction)
- // if (allyPawn.Faction == null || PawnOwner.Faction == null || allyPawn.Faction != PawnOwner.Faction) { Log.Message(" -> Faction mismatch or null faction."); return false; }
-
- // // Target must be in range
- // if (Vector3.Distance(allyPawn.TrueCenter(), PawnOwner.TrueCenter()) > Props.radius) { Log.Message(" -> Target out of range."); return false; }
-
- // // Check if shield has enough HP
- // if (currentHitPoints < dinfo.Amount) { Log.Message(" -> Not enough HP to absorb damage."); return false; }
-
- // // --- Absorption Success for ally ---
- // Props.absorbEffecter?.Spawn(allyPawn.Position, allyPawn.Map).Cleanup();
-
- // // Add entropy based on damage taken for ally
- // if (PawnOwner.psychicEntropy != null && Props.entropyGainPerAllyDamage > 0)
- // {
- // PawnOwner.psychicEntropy.TryAddEntropy(dinfo.Amount * Props.entropyGainPerAllyDamage, overLimit: true);
- // }
-
- // // Consume Hitpoints
- // currentHitPoints -= (int)dinfo.Amount;
- // if (currentHitPoints <= 0)
- // {
- // Break();
- // }
+ if (projectile.def.projectile.flyOverhead && !Props.interceptAirProjectiles) return false;
+ if (!projectile.def.projectile.flyOverhead && !Props.interceptGroundProjectiles) return false;
+ if (projectile.Launcher != null && !projectile.Launcher.HostileTo(PawnOwner.Faction) && !Props.interceptNonHostileProjectiles) return false;
- // Log.Message(" -> Damage absorption successful!");
- // return true; // Damage was absorbed
- // }
+ lastInterceptTicks = Find.TickManager.TicksGame;
+ Props.interceptEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), PawnOwner.Map).Cleanup();
+
+ // Apply costs for intercepting projectile
+ ApplyCosts(projectile.DamageAmount);
+
+ return true;
+ }
+
+ public override void PostPreApplyDamage(ref DamageInfo dinfo, out bool absorbed)
+ {
+ absorbed = false;
+ if (!Active || PawnOwner == null) return;
+
+ // We only handle non-projectile damage here, as projectiles are handled by TryIntercept
+ if (dinfo.Def.isRanged) return;
+
+ if (currentHitPoints < dinfo.Amount) return;
+
+ Props.absorbEffecter?.Spawn(PawnOwner.Position, PawnOwner.Map).Cleanup();
+
+ // Apply costs for absorbing non-projectile damage
+ ApplyCosts(dinfo.Amount);
+
+ absorbed = true;
+ }
private void Break()
{
@@ -275,7 +209,6 @@ namespace ArachnaeSwarm
return Mathf.Max(idleAlpha, interceptAlpha);
}
- // --- GIZMO ---
public override System.Collections.Generic.IEnumerable CompGetGizmosExtra()
{
if (PawnOwner != null && Find.Selector.SingleSelectedThing == PawnOwner)
@@ -285,7 +218,6 @@ namespace ArachnaeSwarm
}
}
- // Gizmo class copied from the user's example and adapted
[StaticConstructorOnStartup]
public class Gizmo_GuardianShieldStatus : Gizmo
{
@@ -304,7 +236,7 @@ namespace ArachnaeSwarm
Rect labelRect = rect2;
labelRect.height = rect.height / 2f;
Text.Font = GameFont.Tiny;
- Widgets.Label(labelRect, "Guardian Field");
+ Widgets.Label(labelRect, "ARA_GuardianFieldGizmoLabel".Translate());
Rect barRect = rect2;
barRect.yMin = rect2.y + rect2.height / 2f;