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
+ Cruise Missile Launcher
+ 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
+ cruise missile
+
+ 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
+ Homing Rifle
+ 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
+ homing bullet
+
+ 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
+ Homing Explosive Launcher
+ 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
+ homing explosive bullet
+
+ 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 @@
+
+
+
+