using RimWorld; using System; using System.Collections.Generic; using UnityEngine; using Verse; using Verse.Sound; namespace WulaFallenEmpire { /// /// 支持直击伤害的爆炸弹丸 /// public class Projectile_ExplosiveWithDirectHit : Projectile_Explosive { // 缓存ModExtension private ProjectileExtension_DirectHit directHitExtension = null; private TrackingBulletDef trackingDefInt; private int Fleck_MakeFleckTick; private Vector3 lastTickPosition; public TrackingBulletDef TrackingDef { get { if (trackingDefInt == null) { trackingDefInt = def.GetModExtension(); if (trackingDefInt == null) { Log.ErrorOnce($"TrackingBulletDef for {this.def.defName} is null. Creating a default instance.", this.thingIDNumber ^ 0x12345678); this.trackingDefInt = new TrackingBulletDef(); } } return trackingDefInt; } } 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); lastTickPosition = origin; } protected override void Tick() { base.Tick(); // 处理拖尾特效 if (TrackingDef != null && TrackingDef.tailFleckDef != null) { Fleck_MakeFleckTick++; if (Fleck_MakeFleckTick >= TrackingDef.fleckDelayTicks) { if (Fleck_MakeFleckTick >= (TrackingDef.fleckDelayTicks + TrackingDef.fleckMakeFleckTickMax)) { Fleck_MakeFleckTick = TrackingDef.fleckDelayTicks; } Map map = base.Map; int randomInRange = TrackingDef.fleckMakeFleckNum.RandomInRange; Vector3 currentPosition = base.ExactPosition; Vector3 previousPosition = lastTickPosition; for (int i = 0; i < randomInRange; i++) { float num = (currentPosition - previousPosition).AngleFlat(); float velocityAngle = TrackingDef.fleckAngle.RandomInRange + num; float randomInRange2 = TrackingDef.fleckScale.RandomInRange; float randomInRange3 = TrackingDef.fleckSpeed.RandomInRange; FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, TrackingDef.tailFleckDef, randomInRange2); dataStatic.rotation = (currentPosition - previousPosition).AngleFlat(); dataStatic.rotationRate = TrackingDef.fleckRotation.RandomInRange; dataStatic.velocityAngle = velocityAngle; dataStatic.velocitySpeed = randomInRange3; map.flecks.CreateFleck(dataStatic); } } } lastTickPosition = base.ExactPosition; } // 标记是否已经应用了直击伤害 private bool directDamageApplied = false; public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref directDamageApplied, "directDamageApplied", false); Scribe_Values.Look(ref Fleck_MakeFleckTick, "Fleck_MakeFleckTick", 0); Scribe_Values.Look(ref lastTickPosition, "lastTickPosition", Vector3.zero); if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (this.trackingDefInt == null) { this.trackingDefInt = this.def.GetModExtension(); if (this.trackingDefInt == null) { Log.ErrorOnce($"TrackingBulletDef is null for projectile {this.def.defName} after PostLoadInit. Creating a default instance.", this.thingIDNumber ^ 0x12345678); this.trackingDefInt = new TrackingBulletDef(); } } } } protected override void Impact(Thing hitThing, bool blockedByShield = false) { // 获取ModExtension if (directHitExtension == null) { directHitExtension = def.GetModExtension(); } // 应用直击伤害(只在有直接击中目标时) if (hitThing != null && directHitExtension != null && directHitExtension.directDamageAmount > 0 && !directDamageApplied) { ApplyDirectDamage(hitThing, blockedByShield); directDamageApplied = true; } // 调用基类方法处理爆炸 base.Impact(hitThing, blockedByShield); } /// /// 应用直击伤害 /// private void ApplyDirectDamage(Thing hitThing, bool blockedByShield = false) { // 如果只在无护盾时生效且有护盾阻挡,则不应用 if (blockedByShield && directHitExtension.applyDirectDamageOnlyWithoutShield) return; // 准备伤害信息 DamageInfo damageInfo = CreateDirectDamageInfo(); // 对目标造成伤害 hitThing.TakeDamage(damageInfo); // 播放效果 PlayDirectImpactEffects(hitThing); } /// /// 创建直击伤害信息 /// private DamageInfo CreateDirectDamageInfo() { // 确定伤害类型 DamageDef damageDef = directHitExtension.directDamageDef; if (damageDef == null) { // 默认使用爆炸伤害类型 damageDef = base.DamageDef ?? DamageDefOf.Bomb; } // 确定伤害量 int damageAmount = directHitExtension.directDamageAmount; if (directHitExtension.useEquipmentStatsForDirectDamage && equipment != null) { // 使用装备属性计算伤害 damageAmount = def.projectile.GetDamageAmount(equipment); } // 确定护甲穿透 float armorPenetration = directHitExtension.directArmorPenetration; if (directHitExtension.useEquipmentStatsForDirectDamage && equipment != null) { armorPenetration = def.projectile.GetArmorPenetration(equipment); } // 创建伤害信息 DamageInfo damageInfo = new DamageInfo( damageDef, damageAmount, armorPenetration, -1f, // 角度 launcher, null, // 击中部位 equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, intendedTarget.Thing ); // 添加额外伤害 AddExtraDirectDamages(damageInfo); return damageInfo; } /// /// 添加上额外伤害 /// private void AddExtraDirectDamages(DamageInfo mainDamage) { if (directHitExtension?.extraDirectDamages == null) return; foreach (var extraDamage in directHitExtension.extraDirectDamages) { if (extraDamage != null && extraDamage.def != null && extraDamage.amount > 0) { DamageInfo extraDamageInfo = new DamageInfo( extraDamage.def, extraDamage.amount, extraDamage.armorPenetration, -1f, launcher, null, equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, intendedTarget.Thing ); // 应用额外伤害 if (mainDamage.IntendedTarget != null && mainDamage.IntendedTarget != null) { mainDamage.IntendedTarget.TakeDamage(extraDamageInfo); } } } } /// /// 播放直击效果 /// private void PlayDirectImpactEffects(Thing hitThing) { Map map = base.Map; if (map == null) return; // 播放效果器 if (directHitExtension.directImpactEffecter != null) { Effecter effecter = directHitExtension.directImpactEffecter.Spawn(); effecter.Trigger(new TargetInfo(base.Position, map), new TargetInfo(hitThing.Position, map)); effecter.Cleanup(); } // 播放音效 if (directHitExtension.directImpactSound != null) { directHitExtension.directImpactSound.PlayOneShot(new TargetInfo(base.Position, map)); } } /// /// 覆盖爆炸方法以添加直击伤害信息 /// protected override void Explode() { // 在爆炸前确保直击伤害已经应用(如果是延迟爆炸的情况) if (!directDamageApplied && directHitExtension != null && directHitExtension.directDamageAmount > 0 && intendedTarget.Thing != null) { ApplyDirectDamage(intendedTarget.Thing, false); directDamageApplied = true; } // 调用基类爆炸方法 base.Explode(); } /// /// 获取调试信息 /// public string GetDirectHitDebugInfo() { if (directHitExtension == null) return "No direct hit extension configured."; string info = "Direct Hit Configuration:\n"; info += $"Damage Def: {directHitExtension.directDamageDef?.defName ?? "None"}\n"; info += $"Damage Amount: {directHitExtension.directDamageAmount}\n"; info += $"Armor Penetration: {directHitExtension.directArmorPenetration}\n"; info += $"Use Equipment Stats: {directHitExtension.useEquipmentStatsForDirectDamage}\n"; info += $"Apply Without Shield Only: {directHitExtension.applyDirectDamageOnlyWithoutShield}\n"; info += $"Extra Damages Count: {directHitExtension.extraDirectDamages?.Count ?? 0}\n"; info += $"Direct Damage Applied: {directDamageApplied}"; return info; } } /// /// 直击伤害ModExtension定义 /// public class ProjectileExtension_DirectHit : DefModExtension { /// /// 直击伤害类型(默认为爆炸伤害类型) /// public DamageDef directDamageDef = null; /// /// 直击伤害量 /// public int directDamageAmount = 0; /// /// 直击伤害护甲穿透 /// public float directArmorPenetration = 0f; /// /// 直击伤害是否受装备影响 /// public bool useEquipmentStatsForDirectDamage = false; /// /// 直击伤害额外伤害列表 /// public List extraDirectDamages = null; /// /// 直击伤害是否只在击穿护盾后生效 /// public bool applyDirectDamageOnlyWithoutShield = false; /// /// 直击伤害效果器 /// public EffecterDef directImpactEffecter = null; /// /// 直击伤害音效 /// public SoundDef directImpactSound = null; /// /// 是否显示直击伤害日志 /// public bool logDirectDamage = false; } }