diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 5806a8ca..dd6f7824 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/Effects/WulaFleckDefs.xml b/1.6/1.6/Defs/Effects/WulaFleckDefs.xml new file mode 100644 index 00000000..49f56283 --- /dev/null +++ b/1.6/1.6/Defs/Effects/WulaFleckDefs.xml @@ -0,0 +1,24 @@ + + + + WULA_GunTail_Blue + Projectile + 0.5 + + Things/Projectile/ChargeLanceShot + MoteGlow + (0.45,2) + + + + + WULA_GunTail_Smoke + Projectile + 0.23 + + Things/Others/Smoke_Dark + TransparentPostLight + (0.06,0.25) + + + 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 9ccf10a2..f930ff49 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 @@ -1725,7 +1725,6 @@ true Bullet_WULA_WM_Panzer_Turret 0 - 0.1 5.9 75 1 diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_CruiseMissile.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_CruiseMissile.xml new file mode 100644 index 00000000..1a6ef9d4 --- /dev/null +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_CruiseMissile.xml @@ -0,0 +1,127 @@ + + + + Weapon_ExampleCruiseMissileLauncher + + A heavy launcher designed for cruise missiles, capable of long-range precision strikes and area bombardment. + Spacer + + Things/Item/Weapon/Launcher + Graphic_Single + + 1 + Interact_ChargeRifle + +
  • LongShots
  • +
  • RangedHeavy
  • +
    + + +
  • WULA_Cube_Productor_BIO
  • +
  • WULA_Cube_Productor_Energy
  • +
    + WULA_Synth_Weapon_Technology + UnfinishedWeapon +
    + + 2500 + 6.0 + 0.3 + 0.5 + 0.6 + 0.7 + 4.0 + + + 180 + 10 + 40 + 15 + + +
  • + Verb_LaunchProjectile + true + Bullet_ExampleCruiseMissile + 3.0 + 60 + 1 + Shot_ChargeLance + GunTail_Heavy + 15 + + true + + false +
  • +
    + +
  • Wula_Weapon_Init
  • +
  • CruiseMissileLauncher
  • +
    + +
  • RewardStandardQualitySuper
  • +
    +
    + + + Bullet_ExampleCruiseMissile + + + Things/Projectile/Bullet_Big + Graphic_Single + + WulaFallenEmpire.Projectile_CruiseMissile + + 30 + Bomb + 20 + 2.5 + 0.8 + Explosion_Bomb + Impact_Metal + true + 1.0 + 4.0 + Filth_Rubble + 1.0 + 5 + 120 + 1.5 + true + 1.0 + 8 + 0.7 + true + true + +
  • + Bomb + 25 + 3.5 + Explosion_Bomb + true + 5 + 2.0 + 15 + 7.0 + Bomb + Explosion_Bomb + WULA_GunTail_Smoke + 0.05 + 15 + + 180 + 300 + + 0.001 + + 10 + 20 + + 1.5 +
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml new file mode 100644 index 00000000..60360de1 --- /dev/null +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml @@ -0,0 +1,110 @@ + + + + Weapon_ExampleHomingGun + + A rifle designed to fire homing projectiles. It can track targets and adjust its trajectory in real-time. + Spacer + + Things/Item/Weapon/Rifle + Graphic_Single + + 1 + Interact_Rifle + +
  • LongShots
  • +
  • RangedHeavy
  • +
    + + +
  • WULA_Cube_Productor_BIO
  • +
  • WULA_Cube_Productor_Energy
  • +
    + WULA_Synth_Weapon_Technology + UnfinishedWeapon +
    + + 1500 + 3.0 + 0.6 + 0.75 + 0.85 + 0.8 + 1.2 + + + 100 + 5 + 20 + + +
  • + Verb_Shoot + true + Bullet_ExampleHoming + 1.0 + 35 + 1 + Shot_ChargeRifle + GunTail_Medium + 9 +
  • +
    + +
  • Wula_Weapon_Init
  • +
  • HomingWeapon
  • +
    + +
  • RewardStandardQualitySuper
  • +
    +
    + + + Bullet_ExampleHoming + + + Things/Projectile/Bullet_Big + Graphic_Single + + WulaFallenEmpire.Projectile_Homing + + 30 + Bullet + 15 + 1.5 + 0.5 + Explosion_Blasting + Impact_Metal + false + 0.5 + 0.5 + Filth_Rubble + 0.5 + 1 + 0 + 0.5 + false + 0.5 + 1 + 0.1 + true + true + +
  • + 10 + 0.05 + 60 + 1.5 + 0.8 + Bullet_ExampleHoming + 0.05 + + 20 + 40 + + WULA_GunTail_Smoke +
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml new file mode 100644 index 00000000..b9314b46 --- /dev/null +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml @@ -0,0 +1,123 @@ + + + + Weapon_ExampleHomingExplosiveLauncher + + A powerful launcher that fires homing projectiles with explosive payloads. Ideal for area denial and heavy damage. + Spacer + + Things/Item/Weapon/Launcher + Graphic_Single + + 0.8 + Interact_ChargeRifle + +
  • LongShots
  • +
  • RangedHeavy
  • +
    + + +
  • WULA_Cube_Productor_BIO
  • +
  • WULA_Cube_Productor_Energy
  • +
    + WULA_Synth_Weapon_Technology + UnfinishedWeapon +
    + + 2000 + 5.0 + 0.4 + 0.6 + 0.7 + 0.65 + 3.0 + + + 150 + 8 + 30 + 10 + + +
  • + Verb_Shoot + true + Bullet_ExampleHomingExplosive + 2.5 + 40 + 1 + Shot_ChargeLance + GunTail_Heavy + 12 +
  • +
    + +
  • Wula_Weapon_Init
  • +
  • HomingExplosiveWeapon
  • +
    + +
  • RewardStandardQualitySuper
  • +
    +
    + + + Bullet_ExampleHomingExplosive + + + Things/Projectile/Bullet_Big + Graphic_Single + + WulaFallenEmpire.Projectile_Homing_Explosive + + 25 + Bomb + 30 + 2.0 + 0.7 + Explosion_Bomb + Impact_Metal + true + 0.8 + 3.0 + Filth_Rubble + 1.0 + 3 + 60 + 1.0 + true + 1.0 + 5 + 0.5 + true + true + +
  • + 5 + 0.03 + 90 + 2.0 + 0.7 + Bullet_ExampleHomingExplosive + 0.03 + + 20 + 30 + + WULA_GunTail_Smoke +
  • +
  • + 30 + 5 + 3 + Bullet_ShotgunPellet + 5 + + 1 + 3 + + true +
  • +
    +
    +
    +
    \ No newline at end of file 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 68126e7c..a0d739d7 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 @@ -68,6 +68,7 @@ -1 0 false + WULA_GunTail_Blue Normal diff --git a/Source/WulaFallenEmpire/3516260226.code-workspace b/Source/WulaFallenEmpire/3516260226.code-workspace index 2c8d6d23..3a0a3ee4 100644 --- a/Source/WulaFallenEmpire/3516260226.code-workspace +++ b/Source/WulaFallenEmpire/3516260226.code-workspace @@ -9,13 +9,7 @@ "path": "../../../../Data" }, { - "path": "../../../3256974620" - }, - { - "path": "../../../2953846705" - }, - { - "path": "../../../1635901197" + "path": "../../../../../../workshop/content/294100/3534748687" } ], "settings": {} diff --git a/Source/WulaFallenEmpire/HomingProjectileDef.cs b/Source/WulaFallenEmpire/HomingProjectileDef.cs new file mode 100644 index 00000000..65ba2ff1 --- /dev/null +++ b/Source/WulaFallenEmpire/HomingProjectileDef.cs @@ -0,0 +1,41 @@ +using System; +using Verse; + +namespace WulaFallenEmpire +{ + public class HomingProjectileDef : DefModExtension + { + public float SpeedChangeTilesPerTickOverride + { + get + { + return this.speedChangePerTick / 100f; + } + } + + public FloatRange SpeedRangeTilesPerTickOverride + { + get + { + return this.speedRangeOverride.Value * 0.01f; + } + } + + public float hitChance = 0.5f; + + public float homingSpeed = 0.1f; + + public float initRotateAngle = 30f; + + public float proximityFuseRange = 0f; + + public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120); + + public ThingDef extraProjectile; + + public float speedChangePerTick; + + public FloatRange? speedRangeOverride; + public FleckDef tailFleckDef; + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/ModExtension_Cone.cs b/Source/WulaFallenEmpire/ModExtension_Cone.cs new file mode 100644 index 00000000..3008b5d7 --- /dev/null +++ b/Source/WulaFallenEmpire/ModExtension_Cone.cs @@ -0,0 +1,105 @@ +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_Homing.cs b/Source/WulaFallenEmpire/Projectile_Homing.cs new file mode 100644 index 00000000..93f38c22 --- /dev/null +++ b/Source/WulaFallenEmpire/Projectile_Homing.cs @@ -0,0 +1,325 @@ +using System; +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 + { + public HomingProjectileDef HomingDef + { + get + { + bool flag = this.homingDefInt == null; + if (flag) + { + this.homingDefInt = this.def.GetModExtension(); + } + return this.homingDefInt; + } + } + + 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; + bool flag2 = usedTarget.HasThing && usedTarget.Thing is IAttackTarget; + if (flag2) + { + bool flag3 = Rand.Chance(this.GetHitChance(usedTarget.Thing)); + if (flag3) + { + hitFlags |= ProjectileHitFlags.IntendedTarget; + intendedTarget = usedTarget; + flag = true; + } + } + else + { + bool flag4 = Rand.Chance(this.GetHitChance(intendedTarget.Thing)); + if (flag4) + { + hitFlags |= ProjectileHitFlags.IntendedTarget; + usedTarget = intendedTarget; + flag = true; + } + } + bool flag5 = flag; + if (flag5) + { + hitFlags &= ~ProjectileHitFlags.IntendedTarget; + } + base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef); + this.exactPositionInt = origin.Yto0() + Vector3.up * this.def.Altitude; + Vector3 normalized = (this.destination - origin).Yto0().normalized; + float degrees = Rand.Range(-this.HomingDef.initRotateAngle, this.HomingDef.initRotateAngle); + Vector2 vector = new Vector2(normalized.x, normalized.z); + vector = vector.RotatedBy(degrees); + Vector3 a = new Vector3(vector.x, 0f, vector.y); + bool flag6 = this.HomingDef.speedRangeOverride == null; + if (flag6) + { + this.curSpeed = a * this.def.projectile.SpeedTilesPerTick; + } + else + { + this.curSpeed = a * this.HomingDef.SpeedRangeTilesPerTickOverride.RandomInRange; + } + this.ticksToImpact = int.MaxValue; + this.lifetime = int.MaxValue; + this.ReflectInit(); + } + + protected void ReflectInit() + { + bool flag = !this.def.projectile.soundAmbient.NullOrUndefined(); + if (flag) + { + this.ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this); + } + this.comps = (List)NonPublicFields.ThingWithComps_comps.GetValue(this); + } + + public float GetHitChance(Thing thing) + { + float num = this.HomingDef.hitChance; + bool flag = thing == null; + float result; + if (flag) + { + result = num; + } + else + { + Pawn pawn = thing as Pawn; + bool flag2 = pawn != null; + if (flag2) + { + num *= Mathf.Clamp(pawn.BodySize, 0.5f, 1.5f); + bool flag3 = pawn.GetPosture() > PawnPosture.Standing; + if (flag3) + { + num *= 0.5f; + } + float num2 = 1f; + switch (this.equipmentQuality) + { + case QualityCategory.Awful: + num2 = 0.5f; + goto IL_DD; + case QualityCategory.Poor: + num2 = 0.75f; + goto IL_DD; + case QualityCategory.Normal: + num2 = 1f; + goto IL_DD; + case QualityCategory.Excellent: + num2 = 1.1f; + goto IL_DD; + case QualityCategory.Masterwork: + num2 = 1.2f; + goto IL_DD; + case QualityCategory.Legendary: + num2 = 1.3f; + goto IL_DD; + } + Log.Message("Unknown QualityCategory, returning default qualityFactor = 1"); + IL_DD: + num *= num2; + } + else + { + num *= 1.5f * thing.def.fillPercent; + } + result = Mathf.Clamp(num, 0f, 1f); + } + return result; + } + + public override Vector3 ExactPosition + { + get + { + return this.exactPositionInt; + } + } + + public override Quaternion ExactRotation + { + get + { + return Quaternion.LookRotation(this.curSpeed); + } + } + + public virtual void MovementTick() + { + Vector3 vect = this.ExactPosition + this.curSpeed; + ShootLine shootLine = new ShootLine(this.ExactPosition.ToIntVec3(), vect.ToIntVec3()); + Vector3 vector = (this.intendedTarget.Cell.ToVector3() - this.ExactPosition).Yto0(); + bool flag = this.homing; + if (flag) + { + Vector3 a = vector.normalized - this.curSpeed.normalized; + bool flag2 = a.sqrMagnitude >= 1.414f; + if (flag2) + { + this.homing = false; + this.lifetime = this.HomingDef.destroyTicksAfterLosingTrack.RandomInRange; + this.ticksToImpact = this.lifetime; + base.HitFlags &= ~ProjectileHitFlags.IntendedTarget; + base.HitFlags |= ProjectileHitFlags.NonTargetPawns; + base.HitFlags |= ProjectileHitFlags.NonTargetWorld; + } + else + { + this.curSpeed += a * this.HomingDef.homingSpeed * this.curSpeed.magnitude; + } + } + foreach (IntVec3 b in shootLine.Points()) + { + bool flag3 = (this.intendedTarget.Cell - b).SqrMagnitude <= this.HomingDef.proximityFuseRange * this.HomingDef.proximityFuseRange; + if (flag3) + { + this.homing = false; + this.lifetime = this.HomingDef.destroyTicksAfterLosingTrack.RandomInRange; + bool flag4 = (base.HitFlags & ProjectileHitFlags.IntendedTarget) == ProjectileHitFlags.IntendedTarget || this.HomingDef.proximityFuseRange > 0f; + if (flag4) + { + this.lifetime = 0; + this.ticksToImpact = 0; + vect = b.ToVector3(); + bool flag5 = Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && this.def.projectile.soundImpactAnticipate != null; + if (flag5) + { + this.def.projectile.soundImpactAnticipate.PlayOneShot(this); + } + } + } + } + this.exactPositionInt = vect; + this.curSpeed *= (this.curSpeed.magnitude + this.HomingDef.SpeedChangeTilesPerTickOverride) / this.curSpeed.magnitude; + } + + protected override void Tick() + { + this.ThingWithCompsTick(); + this.lifetime--; + if (this.HomingDef.tailFleckDef != null) + { + FleckMaker.Static(this.ExactPosition, base.Map, this.HomingDef.tailFleckDef, 1f); + } + bool landed = this.landed; + if (!landed) + { + Vector3 exactPosition = this.ExactPosition; + this.ticksToImpact--; + this.MovementTick(); + bool flag = !this.ExactPosition.InBounds(base.Map); + if (flag) + { + base.Position = exactPosition.ToIntVec3(); + this.Destroy(DestroyMode.Vanish); + } + else + { + Vector3 exactPosition2 = this.ExactPosition; + object[] parameters = new object[] + { + exactPosition, + exactPosition2 + }; + bool flag2 = (bool)Projectile_Homing.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters); + if (!flag2) + { + base.Position = this.ExactPosition.ToIntVec3(); + bool flag3 = this.ticksToImpact == 60 && Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && this.def.projectile.soundImpactAnticipate != null; + if (flag3) + { + this.def.projectile.soundImpactAnticipate.PlayOneShot(this); + } + bool flag4 = this.ticksToImpact <= 0; + if (flag4) + { + this.ImpactSomething(); + } + else + { + bool flag5 = this.ambientSustainer != null; + if (flag5) + { + this.ambientSustainer.Maintain(); + } + } + } + } + } + } + + private void ThingWithCompsTick() + { + bool flag = this.comps != null; + if (flag) + { + int i = 0; + int count = this.comps.Count; + while (i < count) + { + this.comps[i].CompTick(); + i++; + } + } + } + + protected override void Impact(Thing hitThing, bool blockedByShield = false) + { + Map map = base.Map; + IntVec3 position = base.Position; + base.Impact(hitThing, blockedByShield); + bool flag = this.HomingDef.extraProjectile != null; + if (flag) + { + bool flag2 = hitThing != null && hitThing.Spawned; + if (flag2) + { + ((Projectile)GenSpawn.Spawn(this.HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(this.launcher, this.ExactPosition, hitThing, hitThing, ProjectileHitFlags.All, false, null, null); + } + else + { + ((Projectile)GenSpawn.Spawn(this.HomingDef.extraProjectile, base.Position, map, WipeMode.Vanish)).Launch(this.launcher, this.ExactPosition, position, position, ProjectileHitFlags.All, false, null, null); + } + } + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref this.exactPositionInt, "exactPosition", default(Vector3), false); + Scribe_Values.Look(ref this.curSpeed, "curSpeed", default(Vector3), false); + Scribe_Values.Look(ref this.homing, "homing", false, false); + bool flag = Scribe.mode == LoadSaveMode.PostLoadInit; + if (flag) + { + this.ReflectInit(); + } + } + + private HomingProjectileDef homingDefInt; + + private Sustainer ambientSustainer; + + private List comps; + + protected Vector3 exactPositionInt; + + public Vector3 curSpeed; + + public bool homing = true; + + private static MethodInfo ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic); + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs b/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs new file mode 100644 index 00000000..093bfa8e --- /dev/null +++ b/Source/WulaFallenEmpire/Projectile_Homing_Explosive.cs @@ -0,0 +1,142 @@ +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_WulaPenetrating.cs b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs index 03de527a..2f3b1df4 100644 --- a/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs +++ b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs @@ -14,6 +14,7 @@ namespace WulaFallenEmpire public float damageFalloff = 0.25f; // If true, this projectile will never cause friendly fire, regardless of game settings. public bool preventFriendlyFire = false; + public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef } public class Projectile_WulaLineAttack : Projectile @@ -21,6 +22,13 @@ namespace WulaFallenEmpire private int hitCounter = 0; private List alreadyDamaged = new List(); private Vector3 lastTickPosition; + private int Fleck_MakeFleckTick; // 拖尾特效的计时器 + public int Fleck_MakeFleckTickMax = 1; // 拖尾特效的生成频率 + public IntRange Fleck_MakeFleckNum = new IntRange(1, 1); // 每次生成的粒子数量 + public FloatRange Fleck_Angle = new FloatRange(-180f, 180f); // 粒子角度 + public FloatRange Fleck_Scale = new FloatRange(1f, 1f); // 粒子大小 + public FloatRange Fleck_Speed = new FloatRange(0f, 0f); // 粒子速度 + public FloatRange Fleck_Rotation = new FloatRange(-180f, 180f); // 粒子旋转 private Wula_PathPierce_Extension Props => def.GetModExtension(); @@ -49,7 +57,38 @@ namespace WulaFallenEmpire protected override void Tick() { Vector3 startPos = this.lastTickPosition; - base.Tick(); + base.Tick(); + + if (this.Destroyed) return; + + this.Fleck_MakeFleckTick++; + bool flag = this.Fleck_MakeFleckTick >= this.Fleck_MakeFleckTickMax; + if (flag) + { + this.Fleck_MakeFleckTick = 0; + Map map = base.Map; + int randomInRange = this.Fleck_MakeFleckNum.RandomInRange; + Vector3 vector = this.ExactPosition; // Current position of the bullet + Vector3 vector2 = this.lastTickPosition; // Previous position of the bullet + + for (int i = 0; i < randomInRange; i++) + { + float num = (vector - vector2).AngleFlat(); // Angle based on movement direction + float velocityAngle = this.Fleck_Angle.RandomInRange + num; + float randomInRange2 = this.Fleck_Scale.RandomInRange; + float randomInRange3 = this.Fleck_Speed.RandomInRange; + + if (Props?.tailFleckDef != null) + { + FleckCreationData dataStatic = FleckMaker.GetDataStatic(vector, map, Props.tailFleckDef, randomInRange2); + dataStatic.rotation = (vector - vector2).AngleFlat(); + dataStatic.rotationRate = this.Fleck_Rotation.RandomInRange; + dataStatic.velocityAngle = velocityAngle; + dataStatic.velocitySpeed = randomInRange3; + map.flecks.CreateFleck(dataStatic); + } + } + } if (this.Destroyed) return; diff --git a/Source/WulaFallenEmpire/Verb/Trackingbullet.cs b/Source/WulaFallenEmpire/Verb/Trackingbullet.cs index 5ec0686c..f49445ca 100644 --- a/Source/WulaFallenEmpire/Verb/Trackingbullet.cs +++ b/Source/WulaFallenEmpire/Verb/Trackingbullet.cs @@ -1,6 +1,8 @@ using RimWorld; using System.Collections.Generic; +using Verse.Sound; using System.Linq; +using System.Reflection; using UnityEngine; using Verse; @@ -20,58 +22,150 @@ namespace WulaFallenEmpire public float subExplosionSpread = 6f; public DamageDef subDamageDef; public SoundDef subSoundExplode; - + public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef + public float homingSpeed = 0.1f; + public float initRotateAngle = 30f; + public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120); + public float speedChangePerTick; + public FloatRange? speedRangeOverride; + public float proximityFuseRange = 0f; } public class Projectile_CruiseMissile : Projectile_Explosive { private CruiseMissileProperties settings; - private bool flag2; - private Vector3 Randdd; - private Vector3 position2; - public Vector3 ExPos; + protected Vector3 exactPositionInt; + public Vector3 curSpeed; + public bool homing = true; + private Sustainer ambientSustainer; + private List comps; + private int ticksToDestroy = -1; + + // Launch 方法的参数作为字段 + + // 拖尾特效相关字段 + private int Fleck_MakeFleckTick; + public int Fleck_MakeFleckTickMax = 1; + public IntRange Fleck_MakeFleckNum = new IntRange(1, 1); + public FloatRange Fleck_Angle = new FloatRange(-180f, 180f); + public FloatRange Fleck_Scale = new FloatRange(1f, 1f); + public FloatRange Fleck_Speed = new FloatRange(0f, 0f); + public FloatRange Fleck_Rotation = new FloatRange(-180f, 180f); public override void SpawnSetup(Map map, bool respawningAfterLoad) { base.SpawnSetup(map, respawningAfterLoad); settings = def.GetModExtension() ?? new CruiseMissileProperties(); + this.ReflectInit(); } - private void RandFactor() + public override void Launch(Thing launcherParam, Vector3 originParam, LocalTargetInfo usedTargetParam, LocalTargetInfo intendedTargetParam, ProjectileHitFlags hitFlagsParam, bool preventFriendlyFireParam = false, Thing equipmentParam = null, ThingDef targetCoverDefParam = null) { - // 减少垂直方向随机性,调整水平随机范围 - Randdd = new Vector3( - Rand.Range(-3f, 3f), // 减小水平随机范围 - Rand.Range(8f, 12f), // 降低基础高度 - Rand.Range(-3f, 3f) - ); - flag2 = true; + this.launcher = launcherParam; + this.origin = originParam; + this.usedTarget = usedTargetParam; + this.intendedTarget = intendedTargetParam; + this.HitFlags = hitFlagsParam; + this.preventFriendlyFire = preventFriendlyFireParam; + this.equipment = equipmentParam; + this.targetCoverDef = targetCoverDefParam; + + this.exactPositionInt = origin.Yto0() + Vector3.up * this.def.Altitude; + Vector3 normalized = (this.destination - origin).Yto0().normalized; + float degrees = Rand.Range(-this.settings.initRotateAngle, this.settings.initRotateAngle); + Vector2 vector = new Vector2(normalized.x, normalized.z); + vector = vector.RotatedBy(degrees); + Vector3 a = new Vector3(vector.x, 0f, vector.y); + bool flag6 = this.settings.speedRangeOverride == null; + if (flag6) + { + this.curSpeed = a * this.def.projectile.SpeedTilesPerTick; + } + else + { + this.curSpeed = a * this.settings.speedRangeOverride.Value.RandomInRange; + } + this.ticksToImpact = int.MaxValue; + this.lifetime = int.MaxValue; } - public Vector3 BPos(float t) + protected void ReflectInit() { - if (!flag2) RandFactor(); + if (NonPublicFields.Projectile_AmbientSustainer == null) + { + NonPublicFields.Projectile_AmbientSustainer = typeof(Projectile).GetField("ambientSustainer", BindingFlags.Instance | BindingFlags.NonPublic); + } + if (NonPublicFields.ThingWithComps_comps == null) + { + NonPublicFields.ThingWithComps_comps = typeof(ThingWithComps).GetField("comps", BindingFlags.Instance | BindingFlags.NonPublic); + } + if (NonPublicFields.ProjectileCheckForFreeInterceptBetween == null) + { + NonPublicFields.ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic); + } - // 计算水平距离 - float horizontalDistance = Vector3.Distance(new Vector3(origin.x, 0, origin.z), - new Vector3(destination.x, 0, destination.z)); - - // 动态调整控制点高度 - float arcHeight = Mathf.Clamp(horizontalDistance * 0.2f, 8f, 15f); - - Vector3 a = origin + Vector3.forward * horizontalDistance * 0.2f + new Vector3(0f, arcHeight, 0f); - Vector3 a2 = destination - Vector3.forward * horizontalDistance * 0.2f + new Vector3(0f, arcHeight, 0f); - - return BezierCurve(origin, a, a2, destination, t); + bool flag = !this.def.projectile.soundAmbient.NullOrUndefined(); + if (flag) + { + this.ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this); + } + this.comps = (List)NonPublicFields.ThingWithComps_comps.GetValue(this); } - private Vector3 BezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) + public float GetHitChance(Thing thing) { - float u = 1 - t; - return u * u * u * p0 - + 3 * u * u * t * p1 - + 3 * u * t * t * p2 - + t * t * t * p3; + float num = this.settings.homingSpeed; + bool flag = thing == null; + float result; + if (flag) + { + result = num; + } + else + { + Pawn pawn = thing as Pawn; + bool flag2 = pawn != null; + if (flag2) + { + num *= Mathf.Clamp(pawn.BodySize, 0.5f, 1.5f); + bool flag3 = pawn.GetPosture() > PawnPosture.Standing; + if (flag3) + { + num *= 0.5f; + } + float num2 = 1f; + switch (this.equipmentQuality) + { + case QualityCategory.Awful: + num2 = 0.5f; + goto IL_DD; + case QualityCategory.Poor: + num2 = 0.75f; + goto IL_DD; + case QualityCategory.Normal: + num2 = 1f; + goto IL_DD; + case QualityCategory.Excellent: + num2 = 1.1f; + goto IL_DD; + case QualityCategory.Masterwork: + num2 = 1.2f; + goto IL_DD; + case QualityCategory.Legendary: + num2 = 1.3f; + goto IL_DD; + } + Log.Message("Unknown QualityCategory, returning default qualityFactor = 1"); + IL_DD: + num *= num2; + } + else + { + num *= 1.5f * thing.def.fillPercent; + } + result = Mathf.Clamp(num, 0f, 1f); + } + return result; } private IEnumerable GetValidCells(Map map) @@ -136,43 +230,149 @@ namespace WulaFallenEmpire ); } - protected override void DrawAt(Vector3 position, bool flip = false) + public override Quaternion ExactRotation { - position2 = BPos(DistanceCoveredFraction - 0.01f); - ExPos = position = BPos(DistanceCoveredFraction); - base.DrawAt(position, flip); + get + { + return Quaternion.LookRotation(this.curSpeed); + } + } + public override Vector3 ExactPosition + { + get + { + return this.exactPositionInt; + } } protected override void Tick() { - if (intendedTarget.Thing is Pawn pawn && pawn.Spawned && !pawn.Destroyed) + this.ThingWithCompsTick(); + this.lifetime--; + if (this.settings.tailFleckDef != null) { - if ((pawn.Dead || pawn.Downed) && DistanceCoveredFraction < 0.6f) + this.Fleck_MakeFleckTick++; + if (this.Fleck_MakeFleckTick >= this.Fleck_MakeFleckTickMax) { - FindNextTarget(pawn.DrawPos); + this.Fleck_MakeFleckTick = 0; + for (int i = 0; i < this.Fleck_MakeFleckNum.RandomInRange; i++) + { + FleckMaker.Static(this.ExactPosition + Gen.RandomHorizontalVector(this.Fleck_Scale.RandomInRange / 2f), base.Map, this.settings.tailFleckDef, this.Fleck_Scale.RandomInRange); + } + } + } + + bool landed = this.landed; + if (!landed) + { + Vector3 exactPosition = this.ExactPosition; + this.ticksToImpact--; + this.MovementTick(); + bool flag = !this.ExactPosition.InBounds(base.Map); + if (flag) + { + base.Position = exactPosition.ToIntVec3(); + this.Destroy(DestroyMode.Vanish); + } + else + { + Vector3 exactPosition2 = this.ExactPosition; + object[] parameters = new object[] + { + exactPosition, + exactPosition2 + }; + bool flag2 = (bool)NonPublicFields.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters); + if (!flag2) + { + base.Position = this.ExactPosition.ToIntVec3(); + bool flag3 = this.ticksToImpact == 60 && Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && this.def.projectile.soundImpactAnticipate != null; + if (flag3) + { + this.def.projectile.soundImpactAnticipate.PlayOneShot(this); + } + bool flag4 = this.ticksToImpact <= 0; + if (flag4) + { + this.Impact(null); + } + else + { + bool flag5 = this.ambientSustainer != null; + if (flag5) + { + this.ambientSustainer.Maintain(); + } + } + } } - destination = pawn.DrawPos; } - base.Tick(); } - private void FindNextTarget(Vector3 center) + private void MovementTick() { - var map = base.Map; - if (map == null) return; - - foreach (IntVec3 cell in GenRadial.RadialCellsAround(IntVec3.FromVector3(center), 7f, true)) + if (this.homing) { - if (!cell.InBounds(map)) continue; - - Pawn target = cell.GetFirstPawn(map); - if (target != null && target.Faction.HostileTo(launcher?.Faction)) + if (this.intendedTarget != null && this.intendedTarget.Thing != null) { - intendedTarget = target; + Vector3 vector = (this.intendedTarget.Thing.DrawPos - this.exactPositionInt).normalized; + this.curSpeed = Vector3.RotateTowards(this.curSpeed, vector * this.curSpeed.magnitude, this.settings.homingSpeed, 0f); + } + else if (this.ticksToDestroy == -1) + { + this.ticksToDestroy = this.settings.destroyTicksAfterLosingTrack.RandomInRange; + } + } + if (this.ticksToDestroy > 0) + { + this.ticksToDestroy--; + if (this.ticksToDestroy == 0) + { + this.Destroy(DestroyMode.Vanish); return; } } - intendedTarget = CellRect.CenteredOn(IntVec3.FromVector3(center), 7).RandomCell; + if (this.settings.speedChangePerTick != 0f) + { + this.curSpeed = this.curSpeed.normalized * (this.curSpeed.magnitude + this.settings.speedChangePerTick); + } + if (this.settings.proximityFuseRange > 0f) + { + if (this.intendedTarget != null && this.intendedTarget.Thing != null && (this.intendedTarget.Thing.DrawPos - this.exactPositionInt).magnitude < this.settings.proximityFuseRange) + { + this.Impact(null); + return; + } + } + + this.exactPositionInt += this.curSpeed; + } + + protected void ThingWithCompsTick() + { + if (this.comps != null) + { + for (int i = 0; i < this.comps.Count; i++) + { + this.comps[i].CompTick(); + } + } + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref this.exactPositionInt, "exactPosition", default(Vector3), false); + Scribe_Values.Look(ref this.curSpeed, "curSpeed", default(Vector3), false); + Scribe_Values.Look(ref this.homing, "homing", true, false); + Scribe_Values.Look(ref this.ticksToDestroy, "ticksToDestroy", -1, false); } } + + public static class NonPublicFields + { + public static FieldInfo Projectile_AmbientSustainer; + public static FieldInfo ThingWithComps_comps; + public static MethodInfo ProjectileCheckForFreeInterceptBetween; + } } \ No newline at end of file diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index d93c48f6..82d1a4be 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -124,6 +124,10 @@ + + + +