diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 48a8b88f..77389a20 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/Source/WulaFallenEmpire/BulletWithTrail.cs b/Source/WulaFallenEmpire/BulletWithTrail.cs new file mode 100644 index 00000000..e9f96313 --- /dev/null +++ b/Source/WulaFallenEmpire/BulletWithTrail.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Reflection; +using RimWorld; +using UnityEngine; +using Verse; +using Verse.AI; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class BulletWithTrail : Bullet + { + 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; + } + + public override void ExposeData() + { + base.ExposeData(); + 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(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/HomingProjectileDef.cs b/Source/WulaFallenEmpire/HomingProjectileDef.cs deleted file mode 100644 index 69a279d1..00000000 --- a/Source/WulaFallenEmpire/HomingProjectileDef.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Verse; - -namespace WulaFallenEmpire -{ - public class HomingProjectileDef : DefModExtension - { - public float SpeedChangeTilesPerTickOverride; - public FloatRange SpeedRangeTilesPerTickOverride; - - public float hitChance = 0.5f; - - public float homingSpeed = 0.1f; - - public float initRotateAngle = 30f; - - public float proximityFuseRange = 0.5f; // 调整默认值,使其在接近目标时能正确触发引信 - - public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120); - - public ThingDef extraProjectile; - - public float speedChangePerTick; - - public FloatRange? speedRangeOverride; - public FleckDef tailFleckDef; - // 拖尾特效的详细配置参数 - public int fleckMakeFleckTickMax = 1; - public IntRange fleckMakeFleckNum = new IntRange(1, 1); - public FloatRange fleckAngle = new FloatRange(-180f, 180f); - public FloatRange fleckScale = new FloatRange(1f, 1f); - public FloatRange fleckSpeed = new FloatRange(0f, 0f); - public FloatRange fleckRotation = new FloatRange(-180f, 180f); - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/ModExtension_Cone.cs b/Source/WulaFallenEmpire/ModExtension_Cone.cs deleted file mode 100644 index 3008b5d7..00000000 --- a/Source/WulaFallenEmpire/ModExtension_Cone.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using Verse; - -namespace WulaFallenEmpire -{ - public class ModExtension_Cone : DefModExtension - { - public float coneAngle = 10f; - - public float coneRange = 7f; - - public int repeatExplosionCount = 1; - - public ThingDef fragment; - - public int fragmentCount; - - public FloatRange? fragmentRange; - - public bool showConeEffect = true; - - public void DoConeExplosion(IntVec3 center, Map map, Quaternion rotation, DamageDef damType, Thing instigator, int damAmount = -1, float armorPenetration = -1f, SoundDef explosionSound = null, ThingDef weapon = null, ThingDef projectile = null, Thing intendedTarget = null, ThingDef postExplosionSpawnThingDef = null, float postExplosionSpawnChance = 0f, int postExplosionSpawnThingCount = 1, GasType? postExplosionGasType = null, float? postExplosionGasRadiusOverride = null, int postExplosionGasAmount = 255, bool applyDamageToExplosionCellsNeighbors = false, ThingDef preExplosionSpawnThingDef = null, float preExplosionSpawnChance = 0f, int preExplosionSpawnThingCount = 1, float chanceToStartFire = 0f, bool damageFalloff = false, float? direction = null, List ignoredThings = null, float propagationSpeed = 1f, float excludeRadius = 0f, ThingDef postExplosionSpawnThingDefWater = null, float screenShakeFactor = 1f, SimpleCurve flammabilityChanceCurve = null, List overrideCells = null) - { - Vector3 v = rotation * Vector3.forward; - FloatRange initialAngleRange = new FloatRange(v.ToAngleFlat() - coneAngle, v.ToAngleFlat() + coneAngle); - - for (int i = 0; i < repeatExplosionCount; i++) - { - // Handle angle wrap-around for max > 360 - if (initialAngleRange.max > 360f) - { - GenExplosion.DoExplosion(affectedAngle: new FloatRange(0f, initialAngleRange.max - 360f), center: center, map: map, radius: coneRange, damType: damType, instigator: instigator, damAmount: damAmount, armorPenetration: armorPenetration, explosionSound: explosionSound, weapon: weapon, projectile: projectile, intendedTarget: intendedTarget, postExplosionSpawnThingDef: postExplosionSpawnThingDef, postExplosionSpawnChance: postExplosionSpawnChance, postExplosionSpawnThingCount: postExplosionSpawnThingCount, postExplosionGasType: postExplosionGasType, postExplosionGasRadiusOverride: postExplosionGasRadiusOverride, postExplosionGasAmount: postExplosionGasAmount, applyDamageToExplosionCellsNeighbors: applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef: preExplosionSpawnThingDef, preExplosionSpawnChance: preExplosionSpawnChance, preExplosionSpawnThingCount: preExplosionSpawnThingCount, chanceToStartFire: chanceToStartFire, damageFalloff: damageFalloff, direction: direction, ignoredThings: ignoredThings, doVisualEffects: showConeEffect, propagationSpeed: propagationSpeed, excludeRadius: excludeRadius, doSoundEffects: showConeEffect, postExplosionSpawnThingDefWater: postExplosionSpawnThingDefWater, screenShakeFactor: screenShakeFactor, flammabilityChanceCurve: flammabilityChanceCurve, overrideCells: overrideCells); - } - - // Handle angle wrap-around for min < 0 - if (initialAngleRange.min < 0f) - { - GenExplosion.DoExplosion(affectedAngle: new FloatRange(initialAngleRange.min + 360f, 360f), center: center, map: map, radius: coneRange, damType: damType, instigator: instigator, damAmount: damAmount, armorPenetration: armorPenetration, explosionSound: explosionSound, weapon: weapon, projectile: projectile, intendedTarget: intendedTarget, postExplosionSpawnThingDef: postExplosionSpawnThingDef, postExplosionSpawnChance: postExplosionSpawnChance, postExplosionSpawnThingCount: postExplosionSpawnThingCount, postExplosionGasType: postExplosionGasType, postExplosionGasRadiusOverride: postExplosionGasRadiusOverride, postExplosionGasAmount: postExplosionGasAmount, applyDamageToExplosionCellsNeighbors: applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef: preExplosionSpawnThingDef, preExplosionSpawnChance: preExplosionSpawnChance, preExplosionSpawnThingCount: preExplosionSpawnThingCount, chanceToStartFire: chanceToStartFire, damageFalloff: damageFalloff, direction: direction, ignoredThings: ignoredThings, doVisualEffects: showConeEffect, propagationSpeed: propagationSpeed, excludeRadius: excludeRadius, doSoundEffects: showConeEffect, postExplosionSpawnThingDefWater: postExplosionSpawnThingDefWater, screenShakeFactor: screenShakeFactor, flammabilityChanceCurve: flammabilityChanceCurve, overrideCells: overrideCells); - } - - // Main explosion - GenExplosion.DoExplosion(center, map, coneRange, damType, instigator, damAmount, armorPenetration, explosionSound, weapon, projectile, intendedTarget, postExplosionSpawnThingDef, postExplosionSpawnChance, postExplosionSpawnThingCount, postExplosionGasType, postExplosionGasRadiusOverride, postExplosionGasAmount, applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef, preExplosionSpawnChance, preExplosionSpawnThingCount, chanceToStartFire, damageFalloff, direction, ignoredThings, initialAngleRange, showConeEffect, propagationSpeed, excludeRadius, showConeEffect, postExplosionSpawnThingDefWater, screenShakeFactor, flammabilityChanceCurve, overrideCells); - } - - if (fragment != null) - { - FloatRange currentFragmentRange = fragmentRange.HasValue ? fragmentRange.Value : new FloatRange(0f, coneRange); - IEnumerable source = FragmentCells(center, initialAngleRange, currentFragmentRange); - for (int j = 0; j < fragmentCount; j++) - { - IntVec3 intVec = source.RandomElement(); - ((Projectile)GenSpawn.Spawn(fragment, center, map)).Launch(instigator, intVec, intVec, ProjectileHitFlags.All); - } - } - } - - private IEnumerable FragmentCells(IntVec3 center, FloatRange? angle, FloatRange range) - { - int minRadialCells = GenRadial.NumCellsInRadius(range.min); - int maxRadialCells = GenRadial.NumCellsInRadius(range.max); - - for (int i = minRadialCells; i < maxRadialCells; i++) - { - IntVec3 currentCell = center + GenRadial.RadialPattern[i]; - - if (angle.HasValue) - { - float angleMin = angle.Value.min; - float angleMax = angle.Value.max; - float lengthHorizontal = (currentCell - center).LengthHorizontal; - - if (lengthHorizontal <= 0.5f) // Close to center, always include - { - yield return currentCell; - continue; - } - - float cellAngle = Mathf.Atan2(-(currentCell.z - center.z), currentCell.x - center.x) * 57.29578f; // Convert radians to degrees - - // Handle angle wrap-around for comparison - if (angleMin < 0f && cellAngle - angleMin > 360f) - { - cellAngle -= 360f; - } - if (angleMax > 360f && angleMax - cellAngle < 360f) - { - cellAngle += 360f; - } - - // Check if cell is within the angular range - if (cellAngle >= angleMin && cellAngle <= angleMax) - { - yield return currentCell; - } - } - else - { - yield return currentCell; // No angle restriction - } - } - } - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs b/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs index eeddb204..c742e789 100644 --- a/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs +++ b/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs @@ -60,6 +60,9 @@ namespace WulaFallenEmpire this.landed = true; this.ticksToDetonation = ExplosiveDef.explosionDelay; // Use ExplosiveDef for explosionDelay GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, ExplosiveDef.damageDef ?? DamageDefOf.Bomb, this.launcher.Faction, this.launcher); // Use ExplosiveDef for damageDef + // 停止追踪并清空速度,确保子弹停止移动 + this.homing = false; + this.curSpeed = Vector3.zero; } } @@ -140,7 +143,7 @@ namespace WulaFallenEmpire bool doExplosionVFX = ExplosiveDef.doExplosionVFX; // Use ExplosiveDef for doExplosionVFX GenExplosion.DoExplosion( - center: position, // 爆炸中心 + center: ExactPosition.ToIntVec3(), // 爆炸中心 map: map, // 地图 radius: explosionRadius, // 爆炸半径 damType: damageDef, // 伤害类型 diff --git a/Source/WulaFallenEmpire/Projectile_ExplosiveWithTrail.cs b/Source/WulaFallenEmpire/Projectile_ExplosiveWithTrail.cs new file mode 100644 index 00000000..4fb54d4a --- /dev/null +++ b/Source/WulaFallenEmpire/Projectile_ExplosiveWithTrail.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Reflection; +using RimWorld; +using UnityEngine; +using Verse; +using Verse.AI; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class Projectile_ExplosiveWithTrail : Projectile_Explosive + { + 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; + } + + public override void ExposeData() + { + base.ExposeData(); + 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(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_Homing.cs b/Source/WulaFallenEmpire/Projectile_Homing.cs deleted file mode 100644 index fbf42bcd..00000000 --- a/Source/WulaFallenEmpire/Projectile_Homing.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System.Collections.Generic; -using System.Reflection; -using RimWorld; -using UnityEngine; -using Verse; -using Verse.AI; -using Verse.Sound; - -namespace WulaFallenEmpire -{ - public class Projectile_Homing : Bullet - { - private HomingProjectileDef homingDefInt; - - private Sustainer ambientSustainer; - - private List comps; - - protected Vector3 exactPositionInt; - - public Vector3 curSpeed; - - public bool homing = true; - private int Fleck_MakeFleckTick; // 拖尾特效的计时器 - private Vector3 lastTickPosition; // 记录上一帧的位置,用于计算移动方向 - - private static class NonPublicFields - { - public static FieldInfo Projectile_AmbientSustainer = typeof(Projectile).GetField("ambientSustainer", BindingFlags.Instance | BindingFlags.NonPublic); - public static FieldInfo ThingWithComps_comps = typeof(ThingWithComps).GetField("comps", BindingFlags.Instance | BindingFlags.NonPublic); - public static MethodInfo ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic); - } - - public HomingProjectileDef HomingDef - { - get - { - if (homingDefInt == null) - { - homingDefInt = def.GetModExtension(); - if (homingDefInt == null) - { - Log.ErrorOnce($"HomingProjectileDef for {this.def.defName} is null. Creating a default instance.", this.thingIDNumber ^ 0x12345678); - this.homingDefInt = new HomingProjectileDef(); - } - } - return homingDefInt; - } - } - - public override Vector3 ExactPosition => exactPositionInt; - - public override Quaternion ExactRotation => Quaternion.LookRotation(curSpeed); - - public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null) - { - bool flag = false; - if (usedTarget.HasThing && usedTarget.Thing is IAttackTarget) - { - if (Rand.Chance(GetHitChance(usedTarget.Thing))) - { - hitFlags |= ProjectileHitFlags.IntendedTarget; - intendedTarget = usedTarget; - flag = true; - } - } - else if (Rand.Chance(GetHitChance(intendedTarget.Thing))) - { - hitFlags |= ProjectileHitFlags.IntendedTarget; - usedTarget = intendedTarget; - flag = true; - } - if (flag) - { - hitFlags &= ~ProjectileHitFlags.IntendedTarget; - } - base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef); - exactPositionInt = origin.Yto0() + Vector3.up * def.Altitude; - lastTickPosition = origin; // 初始化 lastTickPosition - Vector3 normalized = (destination - origin).Yto0().normalized; - float degrees = Rand.Range(0f - HomingDef.initRotateAngle, HomingDef.initRotateAngle); - Vector2 v = new Vector2(normalized.x, normalized.z); - v = v.RotatedBy(degrees); - Vector3 vector = new Vector3(v.x, 0f, v.y); - // 检查 HomingDef.speedRangeOverride 是否有值 - if (!HomingDef.speedRangeOverride.HasValue) - { - curSpeed = vector * def.projectile.SpeedTilesPerTick; - } - else - { - curSpeed = vector * HomingDef.SpeedRangeTilesPerTickOverride.RandomInRange; - } - ReflectInit(); - } - - protected void ReflectInit() - { - if (!def.projectile.soundAmbient.NullOrUndefined()) - { - ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this); - } - comps = (List)NonPublicFields.ThingWithComps_comps.GetValue(this); - } - - public float GetHitChance(Thing thing) - { - if (this.HomingDef == null) - { - Log.ErrorOnce("HomingDef is null for projectile " + this.def.defName + ". Returning default hitChance.", this.thingIDNumber ^ 0x12345678); - return 0.7f; - } - - float hitChance = HomingDef.hitChance; - if (thing == null) - { - return hitChance; - } - if (thing is Pawn pawn) - { - hitChance *= Mathf.Clamp(pawn.BodySize, 0.5f, 1.5f); - if (pawn.GetPosture() != 0) - { - hitChance *= 0.5f; - } - float num = 1f; - switch (equipmentQuality) - { - case QualityCategory.Awful: - num = 0.5f; - break; - case QualityCategory.Poor: - num = 0.75f; - break; - case QualityCategory.Normal: - num = 1f; - break; - case QualityCategory.Excellent: - num = 1.1f; - break; - case QualityCategory.Masterwork: - num = 1.2f; - break; - case QualityCategory.Legendary: - num = 1.3f; - break; - default: - Log.Message("Unknown QualityCategory, returning default qualityFactor = 1"); - break; - } - hitChance *= num; - } - else - { - hitChance *= 1.5f * thing.def.fillPercent; - } - return Mathf.Clamp(hitChance, 0f, 1f); - } - - public virtual void MovementTick() - { - Vector3 vect = ExactPosition + curSpeed; - ShootLine shootLine = new ShootLine(ExactPosition.ToIntVec3(), vect.ToIntVec3()); - Vector3 vector = (intendedTarget.Cell.ToVector3() - ExactPosition).Yto0(); - if (homing) - { - Vector3 vector2 = vector.normalized - curSpeed.normalized; - if (vector2.sqrMagnitude >= 1.414f) - { - homing = false; - lifetime = HomingDef.destroyTicksAfterLosingTrack.RandomInRange; - ticksToImpact = lifetime; - base.HitFlags &= ~ProjectileHitFlags.IntendedTarget; - base.HitFlags |= ProjectileHitFlags.NonTargetPawns; - base.HitFlags |= ProjectileHitFlags.NonTargetWorld; - } - else - { - curSpeed += vector2 * HomingDef.homingSpeed * curSpeed.magnitude; - } - } - foreach (IntVec3 item in shootLine.Points()) - { - if (!((intendedTarget.Cell - item).SqrMagnitude <= HomingDef.proximityFuseRange * HomingDef.proximityFuseRange)) - { - continue; - } - homing = false; - lifetime = HomingDef.destroyTicksAfterLosingTrack.RandomInRange; - if ((base.HitFlags & ProjectileHitFlags.IntendedTarget) == ProjectileHitFlags.IntendedTarget || HomingDef.proximityFuseRange > 0f) - { - lifetime = 0; - ticksToImpact = 0; - vect = item.ToVector3(); - if (Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && def.projectile.soundImpactAnticipate != null) - { - def.projectile.soundImpactAnticipate.PlayOneShot(this); - } - } - } - exactPositionInt = vect; - curSpeed *= (curSpeed.magnitude + HomingDef.SpeedChangeTilesPerTickOverride) / curSpeed.magnitude; - } - - protected override void Tick() - { - ThingWithCompsTick(); - lifetime--; - - if (lifetime <= 0) - { - Destroy(); - return; - } - - // 处理拖尾特效 - if (HomingDef != null && HomingDef.tailFleckDef != null) - { - Fleck_MakeFleckTick++; - if (Fleck_MakeFleckTick >= HomingDef.fleckMakeFleckTickMax) - { - Fleck_MakeFleckTick = 0; - Map map = base.Map; - int randomInRange = HomingDef.fleckMakeFleckNum.RandomInRange; - Vector3 currentPosition = ExactPosition; - Vector3 previousPosition = lastTickPosition; - - for (int i = 0; i < randomInRange; i++) - { - float num = (currentPosition - previousPosition).AngleFlat(); - float velocityAngle = HomingDef.fleckAngle.RandomInRange + num; - float randomInRange2 = HomingDef.fleckScale.RandomInRange; - float randomInRange3 = HomingDef.fleckSpeed.RandomInRange; - - FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, HomingDef.tailFleckDef, randomInRange2); - dataStatic.rotation = (currentPosition - previousPosition).AngleFlat(); - dataStatic.rotationRate = HomingDef.fleckRotation.RandomInRange; - dataStatic.velocityAngle = velocityAngle; - dataStatic.velocitySpeed = randomInRange3; - map.flecks.CreateFleck(dataStatic); - } - } - } - lastTickPosition = ExactPosition; // 更新上一帧位置 - - // 移除 if (landed) return; 以确保子弹落地后也能正常销毁 - Vector3 exactPosition = ExactPosition; - ticksToImpact--; - MovementTick(); - if (!ExactPosition.InBounds(base.Map)) - { - base.Position = exactPosition.ToIntVec3(); - Destroy(); - return; - } - Vector3 exactPosition2 = ExactPosition; - object[] parameters = new object[2] { exactPosition, exactPosition2 }; - if (!(bool)NonPublicFields.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters)) - { - base.Position = ExactPosition.ToIntVec3(); - if (ticksToImpact == 60 && Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && def.projectile.soundImpactAnticipate != null) - { - def.projectile.soundImpactAnticipate.PlayOneShot(this); - } - if (ticksToImpact <= 0) - { - ImpactSomething(); - } - else if (ambientSustainer != null) - { - ambientSustainer.Maintain(); - } - } - } - - private void ThingWithCompsTick() - { - if (comps != null) - { - int i = 0; - for (int count = comps.Count; i < count; i++) - { - comps[i].CompTick(); - } - } - } - - protected override void Impact(Thing hitThing, bool blockedByShield = false) - { - Map map = base.Map; - IntVec3 position = base.Position; - base.Impact(hitThing, blockedByShield); - if (HomingDef.extraProjectile != null) - { - if (hitThing != null && hitThing.Spawned) - { - ((Projectile)GenSpawn.Spawn(HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(launcher, ExactPosition, hitThing, hitThing, ProjectileHitFlags.All, false, null, null); - } - else - { - ((Projectile)GenSpawn.Spawn(HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(launcher, ExactPosition, position, position, ProjectileHitFlags.All, false, null, null); - } - } - } - - public override void ExposeData() - { - base.ExposeData(); - Scribe_Values.Look(ref exactPositionInt, "exactPosition"); - Scribe_Values.Look(ref curSpeed, "curSpeed"); - Scribe_Values.Look(ref homing, "homing", defaultValue: false); - if (Scribe.mode == LoadSaveMode.PostLoadInit) - { - ReflectInit(); - if (this.homingDefInt == null) - { - this.homingDefInt = this.def.GetModExtension(); - if (this.homingDefInt == null) - { - Log.ErrorOnce($"HomingProjectileDef is null for projectile {this.def.defName} after PostLoadInit. Creating a default instance.", this.thingIDNumber ^ 0x12345678); - this.homingDefInt = new HomingProjectileDef(); - } - } - } - } - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs b/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs deleted file mode 100644 index 093bfa8e..00000000 --- a/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using UnityEngine; -using Verse; - -namespace WulaFallenEmpire -{ - public class Projectile_Homing_Explosive : Projectile_Homing - { - public override void ExposeData() - { - base.ExposeData(); - Scribe_Values.Look(ref this.ticksToDetonation, "ticksToDetonation", 0, false); - } - - protected override void Tick() - { - base.Tick(); - bool flag = this.ticksToDetonation > 0; - if (flag) - { - this.ticksToDetonation--; - bool flag2 = this.ticksToDetonation <= 0; - if (flag2) - { - this.Explode(); - } - } - } - - protected override void Impact(Thing hitThing, bool blockedByShield = false) - { - bool flag = blockedByShield || this.def.projectile.explosionDelay == 0; - if (flag) - { - this.Explode(); - } - else - { - this.landed = true; - this.ticksToDetonation = this.def.projectile.explosionDelay; - GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, this.def.projectile.damageDef, this.launcher.Faction, this.launcher); - } - } - - protected virtual void Explode() - { - Map map = base.Map; - ModExtension_Cone modExtension = this.def.GetModExtension(); - this.DoExplosion(); - bool flag = modExtension != null; - if (flag) - { - ProjectileProperties projectile = this.def.projectile; - ModExtension_Cone modExtension_Cone = modExtension; - IntVec3 position = base.Position; - Map map2 = map; - Quaternion exactRotation = this.ExactRotation; - DamageDef damageDef = projectile.damageDef; - Thing launcher = base.Launcher; - int damageAmount = this.DamageAmount; - float armorPenetration = this.ArmorPenetration; - SoundDef soundExplode = this.def.projectile.soundExplode; - ThingDef equipmentDef = this.equipmentDef; - ThingDef def = this.def; - Thing thing = this.intendedTarget.Thing; - ThingDef postExplosionSpawnThingDef = null; - float postExplosionSpawnChance = 0f; - int postExplosionSpawnThingCount = 1; - float screenShakeFactor = this.def.projectile.screenShakeFactor; - modExtension_Cone.DoConeExplosion(position, map2, exactRotation, damageDef, launcher, damageAmount, armorPenetration, soundExplode, equipmentDef, def, thing, postExplosionSpawnThingDef, postExplosionSpawnChance, postExplosionSpawnThingCount, null, null, 255, false, null, 0f, 1, 0f, false, null, null, 1f, 0f, null, screenShakeFactor, null, null); - } - bool flag2 = this.def.projectile.explosionEffect != null; - if (flag2) - { - Effecter effecter = this.def.projectile.explosionEffect.Spawn(); - bool flag3 = this.def.projectile.explosionEffectLifetimeTicks != 0; - if (flag3) - { - map.effecterMaintainer.AddEffecterToMaintain(effecter, base.Position.ToVector3().ToIntVec3(), this.def.projectile.explosionEffectLifetimeTicks); - } - else - { - effecter.Trigger(new TargetInfo(base.Position, map, false), new TargetInfo(base.Position, map, false), -1); - effecter.Cleanup(); - } - } - this.Destroy(DestroyMode.Vanish); - } - - protected void DoExplosion() - { - IntVec3 position = base.Position; - float explosionRadius = this.def.projectile.explosionRadius; - DamageDef damageDef = this.def.projectile.damageDef; - Thing launcher = this.launcher; - int damageAmount = this.DamageAmount; - float armorPenetration = this.ArmorPenetration; - SoundDef soundExplode = this.def.projectile.soundExplode; - ThingDef equipmentDef = this.equipmentDef; - ThingDef def = this.def; - Thing thing = this.intendedTarget.Thing; - ThingDef thingDef = this.def.projectile.postExplosionSpawnThingDef ?? this.def.projectile.filth; - ThingDef postExplosionSpawnThingDefWater = this.def.projectile.postExplosionSpawnThingDefWater; - float postExplosionSpawnChance = this.def.projectile.postExplosionSpawnChance; - int postExplosionSpawnThingCount = this.def.projectile.postExplosionSpawnThingCount; - GasType? postExplosionGasType = this.def.projectile.postExplosionGasType; - ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; - float preExplosionSpawnChance = this.def.projectile.preExplosionSpawnChance; - int preExplosionSpawnThingCount = this.def.projectile.preExplosionSpawnThingCount; - bool applyDamageToExplosionCellsNeighbors = this.def.projectile.applyDamageToExplosionCellsNeighbors; - ThingDef preExplosionSpawnThingDef2 = preExplosionSpawnThingDef; - float preExplosionSpawnChance2 = preExplosionSpawnChance; - int preExplosionSpawnThingCount2 = preExplosionSpawnThingCount; - float explosionChanceToStartFire = this.def.projectile.explosionChanceToStartFire; - bool explosionDamageFalloff = this.def.projectile.explosionDamageFalloff; - float? direction = new float?(this.origin.AngleToFlat(this.destination)); - FloatRange? affectedAngle = null; - float expolosionPropagationSpeed = this.def.projectile.damageDef.expolosionPropagationSpeed; - float screenShakeFactor = this.def.projectile.screenShakeFactor; - IntVec3 center = position; - Map map = base.Map; - float radius = explosionRadius; - DamageDef damType = damageDef; - Thing instigator = launcher; - int damAmount = damageAmount; - float armorPenetration2 = armorPenetration; - SoundDef explosionSound = soundExplode; - ThingDef weapon = equipmentDef; - ThingDef projectile = def; - Thing intendedTarget = thing; - ThingDef postExplosionSpawnThingDef = thingDef; - float postExplosionSpawnChance2 = postExplosionSpawnChance; - int postExplosionSpawnThingCount2 = postExplosionSpawnThingCount; - GasType? postExplosionGasType2 = postExplosionGasType; - bool doExplosionVFX = this.def.projectile.doExplosionVFX; - ThingDef postExplosionSpawnThingDefWater2 = postExplosionSpawnThingDefWater; - GenExplosion.DoExplosion(center, map, radius, damType, instigator, damAmount, armorPenetration2, explosionSound, weapon, projectile, intendedTarget, postExplosionSpawnThingDef, postExplosionSpawnChance2, postExplosionSpawnThingCount2, postExplosionGasType2, null, 255, applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef2, preExplosionSpawnChance2, preExplosionSpawnThingCount2, explosionChanceToStartFire, explosionDamageFalloff, direction, null, affectedAngle, doExplosionVFX, expolosionPropagationSpeed, 0f, true, postExplosionSpawnThingDefWater2, screenShakeFactor, null, null, null, null); - } - - private int ticksToDetonation; - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_PoiBullet.cs b/Source/WulaFallenEmpire/Projectile_PoiBullet.cs deleted file mode 100644 index d62e8452..00000000 --- a/Source/WulaFallenEmpire/Projectile_PoiBullet.cs +++ /dev/null @@ -1,726 +0,0 @@ -using System; -using System.Collections.Generic; -using RimWorld; -using UnityEngine; -using Verse; -using Verse.Sound; -using System.Reflection; -using Verse.AI; - -namespace WulaFallenEmpire -{ - public class Projectile_PoiBullet : Bullet - { - // Projectile_Homing 的字段 - private HomingProjectileDef homingDefInt; - private Sustainer ambientSustainer; - private List comps; - protected Vector3 exactPositionInt; - public Vector3 curSpeed; - public bool homing = true; - private int Fleck_MakeFleckTick; - private Vector3 lastTickPosition; - - // Projectile_Homing_Explosive 的字段 - private int ticksToDetonation; - - private static class NonPublicFields - { - public static FieldInfo Projectile_AmbientSustainer = typeof(Projectile).GetField("ambientSustainer", BindingFlags.Instance | BindingFlags.NonPublic); - public static FieldInfo ThingWithComps_comps = typeof(ThingWithComps).GetField("comps", BindingFlags.Instance | BindingFlags.NonPublic); - public static MethodInfo ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic); - } - - public HomingProjectileDef HomingDef - { - get - { - if (homingDefInt == null) - { - homingDefInt = def.GetModExtension(); - if (homingDefInt == null) - { - Log.ErrorOnce($"HomingProjectileDef for {this.def.defName} is null. Creating a default instance.", this.thingIDNumber ^ 0x12345678); - this.homingDefInt = new HomingProjectileDef(); - } - } - return homingDefInt; - } - } - - public override Vector3 ExactPosition => exactPositionInt; - - public override Quaternion ExactRotation => Quaternion.LookRotation(curSpeed); - - public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null) - { - bool flag = false; - if (usedTarget.HasThing && usedTarget.Thing is IAttackTarget) - { - if (Rand.Chance(GetHitChance(usedTarget.Thing))) - { - hitFlags |= ProjectileHitFlags.IntendedTarget; - intendedTarget = usedTarget; - flag = true; - } - } - else if (Rand.Chance(GetHitChance(intendedTarget.Thing))) - { - hitFlags |= ProjectileHitFlags.IntendedTarget; - usedTarget = intendedTarget; - flag = true; - } - if (flag) - { - hitFlags &= ~ProjectileHitFlags.IntendedTarget; - } - base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef); - exactPositionInt = origin.Yto0() + Vector3.up * def.Altitude; - lastTickPosition = origin; - Vector3 normalized = (destination - origin).Yto0().normalized; - float degrees = Rand.Range(0f - HomingDef.initRotateAngle, HomingDef.initRotateAngle); - Vector2 v = new Vector2(normalized.x, normalized.z); - v = v.RotatedBy(degrees); - Vector3 vector = new Vector3(v.x, 0f, v.y); - if (!HomingDef.speedRangeOverride.HasValue) - { - curSpeed = vector * def.projectile.SpeedTilesPerTick; - } - else - { - curSpeed = vector * HomingDef.SpeedRangeTilesPerTickOverride.RandomInRange; - } - ReflectInit(); - - // Projectile_PoiBullet 原始逻辑中的部分初始化 - this.flag2 = false; // 重置RandFactor的标志 - this.flag3 = true; // 重置CanHitTarget的标志 - this.CalHit = false; // 重置命中计算结果 - } - - protected void ReflectInit() - { - if (!def.projectile.soundAmbient.NullOrUndefined()) - { - ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this); - } - comps = (List)NonPublicFields.ThingWithComps_comps.GetValue(this); - } - - public float GetHitChance(Thing thing) - { - if (this.HomingDef == null) - { - Log.ErrorOnce("HomingDef is null for projectile " + this.def.defName + ". Returning default hitChance.", this.thingIDNumber ^ 0x12345678); - return 0.7f; - } - - float hitChance = HomingDef.hitChance; - if (thing == null) - { - return hitChance; - } - if (thing is Pawn pawn) - { - hitChance *= Mathf.Clamp(pawn.BodySize, 0.5f, 1.5f); - if (pawn.GetPosture() != 0) - { - hitChance *= 0.5f; - } - float num = 1f; - switch (equipmentQuality) - { - case QualityCategory.Awful: - num = 0.5f; - break; - case QualityCategory.Poor: - num = 0.75f; - break; - case QualityCategory.Normal: - num = 1f; - break; - case QualityCategory.Excellent: - num = 1.1f; - break; - case QualityCategory.Masterwork: - num = 1.2f; - break; - case QualityCategory.Legendary: - num = 1.3f; - break; - default: - Log.Message("Unknown QualityCategory, returning default qualityFactor = 1"); - break; - } - hitChance *= num; - } - else - { - hitChance *= 1.5f * thing.def.fillPercent; - } - return Mathf.Clamp(hitChance, 0f, 1f); - } - - public virtual void MovementTick() - { - Vector3 vect = ExactPosition + curSpeed; - ShootLine shootLine = new ShootLine(ExactPosition.ToIntVec3(), vect.ToIntVec3()); - Vector3 vector = (intendedTarget.Cell.ToVector3() - ExactPosition).Yto0(); - if (homing) - { - Vector3 vector2 = vector.normalized - curSpeed.normalized; - if (vector2.sqrMagnitude >= 1.414f) - { - homing = false; - lifetime = HomingDef.destroyTicksAfterLosingTrack.RandomInRange; - ticksToImpact = lifetime; - base.HitFlags &= ~ProjectileHitFlags.IntendedTarget; - base.HitFlags |= ProjectileHitFlags.NonTargetPawns; - base.HitFlags |= ProjectileHitFlags.NonTargetWorld; - } - else - { - curSpeed += vector2 * HomingDef.homingSpeed * curSpeed.magnitude; - } - } - foreach (IntVec3 item in shootLine.Points()) - { - if (!((intendedTarget.Cell - item).SqrMagnitude <= HomingDef.proximityFuseRange * HomingDef.proximityFuseRange)) - { - continue; - } - homing = false; - lifetime = HomingDef.destroyTicksAfterLosingTrack.RandomInRange; - if ((base.HitFlags & ProjectileHitFlags.IntendedTarget) == ProjectileHitFlags.IntendedTarget || HomingDef.proximityFuseRange > 0f) - { - lifetime = 0; - ticksToImpact = 0; - vect = item.ToVector3(); - if (Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && def.projectile.soundImpactAnticipate != null) - { - def.projectile.soundImpactAnticipate.PlayOneShot(this); - } - } - } - exactPositionInt = vect; - curSpeed *= (curSpeed.magnitude + HomingDef.SpeedChangeTilesPerTickOverride) / curSpeed.magnitude; - } - - protected override void Tick() - { - // Projectile_Homing 的 Tick 逻辑 - ThingWithCompsTick(); - lifetime--; - - if (lifetime <= 0) - { - Destroy(); - return; - } - - // 处理拖尾特效 - if (HomingDef != null && HomingDef.tailFleckDef != null) - { - Fleck_MakeFleckTick++; - if (Fleck_MakeFleckTick >= HomingDef.fleckMakeFleckTickMax) - { - Fleck_MakeFleckTick = 0; - Map map = base.Map; - int randomInRange = HomingDef.fleckMakeFleckNum.RandomInRange; - Vector3 currentPosition = ExactPosition; - Vector3 previousPosition = lastTickPosition; - - for (int i = 0; i < randomInRange; i++) - { - float num = (currentPosition - previousPosition).AngleFlat(); - float velocityAngle = HomingDef.fleckAngle.RandomInRange + num; - float randomInRange2 = HomingDef.fleckScale.RandomInRange; - float randomInRange3 = HomingDef.fleckSpeed.RandomInRange; - - FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, HomingDef.tailFleckDef, randomInRange2); - dataStatic.rotation = (currentPosition - previousPosition).AngleFlat(); - dataStatic.rotationRate = HomingDef.fleckRotation.RandomInRange; - dataStatic.velocityAngle = velocityAngle; - dataStatic.velocitySpeed = randomInRange3; - map.flecks.CreateFleck(dataStatic); - } - } - } - lastTickPosition = ExactPosition; - - // Projectile_Homing_Explosive 的 Tick 逻辑 - if (HomingDef.isExplosive && HomingDef.explosionDelay > 0) - { - if (ticksToDetonation > 0) - { - ticksToDetonation--; - if (ticksToDetonation <= 0) - { - Explode(); - } - } - } - - Vector3 exactPosition = ExactPosition; - ticksToImpact--; - MovementTick(); - if (!ExactPosition.InBounds(base.Map)) - { - base.Position = exactPosition.ToIntVec3(); - Destroy(); - return; - } - Vector3 exactPosition2 = ExactPosition; - object[] parameters = new object[2] { exactPosition, exactPosition2 }; - if (!(bool)NonPublicFields.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters)) - { - base.Position = ExactPosition.ToIntVec3(); - if (ticksToImpact == 60 && Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && def.projectile.soundImpactAnticipate != null) - { - def.projectile.soundImpactAnticipate.PlayOneShot(this); - } - if (ticksToImpact <= 0) - { - ImpactSomething(); - } - else if (ambientSustainer != null) - { - ambientSustainer.Maintain(); - } - } - - // Projectile_PoiBullet 原始逻辑中的部分Tick - this.tickcount++; - bool flag = this.flag3; - if (flag) - { - this.CalHit = this.CanHitTarget_Poi(); // 使用重命名后的方法 - this.flag3 = false; - } - bool flag2 = !this.CalHit; - if (flag2) - { - this.FindRandCell(this.intendedTarget.CenterVector3); - } - bool flag3_poi = this.intendedTarget.Thing != null; - if (flag3_poi) - { - this.destination = this.intendedTarget.Thing.DrawPos; - } - this.Fleck_MakeFleckTick_Poi++; // 使用重命名后的字段 - bool flag4 = this.Fleck_MakeFleckTick_Poi >= this.Fleck_MakeFleckTickMax_Poi; // 使用重命名后的字段 - bool flag5 = flag4 && this.tickcount >= 8; - if (flag5) - { - this.Fleck_MakeFleckTick_Poi = 0; - Map map = base.Map; - int randomInRange = this.Fleck_MakeFleckNum_Poi.RandomInRange; - Vector3 vector = this.BPos(base.DistanceCoveredFraction - 0.01f); - Vector3 vector2 = this.BPos(base.DistanceCoveredFraction - 0.02f); - for (int i = 0; i < randomInRange; i++) - { - float num = (vector - this.intendedTarget.CenterVector3).AngleFlat(); - float velocityAngle = this.Fleck_Angle_Poi.RandomInRange + num; - float randomInRange2 = this.Fleck_Scale_Poi.RandomInRange; - float randomInRange3 = this.Fleck_Speed_Poi.RandomInRange; - float randomInRange4 = this.Fleck_Speed2_Poi.RandomInRange; - FleckCreationData dataStatic = FleckMaker.GetDataStatic(vector, map, this.FleckDef_Poi, randomInRange2); - FleckCreationData dataStatic2 = FleckMaker.GetDataStatic(vector2, map, this.FleckDef2_Poi, randomInRange2); - dataStatic.rotation = (vector - vector2).AngleFlat(); - dataStatic.rotationRate = this.Fleck_Rotation_Poi.RandomInRange; - dataStatic.velocityAngle = velocityAngle; - dataStatic.velocitySpeed = randomInRange3; - dataStatic2.rotation = (vector - vector2).AngleFlat(); - dataStatic2.rotationRate = this.Fleck_Rotation_Poi.RandomInRange; - dataStatic2.velocityAngle = velocityAngle; - dataStatic2.velocitySpeed = randomInRange4; - map.flecks.CreateFleck(dataStatic2); - map.flecks.CreateFleck(dataStatic); - } - } - // 移除原始的 base.Tick(); 因为 Projectile_Homing 的 Tick 已经包含了其父类的逻辑 - } - - private void ThingWithCompsTick() - { - if (comps != null) - { - int i = 0; - for (int count = comps.Count; i < count; i++) - { - comps[i].CompTick(); - } - } - } - - protected override void Impact(Thing hitThing, bool blockedByShield = false) - { - Map map = base.Map; - IntVec3 position = base.Position; - - // Projectile_Homing_Explosive 的 Impact 逻辑 - if (HomingDef.isExplosive) - { - bool flag = blockedByShield || HomingDef.explosionDelay == 0; - if (flag) - { - Explode(); - } - else - { - landed = true; - ticksToDetonation = HomingDef.explosionDelay; - GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, def.projectile.damageDef, launcher.Faction, launcher); - } - } - else // Projectile_Homing 的 Impact 逻辑 - { - base.Impact(hitThing, blockedByShield); - if (HomingDef.extraProjectile != null) - { - if (hitThing != null && hitThing.Spawned) - { - ((Projectile)GenSpawn.Spawn(HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(launcher, ExactPosition, hitThing, hitThing, ProjectileHitFlags.All, false, null, null); - } - else - { - ((Projectile)GenSpawn.Spawn(HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(launcher, ExactPosition, position, position, ProjectileHitFlags.All, false, null, null); - } - } - } - - // Projectile_PoiBullet 原始逻辑中的 Impact - bool flag_poi = this.intendedTarget.Thing is Pawn; - if (flag_poi) - { - hitThing = this.intendedTarget.Thing; - } - // 原始的 base.Impact(hitThing, blockedByShield); 已经被上面的 Homing 和 Explosive 逻辑覆盖,需要确保正确调用或移除 - // 这里我们已经调用了 base.Impact(hitThing, blockedByShield); 在 Projectile_Homing 的 Impact 逻辑中,所以这里不再重复调用。 - - BattleLogEntry_RangedImpact battleLogEntry_RangedImpact = new BattleLogEntry_RangedImpact(this.launcher, hitThing, this.intendedTarget.Thing, this.equipmentDef, this.def, this.targetCoverDef); - Find.BattleLog.Add(battleLogEntry_RangedImpact); - this.NotifyImpact_Poi(hitThing, map, position); // 使用重命名后的方法 - bool flag2 = hitThing != null && !blockedByShield; - if (flag2) - { - Pawn pawn; - bool instigatorGuilty = (pawn = (this.launcher as Pawn)) == null || !pawn.Drafted; - 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, instigatorGuilty, true, QualityCategory.Normal, true); - hitThing.TakeDamage(dinfo).AssociateWithLog(battleLogEntry_RangedImpact); - Pawn pawn2 = hitThing as Pawn; - bool flag3 = pawn2 != null && pawn2.stances != null; - if (flag3) - { - pawn2.stances.stagger.Notify_BulletImpact(this); - } - bool flag4 = this.def.projectile.extraDamages != null; - if (flag4) - { - foreach (ExtraDamage extraDamage in this.def.projectile.extraDamages) - { - bool flag5 = Rand.Chance(extraDamage.chance); - if (flag5) - { - DamageInfo dinfo2 = new DamageInfo(extraDamage.def, extraDamage.amount, extraDamage.AdjustedArmorPenetration(), this.ExactRotation.eulerAngles.y, this.launcher, null, this.equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, this.intendedTarget.Thing, instigatorGuilty, true, QualityCategory.Normal, true); - hitThing.TakeDamage(dinfo2).AssociateWithLog(battleLogEntry_RangedImpact); - } - } - } - bool flag6 = Rand.Chance(this.def.projectile.bulletChanceToStartFire) && (pawn2 == null || Rand.Chance(FireUtility.ChanceToAttachFireFromEvent(pawn2))); - if (flag6) - { - hitThing.TryAttachFire(this.def.projectile.bulletFireSizeRange.RandomInRange, this); - } - } - else - { - bool flag7 = !blockedByShield; - if (flag7) - { - SoundDefOf.BulletImpact_Ground.PlayOneShot(new TargetInfo(base.Position, map, false)); - bool takeSplashes = base.Position.GetTerrain(map).takeSplashes; - if (takeSplashes) - { - FleckMaker.WaterSplash(this.ExactPosition, map, Mathf.Sqrt((float)this.DamageAmount) * 1f, 4f); - } - else - { - FleckMaker.Static(this.ExactPosition, map, FleckDefOf.ShotHit_Dirt, 1f); - } - } - bool flag8 = Rand.Chance(this.def.projectile.bulletChanceToStartFire); - if (flag8) - { - FireUtility.TryStartFireIn(base.Position, map, this.def.projectile.bulletFireSizeRange.RandomInRange, this, null); - } - } - } - - protected virtual void Explode() - { - Map map = base.Map; - ModExtension_Cone modExtension = this.def.GetModExtension(); - DoExplosion(); - if (modExtension != null) - { - ProjectileProperties projectile = this.def.projectile; - ModExtension_Cone modExtension_Cone = modExtension; - IntVec3 position = base.Position; - Map map2 = map; - Quaternion exactRotation = this.ExactRotation; - DamageDef damageDef = projectile.damageDef; - Thing launcher = base.Launcher; - int damageAmount = this.DamageAmount; - float armorPenetration = this.ArmorPenetration; - SoundDef soundExplode = this.def.projectile.soundExplode; - ThingDef equipmentDef = this.equipmentDef; - ThingDef def = this.def; - Thing thing = this.intendedTarget.Thing; - ThingDef postExplosionSpawnThingDef = null; - float postExplosionSpawnChance = 0f; - int postExplosionSpawnThingCount = 1; - float screenShakeFactor = this.def.projectile.screenShakeFactor; - modExtension_Cone.DoConeExplosion(position, map2, exactRotation, damageDef, launcher, damageAmount, armorPenetration, soundExplode, equipmentDef, def, thing, postExplosionSpawnThingDef, postExplosionSpawnChance, postExplosionSpawnThingCount, null, null, 255, false, null, 0f, 1, 0f, false, null, null, 1f, 0f, null, screenShakeFactor, null, null); - } - if (this.def.projectile.explosionEffect != null) - { - Effecter effecter = this.def.projectile.explosionEffect.Spawn(); - if (this.def.projectile.explosionEffectLifetimeTicks != 0) - { - map.effecterMaintainer.AddEffecterToMaintain(effecter, base.Position.ToVector3().ToIntVec3(), this.def.projectile.explosionEffectLifetimeTicks); - } - else - { - effecter.Trigger(new TargetInfo(base.Position, map, false), new TargetInfo(base.Position, map, false), -1); - effecter.Cleanup(); - } - } - Destroy(DestroyMode.Vanish); - } - - protected void DoExplosion() - { - IntVec3 position = base.Position; - float explosionRadius = this.def.projectile.explosionRadius; - DamageDef damageDef = this.def.projectile.damageDef; - Thing launcher = this.launcher; - int damageAmount = this.DamageAmount; - float armorPenetration = this.ArmorPenetration; - SoundDef soundExplode = this.def.projectile.soundExplode; - ThingDef equipmentDef = this.equipmentDef; - ThingDef def = this.def; - Thing thing = this.intendedTarget.Thing; - ThingDef thingDef = this.def.projectile.postExplosionSpawnThingDef ?? this.def.projectile.filth; - ThingDef postExplosionSpawnThingDefWater = this.def.projectile.postExplosionSpawnThingDefWater; - float postExplosionSpawnChance = this.def.projectile.postExplosionSpawnChance; - int postExplosionSpawnThingCount = this.def.projectile.postExplosionSpawnThingCount; - GasType? postExplosionGasType = this.def.projectile.postExplosionGasType; - ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; - float preExplosionSpawnChance = this.def.projectile.preExplosionSpawnChance; - int preExplosionSpawnThingCount = this.def.projectile.preExplosionSpawnThingCount; - bool applyDamageToExplosionCellsNeighbors = this.def.projectile.applyDamageToExplosionCellsNeighbors; - ThingDef preExplosionSpawnThingDef2 = preExplosionSpawnThingDef; - float preExplosionSpawnChance2 = preExplosionSpawnChance; - int preExplosionSpawnThingCount2 = preExplosionSpawnThingCount; - float explosionChanceToStartFire = this.def.projectile.explosionChanceToStartFire; - bool explosionDamageFalloff = this.def.projectile.explosionDamageFalloff; - float? direction = new float?(this.origin.AngleToFlat(this.destination)); - FloatRange? affectedAngle = null; - float expolosionPropagationSpeed = this.def.projectile.damageDef.expolosionPropagationSpeed; - float screenShakeFactor = this.def.projectile.screenShakeFactor; - IntVec3 center = position; - Map map = base.Map; - float radius = explosionRadius; - DamageDef damType = damageDef; - Thing instigator = launcher; - int damAmount = damageAmount; - float armorPenetration2 = armorPenetration; - SoundDef explosionSound = soundExplode; - ThingDef weapon = equipmentDef; - ThingDef projectile = def; - Thing intendedTarget = thing; - ThingDef postExplosionSpawnThingDef = thingDef; - float postExplosionSpawnChance2 = postExplosionSpawnChance; - int postExplosionSpawnThingCount2 = postExplosionSpawnThingCount; - GasType? postExplosionGasType2 = postExplosionGasType; - bool doExplosionVFX = this.def.projectile.doExplosionVFX; - ThingDef postExplosionSpawnThingDefWater2 = postExplosionSpawnThingDefWater; - GenExplosion.DoExplosion(center, map, radius, damType, instigator, damAmount, armorPenetration2, explosionSound, weapon, projectile, intendedTarget, postExplosionSpawnThingDef, postExplosionSpawnChance2, postExplosionSpawnThingCount2, postExplosionGasType2, null, 255, applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef2, preExplosionSpawnChance2, preExplosionSpawnThingCount2, explosionChanceToStartFire, explosionDamageFalloff, direction, null, affectedAngle, doExplosionVFX, expolosionPropagationSpeed, 0f, true, postExplosionSpawnThingDefWater2, screenShakeFactor, null, null, null, null); - } - - public override void ExposeData() - { - base.ExposeData(); - Scribe_Values.Look(ref exactPositionInt, "exactPosition"); - Scribe_Values.Look(ref curSpeed, "curSpeed"); - Scribe_Values.Look(ref homing, "homing", defaultValue: false); - Scribe_Values.Look(ref ticksToDetonation, "ticksToDetonation", 0, false); // 爆炸弹字段 - if (Scribe.mode == LoadSaveMode.PostLoadInit) - { - ReflectInit(); - if (this.homingDefInt == null) - { - this.homingDefInt = this.def.GetModExtension(); - if (this.homingDefInt == null) - { - Log.ErrorOnce($"HomingProjectileDef is null for projectile {this.def.defName} after PostLoadInit. Creating a default instance.", this.thingIDNumber ^ 0x12345678); - this.homingDefInt = new HomingProjectileDef(); - } - } - } - } - - // Projectile_PoiBullet 原始逻辑 - private void RandFactor() - { - FloatRange floatRange = new FloatRange(-0.5f, 0.5f); - FloatRange floatRange2 = new FloatRange(-0.5f, 0.5f); - this.Randdd.x = floatRange.RandomInRange; - this.Randdd.z = floatRange2.RandomInRange; - this.flag2 = true; - } - - public Vector3 BPos(float t) - { - bool flag = !this.flag2; - if (flag) - { - this.RandFactor(); - } - Vector3 origin = this.origin; - Vector3 a = (this.origin + this.destination) / 2f; - a += this.Randdd; - a.y = this.destination.y; - Vector3 destination = this.destination; - return (1f - t) * (1f - t) * origin + 2f * t * (1f - t) * a + t * t * destination; - } - - private void FindRandCell(Vector3 d) - { - IntVec3 center = IntVec3.FromVector3(d); - this.intendedTarget = CellRect.CenteredOn(center, 2).RandomCell; - } - - protected override void DrawAt(Vector3 position, bool flip = false) - { - Vector3 b = this.BPos(base.DistanceCoveredFraction - 0.01f); - position = this.BPos(base.DistanceCoveredFraction); - Quaternion rotation = Quaternion.LookRotation(position - b); - bool flag = this.tickcount >= 4; - if (flag) - { - Vector3 position2 = position; - position2.y = AltitudeLayer.Projectile.AltitudeFor(); - Graphics.DrawMesh(MeshPool.GridPlane(this.def.graphicData.drawSize), position2, rotation, this.DrawMat, 0); - base.Comps_PostDraw(); - } - } - - private bool CanHitTarget_Poi() // 重命名以避免冲突 - { - bool flag = this.launcher is Pawn; - bool result; - if (flag) - { - float num = this.Hitchance_Poi(); // 使用重命名后的方法 - bool flag2 = (float)Rand.RangeInclusive(0, 100) <= num * 100f; - Pawn pawn = this.intendedTarget.Thing as Pawn; - bool flag3 = pawn != null; - if (flag3) - { - bool downed = pawn.Downed; - if (downed) - { - flag2 = (Rand.RangeInclusive(0, 100) <= 30); - } - } - result = flag2; - } - else - { - result = (Rand.RangeInclusive(0, 100) <= 85); - } - return result; - } - - public float Hitchance_Poi() // 重命名以避免冲突 - { - Pawn pawn = this.launcher as Pawn; - bool flag = pawn != null; - float result; - if (flag) - { - SkillDef named = DefDatabase.GetNamed("Intellectual", true); - SkillRecord skill = pawn.skills.GetSkill(named); - bool flag2 = skill != null; - if (flag2) - { - int level = skill.GetLevel(true); - float num = Mathf.Min(1f, (float)level * 0.05f); - result = num; - } - else - { - result = 0.5f; - } - } - else - { - result = 0.2f; - } - return result; - } - - private void NotifyImpact_Poi(Thing hitThing, Map map, IntVec3 position) // 重命名以避免冲突 - { - BulletImpactData impactData = new BulletImpactData - { - bullet = this, - hitThing = hitThing, - impactPosition = position - }; - bool flag = hitThing != null; - if (flag) - { - hitThing.Notify_BulletImpactNearby(impactData); - } - int num = 9; - for (int i = 0; i < num; i++) - { - IntVec3 c = position + GenRadial.RadialPattern[i]; - bool flag2 = c.InBounds(map); - if (flag2) - { - List thingList = c.GetThingList(map); - for (int j = 0; j < thingList.Count; j++) - { - bool flag3 = thingList[j] != hitThing; - if (flag3) - { - thingList[j].Notify_BulletImpactNearby(impactData); - } - } - } - } - } - - private bool flag2 = false; - private bool flag3 = true; - private bool CalHit = false; - private Vector3 Randdd; - private int tickcount; - - // Projectile_PoiBullet 原始的 Fleck 字段,重命名以避免冲突 - public FleckDef FleckDef_Poi = DefDatabase.GetNamed("CMC_SparkFlash_Blue_Small", true); - public FleckDef FleckDef2_Poi = DefDatabase.GetNamed("CMC_SparkFlash_Blue_LongLasting_Small", true); - public int Fleck_MakeFleckTickMax_Poi = 1; - public IntRange Fleck_MakeFleckNum_Poi = new IntRange(2, 2); - public FloatRange Fleck_Angle_Poi = new FloatRange(-180f, 180f); - public FloatRange Fleck_Scale_Poi = new FloatRange(1.6f, 1.7f); - public FloatRange Fleck_Speed_Poi = new FloatRange(5f, 7f); - public FloatRange Fleck_Speed2_Poi = new FloatRange(0.1f, 0.2f); - public FloatRange Fleck_Rotation_Poi = new FloatRange(-180f, 180f); - public int Fleck_MakeFleckTick_Poi; - } -} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 53c40873..e75c9522 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -124,14 +124,10 @@ - - - - @@ -170,11 +166,13 @@ - - - - - - - + + + + + + + + + \ No newline at end of file