using System; using System.Collections.Generic; using System.Linq; using System.Text; using RimWorld; using UnityEngine; using Verse; using Verse.Sound; namespace WulaFallenEmpire { public class VerbProperties_Arc : VerbProperties { public DamageDef damageDef; public float EMPDamageAmount = -1f; public int damageAmount = -1; public float armorPenetration = -1f; public float affectedAngle; public bool isConductible = false; public int conductNum; public bool conductFriendly = false; } public class Verb_ShootArc : Verb { private VerbProperties_Arc Props { get { return (VerbProperties_Arc)this.verbProps; } } private int damageAmount { get { return (this.Props.damageAmount > 0) ? this.Props.damageAmount : this.verbProps.beamDamageDef.defaultDamage; } } private float armorPenetration { get { return (this.Props.armorPenetration > 0f) ? this.Props.armorPenetration : this.verbProps.beamDamageDef.defaultArmorPenetration; } } public override void WarmupComplete() { this.TryCastShot(); } protected override bool TryCastShot() { this.MakeExplosion(); bool flag = this.verbProps.soundCast != null; bool flag3 = flag; if (flag3) { this.verbProps.soundCast.PlayOneShot(new TargetInfo(this.caster.Position, this.caster.MapHeld, false)); } bool flag2 = this.verbProps.soundCastTail != null; bool flag4 = flag2; if (flag4) { this.verbProps.soundCastTail.PlayOneShotOnCamera(this.caster.Map); } return true; } private bool IsTargetImmobile(LocalTargetInfo target) { Thing thing = target.Thing; Pawn pawn = thing as Pawn; return pawn != null && !pawn.Downed && pawn.GetPosture() == PawnPosture.Standing; } public override bool CanHitTarget(LocalTargetInfo targ) { bool flag = this.caster == null || !this.caster.Spawned; bool flag2 = flag; return !flag2 && (targ == this.caster || this.CanHitTargetFrom(this.caster.Position, targ)); } protected void MakeExplosion() { Pawn casterPawn = this.CasterPawn; bool spawned = casterPawn.Spawned; bool flag11 = spawned; if (flag11) { Thing targetThing = this.currentTarget.Thing; bool flag = targetThing != null && this.IsTargetImmobile(this.currentTarget) && casterPawn.skills != null; bool flag12 = flag; if (flag12) { casterPawn.skills.Learn(SkillDefOf.Shooting, 250f * this.verbProps.AdjustedFullCycleTime(this, casterPawn), false, false); } bool flag2 = this.Props != null; bool flag13 = flag2; if (flag13) { List cells = Verb_ShootArc.circularSectorCellsStartedCaster(casterPawn.Position, casterPawn.Map, this.currentTarget.Cell, this.Props.range, this.Props.affectedAngle, false).ToList(); HashSet hashSet = this.HashSetConverter(cells); this.pawnConduct.Add(casterPawn); float weaponDamageMultiplier = base.EquipmentSource.GetStatValue(StatDefOf.RangedWeapon_DamageMultiplier, true, -1); int damageMultiplier = this.GetDamageAmount(weaponDamageMultiplier, null); float armorPenetrationMultiplier = this.GetArmorPenetration(weaponDamageMultiplier, null); foreach (IntVec3 cell in hashSet) { List list = casterPawn.Map.thingGrid.ThingsListAt(cell); for (int num = list.Count - 1; num >= 0; num--) { if (list[num] is Pawn p) { // 新增友方过滤逻辑 bool isFriendly = p.Faction != null && casterPawn.Faction != null && !p.Faction.HostileTo(casterPawn.Faction); if (!Props.conductFriendly && isFriendly) { continue; // 跳过友方目标 } // 原有姿势检查 bool isInvalidPosture = p.GetPosture() != PawnPosture.Standing && this.currentTarget.Thing != p; if (!isInvalidPosture) { this.pawnConduct.Add(p); } } } } bool isConductible = this.Props.isConductible; bool flag17 = isConductible; if (flag17) { for (int i = 0; i < this.Props.conductNum; i++) { bool flag6 = i > this.pawnConduct.Count - 2; bool flag18 = flag6; if (flag18) { break; } bool flag7 = this.Props.EMPDamageAmount > 0f; bool flag19 = flag7; if (flag19) { this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f); } this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], this.Props.damageDef, (float)damageMultiplier, armorPenetrationMultiplier); bool flag8 = this.verbProps.beamMoteDef != null; bool flag20 = flag8; if (flag20) { MoteMaker.MakeInteractionOverlay(this.verbProps.beamMoteDef, new TargetInfo(this.pawnConduct[i].Position, this.caster.Map, false), new TargetInfo(this.pawnConduct[i + 1].Position, this.caster.Map, false)); } } } else { IntVec3 position = this.caster.Position; float num2 = Mathf.Atan2(-(float)(this.currentTarget.Cell.z - position.z), (float)(this.currentTarget.Cell.x - position.x)) * 57.29578f; bool flag9 = num2 - this.Props.affectedAngle < -180f || num2 + this.Props.affectedAngle > 180f; bool flag21 = flag9; if (flag21) { FloatRange? affectedAngle = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(num2 - this.Props.affectedAngle), 180f)); // 修正后的爆炸调用(参数通过命名对齐) GenExplosion.DoExplosion( center: casterPawn.Position, map: this.caster.MapHeld, radius: this.verbProps.range, damType: this.Props.damageDef, instigator: null, damAmount: damageMultiplier, armorPenetration: armorPenetrationMultiplier, explosionSound: null, weapon: this.CasterPawn.equipment.Primary.def, projectile: null, intendedTarget: null, postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile, postExplosionSpawnChance: 0f, postExplosionSpawnThingCount: 1, postExplosionGasType: null, postExplosionGasRadiusOverride: null, postExplosionGasAmount: 0, applyDamageToExplosionCellsNeighbors: false, preExplosionSpawnThingDef: null, preExplosionSpawnChance: 0f, preExplosionSpawnThingCount: 1, chanceToStartFire: 0f, damageFalloff: false, direction: null, ignoredThings: null, affectedAngle: affectedAngle, doVisualEffects: true, propagationSpeed: 0.6f, excludeRadius: 0f, doSoundEffects: false, postExplosionSpawnThingDefWater: null, screenShakeFactor: 1f, flammabilityChanceCurve: null, overrideCells: null, postExplosionSpawnSingleThingDef: null, preExplosionSpawnSingleThingDef: null ); affectedAngle = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(num2 + this.Props.affectedAngle))); // 第二次爆炸调用(参数结构相同) GenExplosion.DoExplosion( center: casterPawn.Position, map: this.caster.MapHeld, radius: this.verbProps.range, damType: this.Props.damageDef, instigator: null, damAmount: damageMultiplier, armorPenetration: armorPenetrationMultiplier, explosionSound: null, weapon: this.CasterPawn.equipment.Primary.def, projectile: null, intendedTarget: null, postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile, postExplosionSpawnChance: 0f, postExplosionSpawnThingCount: 1, postExplosionGasType: null, postExplosionGasRadiusOverride: null, postExplosionGasAmount: 0, applyDamageToExplosionCellsNeighbors: false, preExplosionSpawnThingDef: null, preExplosionSpawnChance: 0f, preExplosionSpawnThingCount: 1, chanceToStartFire: 0f, damageFalloff: false, direction: null, ignoredThings: null, affectedAngle: affectedAngle, doVisualEffects: true, propagationSpeed: 0.6f, excludeRadius: 0f, doSoundEffects: false, postExplosionSpawnThingDefWater: null, screenShakeFactor: 1f, flammabilityChanceCurve: null, overrideCells: null, postExplosionSpawnSingleThingDef: null, preExplosionSpawnSingleThingDef: null ); } else { FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(num2 - this.Props.affectedAngle, num2 + this.Props.affectedAngle)); GenExplosion.DoExplosion( center: casterPawn.Position, map: this.caster.MapHeld, radius: this.verbProps.range, damType: this.Props.damageDef, instigator: null, damAmount: damageMultiplier, armorPenetration: armorPenetrationMultiplier, explosionSound: null, weapon: this.CasterPawn.equipment.Primary.def, projectile: null, intendedTarget: null, postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile, postExplosionSpawnChance: 0f, postExplosionSpawnThingCount: 1, postExplosionGasType: null, postExplosionGasRadiusOverride: null, postExplosionGasAmount: 0, applyDamageToExplosionCellsNeighbors: false, preExplosionSpawnThingDef: null, preExplosionSpawnChance: 0f, preExplosionSpawnThingCount: 1, chanceToStartFire: 0f, damageFalloff: false, direction: null, ignoredThings: null, affectedAngle: affectedAngle2, doVisualEffects: true, propagationSpeed: 0.6f, excludeRadius: 0f, doSoundEffects: false, postExplosionSpawnThingDefWater: null, screenShakeFactor: 1f, flammabilityChanceCurve: null, overrideCells: null, postExplosionSpawnSingleThingDef: null, preExplosionSpawnSingleThingDef: null ); } for (int j = 1; j < this.pawnConduct.Count(); j++) { bool flag10 = this.Props.EMPDamageAmount > 0f; bool flag22 = flag10; if (flag22) { this.TargetTakeDamage(casterPawn, this.pawnConduct[j], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f); } } } this.pawnConduct.Clear(); } } } public override void DrawHighlight(LocalTargetInfo target) { base.DrawHighlight(target); bool isValid = target.IsValid; bool flag = isValid; if (flag) { IntVec3 position = this.caster.Position; float num = Mathf.Atan2(-(float)(target.Cell.z - position.z), (float)(target.Cell.x - position.x)) * 57.29578f; Verb_ShootArc.RenderPredictedAreaOfEffect(this.caster.Position, this.Props.range, this.verbProps.explosionRadiusRingColor, new FloatRange(num - this.Props.affectedAngle, num + this.Props.affectedAngle)); } } public static void RenderPredictedAreaOfEffect(IntVec3 loc, float radius, Color color, FloatRange affectedAngle) { bool flag = affectedAngle.min < -180f || affectedAngle.max > 180f; bool flag2 = flag; List cellsSum; if (flag2) { DamageWorker worker = DamageDefOf.Bomb.Worker; Map currentMap = Find.CurrentMap; FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(affectedAngle.min), 180f)); List cells = worker.ExplosionCellsToHit(loc, currentMap, radius, null, null, affectedAngle2).ToList(); DamageWorker worker2 = DamageDefOf.Bomb.Worker; Map currentMap2 = Find.CurrentMap; affectedAngle2 = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(affectedAngle.max))); List cells2 = worker2.ExplosionCellsToHit(loc, currentMap2, radius, null, null, affectedAngle2).ToList(); cellsSum = cells.Concat(cells2).ToList(); } else { DamageWorker worker3 = DamageDefOf.Bomb.Worker; Map currentMap3 = Find.CurrentMap; FloatRange? affectedAngle3 = new FloatRange?(affectedAngle); cellsSum = worker3.ExplosionCellsToHit(loc, currentMap3, radius, null, null, affectedAngle3).ToList(); } GenDraw.DrawFieldEdges(cellsSum, color, null); } public static float AngleWrapped(float angle) { while (angle > 180f) { angle -= 360f; } while (angle < -180f) { angle += 360f; } return (angle == 180f) ? -180f : angle; } private static IEnumerable circularSectorCellsStartedCaster(IntVec3 center, Map map, IntVec3 target, float radius, float angle, bool useCenter = false) { float num = Mathf.Atan2(-(float)(target.z - center.z), (float)(target.x - center.x)) * 57.29578f; FloatRange affectedAngle = new FloatRange(num - angle, num + angle); bool flag = affectedAngle.min < -180f || affectedAngle.max > 180f; bool flag2 = flag; List cellsSum; if (flag2) { DamageWorker worker = DamageDefOf.Bomb.Worker; FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(affectedAngle.min), 180f)); List cells = worker.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle2).ToList(); DamageWorker worker2 = DamageDefOf.Bomb.Worker; affectedAngle2 = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(affectedAngle.max))); List cells2 = worker2.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle2).ToList(); cellsSum = cells.Concat(cells2).ToList(); } else { DamageWorker worker3 = DamageDefOf.Bomb.Worker; FloatRange? affectedAngle3 = new FloatRange?(affectedAngle); cellsSum = worker3.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle3).ToList(); } return cellsSum; } protected virtual HashSet HashSetConverter(IEnumerable points) { HashSet hashSet = new HashSet(); bool flag = points.Any(); bool flag2 = flag; if (flag2) { foreach (IntVec3 point in points) { hashSet.Add(point); } } return hashSet; } private void TargetTakeDamage(Pawn caster, Pawn target, DamageDef damageDef, float damageAmount, float armorPenetration = -1f) { bool flag = caster == null || target == null; bool flag2 = flag; if (flag2) { Log.Error("TargetTakeDamage has null caster or target"); } else { float angleFlat = (this.currentTarget.Cell - caster.Position).AngleFlat; BattleLogEntry_RangedImpact log = new BattleLogEntry_RangedImpact(caster, target, this.currentTarget.Thing, base.EquipmentSource.def, null, null); DamageInfo dinfo = new DamageInfo(damageDef, damageAmount, armorPenetration, angleFlat, caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing, true, true, QualityCategory.Normal, true); target.TakeDamage(dinfo).AssociateWithLog(log); } } public int GetDamageAmount(float weaponDamageMultiplier, StringBuilder explanation = null) { int num = this.damageAmount; bool flag = explanation != null; bool flag3 = flag; if (flag3) { explanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + num.ToString()); explanation.Append("StatsReport_QualityMultiplier".Translate() + ": " + weaponDamageMultiplier.ToStringPercent()); } num = Mathf.RoundToInt((float)num * weaponDamageMultiplier); bool flag2 = explanation != null; bool flag4 = flag2; if (flag4) { explanation.AppendLine(); explanation.AppendLine(); explanation.Append("StatsReport_FinalValue".Translate() + ": " + num.ToString()); } return num; } public float GetArmorPenetration(float weaponDamageMultiplier, StringBuilder explanation = null) { float num = this.armorPenetration; bool flag = num < 0f; bool flag4 = flag; if (flag4) { num = (float)this.damageAmount * 0.015f; } bool flag2 = explanation != null; bool flag5 = flag2; if (flag5) { explanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + num.ToStringPercent()); explanation.AppendLine(); explanation.Append("StatsReport_QualityMultiplier".Translate() + ": " + weaponDamageMultiplier.ToStringPercent()); } num *= weaponDamageMultiplier; bool flag3 = explanation != null; bool flag6 = flag3; if (flag6) { explanation.AppendLine(); explanation.AppendLine(); explanation.Append("StatsReport_FinalValue".Translate() + ": " + num.ToStringPercent()); } return num; } public List pawnConduct = new List(); } }