Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs
2025-08-17 16:28:01 +08:00

95 lines
3.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
namespace WulaFallenEmpire
{
public class Projectile_WulaLineAttack : Projectile
{
private List<Thing> alreadyDamaged = new List<Thing>();
private Vector3 lastTickPosition;
public override void ExposeData()
{
base.ExposeData();
Scribe_Collections.Look(ref alreadyDamaged, "alreadyDamaged", LookMode.Reference);
Scribe_Values.Look(ref lastTickPosition, "lastTickPosition");
if (alreadyDamaged == null)
{
alreadyDamaged = new List<Thing>();
}
}
public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null)
{
base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef);
this.lastTickPosition = origin;
this.alreadyDamaged.Clear();
}
protected override void Tick()
{
Vector3 startPos = this.lastTickPosition;
base.Tick(); // 这会更新弹丸的位置并可能调用Impact()
if (this.Destroyed)
{
return;
}
Vector3 endPos = this.ExactPosition;
// 调用路径伤害检测
DamageMissedPawns(startPos, endPos);
// 为下一帧更新位置
this.lastTickPosition = endPos;
}
protected override void Impact(Thing hitThing, bool blockedByShield = false)
{
// 在最终碰撞前,最后一次检查从上一帧到当前碰撞点的路径
DamageMissedPawns(this.lastTickPosition, this.ExactPosition);
// 如果最终目标还没被路径伤害击中,在这里造成一次伤害
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);
}
// 调用基类方法来处理XML中定义的爆炸等最终效果
base.Impact(hitThing, blockedByShield);
}
private void DamageMissedPawns(Vector3 startPos, Vector3 endPos)
{
if (startPos == endPos) 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)
{
Vector3 checkPos = startPos + direction * i;
IntVec3 checkCell = new IntVec3(checkPos);
if (!checkCell.InBounds(map)) continue;
var thingsInCell = new HashSet<Thing>(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);
}
}
}
}
}
}