diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index db604075..b930915a 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon.xml index fb6f39e3..73f74dac 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon.xml @@ -1219,7 +1219,7 @@ 0.6 3 - x +
  • WulaFallenEmpire.Verb_ShootBeamExplosive diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Penetrating.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Penetrating.xml index 3df15718..c6d234b2 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Penetrating.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Penetrating.xml @@ -4,7 +4,7 @@ WULA_RW_Penetrating_Rifle - + 一把经过实验性改造的“蓝锥”步枪,能够发射一种特殊的钢针,利用过载的能量使其在击中第一个目标后仍能继续飞行,对路径上的多个敌人造成伤害。 Spacer @@ -27,10 +27,10 @@ 1300 3.5 - 0.3 - 0.8 - 0.9 - 0.8 + 1.0 + 1.0 + 1.0 + 1.0 0.8 @@ -59,7 +59,13 @@ Bullet_WULA_RW_Penetrating_Rifle - WulaFallenEmpire.Projectile_WulaLineAttack + WulaFallenEmpire.Projectile_WulaLineAttack + +
  • + -1 + 0 +
  • + Normal True diff --git a/Source/WulaFallenEmpire/CompMaintenancePod.cs b/Source/WulaFallenEmpire/CompMaintenancePod.cs index f337a904..dee1f776 100644 --- a/Source/WulaFallenEmpire/CompMaintenancePod.cs +++ b/Source/WulaFallenEmpire/CompMaintenancePod.cs @@ -98,16 +98,6 @@ namespace WulaFallenEmpire } } - public override void PostDeSpawn(Map map, DestroyMode mode = DestroyMode.Vanish) - { - base.PostDeSpawn(map, mode); - // This handles cases like uninstalling where the pod is removed from the map - // without being "destroyed". We still need to eject the occupant. - Log.Warning($"[WulaPodDebug] Pod despawned. Ejecting pawn."); - EjectPawn(); - } - - // ===================== IThingHolder Implementation ===================== public void GetChildHolders(List outChildren) { diff --git a/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs index 82c48ef0..c21022f7 100644 --- a/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs +++ b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs @@ -5,14 +5,27 @@ using Verse; namespace WulaFallenEmpire { + // Final, robust extension class for configuring path-based penetration. + public class Wula_PathPierce_Extension : DefModExtension + { + // Set to a positive number for limited hits, or -1 for infinite penetration. + public int maxHits = 3; + // The percentage of damage lost per hit. 0.25 means 25% damage loss per hit. + public float damageFalloff = 0.25f; + } + public class Projectile_WulaLineAttack : Projectile { + private int hitCounter = 0; private List alreadyDamaged = new List(); private Vector3 lastTickPosition; + private Wula_PathPierce_Extension Props => def.GetModExtension(); + public override void ExposeData() { base.ExposeData(); + Scribe_Values.Look(ref hitCounter, "hitCounter", 0); Scribe_Collections.Look(ref alreadyDamaged, "alreadyDamaged", LookMode.Reference); Scribe_Values.Look(ref lastTickPosition, "lastTickPosition"); if (alreadyDamaged == null) @@ -26,70 +39,93 @@ namespace WulaFallenEmpire base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef); this.lastTickPosition = origin; this.alreadyDamaged.Clear(); + this.hitCounter = 0; } protected override void Tick() { Vector3 startPos = this.lastTickPosition; - - base.Tick(); // 这会更新弹丸的位置,并可能调用Impact() + base.Tick(); + + if (this.Destroyed) return; - if (this.Destroyed) - { - return; - } - Vector3 endPos = this.ExactPosition; + + CheckPathForDamage(startPos, endPos); - // 调用路径伤害检测 - DamageMissedPawns(startPos, endPos); - - // 为下一帧更新位置 this.lastTickPosition = endPos; } - + protected override void Impact(Thing hitThing, bool blockedByShield = false) { - // 在最终碰撞前,最后一次检查从上一帧到当前碰撞点的路径 - DamageMissedPawns(this.lastTickPosition, this.ExactPosition); + CheckPathForDamage(lastTickPosition, this.ExactPosition); - // 如果最终目标还没被路径伤害击中,在这里造成一次伤害 - if (hitThing != null && !alreadyDamaged.Contains(hitThing)) + if (hitThing != null && alreadyDamaged.Contains(hitThing)) { - DamageInfo dinfo = new DamageInfo(this.def.projectile.damageDef, (float)this.DamageAmount, this.ArmorPenetration, this.ExactRotation.eulerAngles.y, this.launcher, null, this.equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, this.intendedTarget.Thing); - hitThing.TakeDamage(dinfo); + base.Impact(null, blockedByShield); + } + else + { + base.Impact(hitThing, blockedByShield); } - - // 调用基类方法来处理XML中定义的爆炸等最终效果 - base.Impact(hitThing, blockedByShield); } - private void DamageMissedPawns(Vector3 startPos, Vector3 endPos) + private void CheckPathForDamage(Vector3 startPos, Vector3 endPos) { if (startPos == endPos) return; + int maxHits = Props?.maxHits ?? 1; + bool infinitePenetration = maxHits < 0; + + if (!infinitePenetration && hitCounter >= maxHits) return; + Map map = this.Map; float distance = Vector3.Distance(startPos, endPos); Vector3 direction = (endPos - startPos).normalized; - for (float i = 0; i < distance; i += 0.5f) + for (float i = 0; i < distance; i += 0.8f) { - Vector3 checkPos = startPos + direction * i; - IntVec3 checkCell = new IntVec3(checkPos); + if (!infinitePenetration && hitCounter >= maxHits) break; + + Vector3 checkPos = startPos + direction * i; + var thingsInCell = new HashSet(map.thingGrid.ThingsListAt(checkPos.ToIntVec3())); - if (!checkCell.InBounds(map)) continue; - - var thingsInCell = new HashSet(map.thingGrid.ThingsListAt(checkCell)); foreach (Thing thing in thingsInCell) { if (thing is Pawn pawn && pawn != this.launcher && !alreadyDamaged.Contains(pawn) && GenHostility.HostileTo(pawn, this.launcher.Faction)) { - var dinfo = new DamageInfo(this.def.projectile.damageDef, (float)this.DamageAmount, this.ArmorPenetration, this.ExactRotation.eulerAngles.y, this.launcher, null, this.equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, this.intendedTarget.Thing); - pawn.TakeDamage(dinfo); - alreadyDamaged.Add(pawn); + ApplyPathDamage(pawn); + if (!infinitePenetration && hitCounter >= maxHits) break; } } } } + + private void ApplyPathDamage(Pawn pawn) + { + Wula_PathPierce_Extension props = Props; + float falloff = props?.damageFalloff ?? 0.25f; + + // Damage falloff now applies universally, even for infinite penetration. + float damageMultiplier = Mathf.Pow(1f - falloff, hitCounter); + + int damageAmount = (int)(this.DamageAmount * damageMultiplier); + if (damageAmount <= 0) return; + + var dinfo = new DamageInfo( + this.def.projectile.damageDef, + damageAmount, + this.ArmorPenetration * damageMultiplier, + this.ExactRotation.eulerAngles.y, + this.launcher, + null, + this.equipmentDef, + DamageInfo.SourceCategory.ThingOrUnknown, + this.intendedTarget.Thing); + + pawn.TakeDamage(dinfo); + alreadyDamaged.Add(pawn); + hitCounter++; + } } } \ No newline at end of file