暂存
This commit is contained in:
Binary file not shown.
@@ -28,4 +28,28 @@
|
|||||||
</shaderParameters>
|
</shaderParameters>
|
||||||
</graphicData>
|
</graphicData>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
|
<ThingDef ParentName="MoteBase">
|
||||||
|
<defName>Mote_WULA_RW_Penetrating_Beam</defName>
|
||||||
|
<thingClass>MoteDualAttached</thingClass>
|
||||||
|
<altitudeLayer>MoteOverhead</altitudeLayer>
|
||||||
|
<mote>
|
||||||
|
<fadeInTime>0.1</fadeInTime>
|
||||||
|
<fadeOutTime>0.1</fadeOutTime>
|
||||||
|
<solidTime>0.1</solidTime>
|
||||||
|
<rotateTowardsTarget>True</rotateTowardsTarget>
|
||||||
|
<scaleToConnectTargets>True</scaleToConnectTargets>
|
||||||
|
</mote>
|
||||||
|
<drawOffscreen>true</drawOffscreen>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Projectile/ChargeLanceShot</texPath>
|
||||||
|
<graphicClass>Graphic_MoteWithAgeSecs</graphicClass>
|
||||||
|
<shaderType>MoteBeam</shaderType>
|
||||||
|
<shaderParameters>
|
||||||
|
<_ScrollSpeedA>0</_ScrollSpeedA>
|
||||||
|
<_ScrollSpeedB>0</_ScrollSpeedB>
|
||||||
|
<_Intensity>2</_Intensity>
|
||||||
|
</shaderParameters>
|
||||||
|
</graphicData>
|
||||||
|
</ThingDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Defs>
|
|
||||||
<ThingDef ParentName="BaseHumanMakeableGun">
|
|
||||||
<defName>Weapon_ExampleCruiseMissileLauncher</defName>
|
|
||||||
<label>Cruise Missile Launcher</label>
|
|
||||||
<description>A heavy launcher designed for cruise missiles, capable of long-range precision strikes and area bombardment.</description>
|
|
||||||
<techLevel>Spacer</techLevel>
|
|
||||||
<graphicData>
|
|
||||||
<texPath>Things/Item/Weapon/Launcher</texPath> <!-- Placeholder, needs a proper texture path -->
|
|
||||||
<graphicClass>Graphic_Single</graphicClass>
|
|
||||||
</graphicData>
|
|
||||||
<generateCommonality>1</generateCommonality>
|
|
||||||
<soundInteract>Interact_ChargeRifle</soundInteract> <!-- Placeholder, needs a proper sound -->
|
|
||||||
<weaponClasses>
|
|
||||||
<li>LongShots</li>
|
|
||||||
<li>RangedHeavy</li>
|
|
||||||
</weaponClasses>
|
|
||||||
<recipeMaker>
|
|
||||||
<recipeUsers Inherit="False">
|
|
||||||
<li>WULA_Cube_Productor_BIO</li>
|
|
||||||
<li>WULA_Cube_Productor_Energy</li>
|
|
||||||
</recipeUsers>
|
|
||||||
<researchPrerequisite>WULA_Synth_Weapon_Technology</researchPrerequisite>
|
|
||||||
<unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef>
|
|
||||||
</recipeMaker>
|
|
||||||
<statBases>
|
|
||||||
<WorkToMake>2500</WorkToMake>
|
|
||||||
<Mass>6.0</Mass>
|
|
||||||
<AccuracyTouch>0.3</AccuracyTouch>
|
|
||||||
<AccuracyShort>0.5</AccuracyShort>
|
|
||||||
<AccuracyMedium>0.6</AccuracyMedium>
|
|
||||||
<AccuracyLong>0.7</AccuracyLong>
|
|
||||||
<RangedWeapon_Cooldown>4.0</RangedWeapon_Cooldown>
|
|
||||||
</statBases>
|
|
||||||
<costList Inherit="False">
|
|
||||||
<Steel>180</Steel>
|
|
||||||
<ComponentIndustrial>10</ComponentIndustrial>
|
|
||||||
<Plasteel>40</Plasteel>
|
|
||||||
<Uranium>15</Uranium>
|
|
||||||
</costList>
|
|
||||||
<verbs>
|
|
||||||
<li>
|
|
||||||
<verbClass>Verb_LaunchProjectile</verbClass>
|
|
||||||
<hasStandardCommand>true</hasStandardCommand>
|
|
||||||
<defaultProjectile>Bullet_ExampleCruiseMissile</defaultProjectile>
|
|
||||||
<warmupTime>3.0</warmupTime>
|
|
||||||
<range>60</range>
|
|
||||||
<burstShotCount>1</burstShotCount>
|
|
||||||
<soundCast>Shot_ChargeLance</soundCast> <!-- Placeholder, needs a proper sound -->
|
|
||||||
<soundCastTail>GunTail_Heavy</soundCastTail>
|
|
||||||
<muzzleFlashScale>15</muzzleFlashScale>
|
|
||||||
<targetParams>
|
|
||||||
<canTargetLocations>true</canTargetLocations>
|
|
||||||
</targetParams>
|
|
||||||
<forcedMiss>false</forcedMiss>
|
|
||||||
</li>
|
|
||||||
</verbs>
|
|
||||||
<weaponTags>
|
|
||||||
<li>Wula_Weapon_Init</li>
|
|
||||||
<li>CruiseMissileLauncher</li>
|
|
||||||
</weaponTags>
|
|
||||||
<thingSetMakerTags>
|
|
||||||
<li>RewardStandardQualitySuper</li>
|
|
||||||
</thingSetMakerTags>
|
|
||||||
</ThingDef>
|
|
||||||
|
|
||||||
<ThingDef ParentName="BaseBullet">
|
|
||||||
<defName>Bullet_ExampleCruiseMissile</defName>
|
|
||||||
<label>cruise missile</label>
|
|
||||||
<graphicData>
|
|
||||||
<texPath>Things/Projectile/Bullet_Big</texPath> <!-- Placeholder, needs a proper texture path -->
|
|
||||||
<graphicClass>Graphic_Single</graphicClass>
|
|
||||||
</graphicData>
|
|
||||||
<thingClass>WulaFallenEmpire.Projectile_CruiseMissile</thingClass>
|
|
||||||
<projectile>
|
|
||||||
<speed>30</speed>
|
|
||||||
<damageDef>Bomb</damageDef>
|
|
||||||
<damageAmountBase>20</damageAmountBase>
|
|
||||||
<stoppingPower>2.5</stoppingPower>
|
|
||||||
<armorPenetrationBase>0.8</armorPenetrationBase>
|
|
||||||
<soundExplode>Explosion_Bomb</soundExplode>
|
|
||||||
<soundImpactAnticipate>Impact_Metal</soundImpactAnticipate>
|
|
||||||
<flyOverhead>true</flyOverhead>
|
|
||||||
<shadowSize>1.0</shadowSize>
|
|
||||||
<explosionRadius>4.0</explosionRadius>
|
|
||||||
<postExplosionSpawnThingDef>Filth_Rubble</postExplosionSpawnThingDef>
|
|
||||||
<postExplosionSpawnChance>1.0</postExplosionSpawnChance>
|
|
||||||
<postExplosionSpawnThingCount>5</postExplosionSpawnThingCount>
|
|
||||||
<explosionDelay>120</explosionDelay>
|
|
||||||
<screenShakeFactor>1.5</screenShakeFactor>
|
|
||||||
<applyDamageToExplosionCellsNeighbors>true</applyDamageToExplosionCellsNeighbors>
|
|
||||||
<preExplosionSpawnChance>1.0</preExplosionSpawnChance>
|
|
||||||
<preExplosionSpawnThingCount>8</preExplosionSpawnThingCount>
|
|
||||||
<explosionChanceToStartFire>0.7</explosionChanceToStartFire>
|
|
||||||
<explosionDamageFalloff>true</explosionDamageFalloff>
|
|
||||||
<doExplosionVFX>true</doExplosionVFX>
|
|
||||||
<modExtensions>
|
|
||||||
<li Class="WulaFallenEmpire.CruiseMissileProperties">
|
|
||||||
<customDamageDef>Bomb</customDamageDef>
|
|
||||||
<customDamageAmount>25</customDamageAmount>
|
|
||||||
<customExplosionRadius>3.5</customExplosionRadius>
|
|
||||||
<customSoundExplode>Explosion_Bomb</customSoundExplode>
|
|
||||||
<useSubExplosions>true</useSubExplosions>
|
|
||||||
<subExplosionCount>5</subExplosionCount>
|
|
||||||
<subExplosionRadius>2.0</subExplosionRadius>
|
|
||||||
<subExplosionDamage>15</subExplosionDamage>
|
|
||||||
<subExplosionSpread>7.0</subExplosionSpread>
|
|
||||||
<subDamageDef>Bomb</subDamageDef>
|
|
||||||
<subSoundExplode>Explosion_Bomb</subSoundExplode>
|
|
||||||
<tailFleckDef>WULA_GunTail_Smoke</tailFleckDef>
|
|
||||||
<homingSpeed>0.05</homingSpeed>
|
|
||||||
<initRotateAngle>15</initRotateAngle>
|
|
||||||
<destroyTicksAfterLosingTrack>
|
|
||||||
<min>180</min>
|
|
||||||
<max>300</max>
|
|
||||||
</destroyTicksAfterLosingTrack>
|
|
||||||
<speedChangePerTick>0.001</speedChangePerTick>
|
|
||||||
<speedRangeOverride>
|
|
||||||
<min>10</min>
|
|
||||||
<max>20</max>
|
|
||||||
</speedRangeOverride>
|
|
||||||
<proximityFuseRange>1.5</proximityFuseRange>
|
|
||||||
</li>
|
|
||||||
</modExtensions>
|
|
||||||
</projectile>
|
|
||||||
</ThingDef>
|
|
||||||
</Defs>
|
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
<description>A rifle designed to fire homing projectiles. It can track targets and adjust its trajectory in real-time.</description>
|
<description>A rifle designed to fire homing projectiles. It can track targets and adjust its trajectory in real-time.</description>
|
||||||
<techLevel>Spacer</techLevel>
|
<techLevel>Spacer</techLevel>
|
||||||
<graphicData>
|
<graphicData>
|
||||||
<texPath>Things/Item/Weapon/Rifle</texPath> <!-- Placeholder, needs a proper texture path -->
|
<texPath>Wula/Weapon/WULA_RW_Plasm_AR</texPath>
|
||||||
<graphicClass>Graphic_Single</graphicClass>
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<drawSize>1.4</drawSize>
|
||||||
</graphicData>
|
</graphicData>
|
||||||
<generateCommonality>1</generateCommonality>
|
<generateCommonality>1</generateCommonality>
|
||||||
<soundInteract>Interact_Rifle</soundInteract>
|
<soundInteract>Interact_Rifle</soundInteract>
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
<warmupTime>1.0</warmupTime>
|
<warmupTime>1.0</warmupTime>
|
||||||
<range>35</range>
|
<range>35</range>
|
||||||
<burstShotCount>1</burstShotCount>
|
<burstShotCount>1</burstShotCount>
|
||||||
<soundCast>Shot_ChargeRifle</soundCast> <!-- Placeholder, needs a proper sound -->
|
<soundCast>Shot_ChargeRifle</soundCast> <!-- Placeholder, needs a proper sound -->
|
||||||
<soundCastTail>GunTail_Medium</soundCastTail>
|
<soundCastTail>GunTail_Medium</soundCastTail>
|
||||||
<muzzleFlashScale>9</muzzleFlashScale>
|
<muzzleFlashScale>9</muzzleFlashScale>
|
||||||
</li>
|
</li>
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
<defName>Bullet_ExampleHoming</defName>
|
<defName>Bullet_ExampleHoming</defName>
|
||||||
<label>homing bullet</label>
|
<label>homing bullet</label>
|
||||||
<graphicData>
|
<graphicData>
|
||||||
<texPath>Things/Projectile/Bullet_Big</texPath> <!-- Placeholder, needs a proper texture path -->
|
<texPath>Things/Projectile/Bullet_Big</texPath> <!-- Placeholder, needs a proper texture path -->
|
||||||
<graphicClass>Graphic_Single</graphicClass>
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
</graphicData>
|
</graphicData>
|
||||||
<thingClass>WulaFallenEmpire.Projectile_Homing</thingClass>
|
<thingClass>WulaFallenEmpire.Projectile_Homing</thingClass>
|
||||||
@@ -78,9 +79,6 @@
|
|||||||
<flyOverhead>false</flyOverhead>
|
<flyOverhead>false</flyOverhead>
|
||||||
<shadowSize>0.5</shadowSize>
|
<shadowSize>0.5</shadowSize>
|
||||||
<explosionRadius>0.5</explosionRadius>
|
<explosionRadius>0.5</explosionRadius>
|
||||||
<postExplosionSpawnThingDef>Filth_Rubble</postExplosionSpawnThingDef>
|
|
||||||
<postExplosionSpawnChance>0.5</postExplosionSpawnChance>
|
|
||||||
<postExplosionSpawnThingCount>1</postExplosionSpawnThingCount>
|
|
||||||
<explosionDelay>0</explosionDelay>
|
<explosionDelay>0</explosionDelay>
|
||||||
<screenShakeFactor>0.5</screenShakeFactor>
|
<screenShakeFactor>0.5</screenShakeFactor>
|
||||||
<applyDamageToExplosionCellsNeighbors>false</applyDamageToExplosionCellsNeighbors>
|
<applyDamageToExplosionCellsNeighbors>false</applyDamageToExplosionCellsNeighbors>
|
||||||
@@ -89,22 +87,22 @@
|
|||||||
<explosionChanceToStartFire>0.1</explosionChanceToStartFire>
|
<explosionChanceToStartFire>0.1</explosionChanceToStartFire>
|
||||||
<explosionDamageFalloff>true</explosionDamageFalloff>
|
<explosionDamageFalloff>true</explosionDamageFalloff>
|
||||||
<doExplosionVFX>true</doExplosionVFX>
|
<doExplosionVFX>true</doExplosionVFX>
|
||||||
<modExtensions>
|
|
||||||
<li Class="WulaFallenEmpire.HomingProjectileDef">
|
|
||||||
<initRotateAngle>10</initRotateAngle>
|
|
||||||
<homingSpeed>0.05</homingSpeed>
|
|
||||||
<destroyTicksAfterLosingTrack>60</destroyTicksAfterLosingTrack>
|
|
||||||
<proximityFuseRange>1.5</proximityFuseRange>
|
|
||||||
<hitChance>0.8</hitChance>
|
|
||||||
<extraProjectile>Bullet_ExampleHoming</extraProjectile>
|
|
||||||
<SpeedChangeTilesPerTickOverride>0.05</SpeedChangeTilesPerTickOverride>
|
|
||||||
<SpeedRangeTilesPerTickOverride>
|
|
||||||
<min>20</min>
|
|
||||||
<max>40</max>
|
|
||||||
</SpeedRangeTilesPerTickOverride>
|
|
||||||
<tailFleckDef>WULA_GunTail_Smoke</tailFleckDef>
|
|
||||||
</li>
|
|
||||||
</modExtensions>
|
|
||||||
</projectile>
|
</projectile>
|
||||||
|
<modExtensions>
|
||||||
|
<li Class="WulaFallenEmpire.HomingProjectileDef">
|
||||||
|
<initRotateAngle>10</initRotateAngle>
|
||||||
|
<homingSpeed>0.05</homingSpeed>
|
||||||
|
<destroyTicksAfterLosingTrack>60</destroyTicksAfterLosingTrack>
|
||||||
|
<proximityFuseRange>1.5</proximityFuseRange>
|
||||||
|
<hitChance>0.8</hitChance>
|
||||||
|
<extraProjectile>Bullet_ExampleHoming</extraProjectile>
|
||||||
|
<SpeedChangeTilesPerTickOverride>0.05</SpeedChangeTilesPerTickOverride>
|
||||||
|
<SpeedRangeTilesPerTickOverride>
|
||||||
|
<min>20</min>
|
||||||
|
<max>40</max>
|
||||||
|
</SpeedRangeTilesPerTickOverride>
|
||||||
|
<tailFleckDef>WULA_GunTail_Smoke</tailFleckDef>
|
||||||
|
</li>
|
||||||
|
</modExtensions>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
<description>A powerful launcher that fires homing projectiles with explosive payloads. Ideal for area denial and heavy damage.</description>
|
<description>A powerful launcher that fires homing projectiles with explosive payloads. Ideal for area denial and heavy damage.</description>
|
||||||
<techLevel>Spacer</techLevel>
|
<techLevel>Spacer</techLevel>
|
||||||
<graphicData>
|
<graphicData>
|
||||||
<texPath>Things/Item/Weapon/Launcher</texPath> <!-- Placeholder, needs a proper texture path -->
|
<texPath>Wula/Weapon/WULA_RW_Plasm_AR</texPath>
|
||||||
<graphicClass>Graphic_Single</graphicClass>
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<drawSize>1.4</drawSize>
|
||||||
</graphicData>
|
</graphicData>
|
||||||
<generateCommonality>0.8</generateCommonality>
|
<generateCommonality>0.8</generateCommonality>
|
||||||
<soundInteract>Interact_ChargeRifle</soundInteract> <!-- Placeholder, needs a proper sound -->
|
<soundInteract>Interact_ChargeRifle</soundInteract> <!-- Placeholder, needs a proper sound -->
|
||||||
@@ -79,10 +80,6 @@
|
|||||||
<flyOverhead>true</flyOverhead>
|
<flyOverhead>true</flyOverhead>
|
||||||
<shadowSize>0.8</shadowSize>
|
<shadowSize>0.8</shadowSize>
|
||||||
<explosionRadius>3.0</explosionRadius>
|
<explosionRadius>3.0</explosionRadius>
|
||||||
<postExplosionSpawnThingDef>Filth_Rubble</postExplosionSpawnThingDef>
|
|
||||||
<postExplosionSpawnChance>1.0</postExplosionSpawnChance>
|
|
||||||
<postExplosionSpawnThingCount>3</postExplosionSpawnThingCount>
|
|
||||||
<explosionDelay>60</explosionDelay>
|
|
||||||
<screenShakeFactor>1.0</screenShakeFactor>
|
<screenShakeFactor>1.0</screenShakeFactor>
|
||||||
<applyDamageToExplosionCellsNeighbors>true</applyDamageToExplosionCellsNeighbors>
|
<applyDamageToExplosionCellsNeighbors>true</applyDamageToExplosionCellsNeighbors>
|
||||||
<preExplosionSpawnChance>1.0</preExplosionSpawnChance>
|
<preExplosionSpawnChance>1.0</preExplosionSpawnChance>
|
||||||
@@ -90,34 +87,22 @@
|
|||||||
<explosionChanceToStartFire>0.5</explosionChanceToStartFire>
|
<explosionChanceToStartFire>0.5</explosionChanceToStartFire>
|
||||||
<explosionDamageFalloff>true</explosionDamageFalloff>
|
<explosionDamageFalloff>true</explosionDamageFalloff>
|
||||||
<doExplosionVFX>true</doExplosionVFX>
|
<doExplosionVFX>true</doExplosionVFX>
|
||||||
<modExtensions>
|
|
||||||
<li Class="WulaFallenEmpire.HomingProjectileDef">
|
|
||||||
<initRotateAngle>5</initRotateAngle>
|
|
||||||
<homingSpeed>0.03</homingSpeed>
|
|
||||||
<destroyTicksAfterLosingTrack>90</destroyTicksAfterLosingTrack>
|
|
||||||
<proximityFuseRange>2.0</proximityFuseRange>
|
|
||||||
<hitChance>0.7</hitChance>
|
|
||||||
<extraProjectile>Bullet_ExampleHomingExplosive</extraProjectile>
|
|
||||||
<SpeedChangeTilesPerTickOverride>0.03</SpeedChangeTilesPerTickOverride>
|
|
||||||
<SpeedRangeTilesPerTickOverride>
|
|
||||||
<min>20</min>
|
|
||||||
<max>30</max>
|
|
||||||
</SpeedRangeTilesPerTickOverride>
|
|
||||||
<tailFleckDef>WULA_GunTail_Smoke</tailFleckDef>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.ModExtension_Cone">
|
|
||||||
<coneAngle>30</coneAngle>
|
|
||||||
<coneRange>5</coneRange>
|
|
||||||
<repeatExplosionCount>3</repeatExplosionCount>
|
|
||||||
<fragment>Bullet_ShotgunPellet</fragment> <!-- Example fragment -->
|
|
||||||
<fragmentCount>5</fragmentCount>
|
|
||||||
<fragmentRange>
|
|
||||||
<min>1</min>
|
|
||||||
<max>3</max>
|
|
||||||
</fragmentRange>
|
|
||||||
<showConeEffect>true</showConeEffect>
|
|
||||||
</li>
|
|
||||||
</modExtensions>
|
|
||||||
</projectile>
|
</projectile>
|
||||||
|
<modExtensions>
|
||||||
|
<li Class="WulaFallenEmpire.HomingProjectileDef">
|
||||||
|
<initRotateAngle>5</initRotateAngle>
|
||||||
|
<homingSpeed>0.03</homingSpeed>
|
||||||
|
<destroyTicksAfterLosingTrack>90</destroyTicksAfterLosingTrack>
|
||||||
|
<proximityFuseRange>2.0</proximityFuseRange>
|
||||||
|
<hitChance>0.7</hitChance>
|
||||||
|
<extraProjectile>Bullet_ExampleHomingExplosive</extraProjectile>
|
||||||
|
<SpeedChangeTilesPerTickOverride>0.03</SpeedChangeTilesPerTickOverride>
|
||||||
|
<SpeedRangeTilesPerTickOverride>
|
||||||
|
<min>20</min>
|
||||||
|
<max>30</max>
|
||||||
|
</SpeedRangeTilesPerTickOverride>
|
||||||
|
<tailFleckDef>WULA_GunTail_Smoke</tailFleckDef>
|
||||||
|
</li>
|
||||||
|
</modExtensions>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
</WulaFallenEmpire.EventDef>
|
</WulaFallenEmpire.EventDef>
|
||||||
|
|
||||||
<WulaFallenEmpire.EventDef>
|
<WulaFallenEmpire.EventDef>
|
||||||
<defName>Wula_UI_FE_Spiritualist_10</defName>
|
<defName>Wula_UI_FE_Spiritualist_11</defName>
|
||||||
<label>乌拉帝国 大教堂</label>
|
<label>乌拉帝国 大教堂</label>
|
||||||
<portraitPath>Wula/Events/Portraits/WULA_FE_Spiritualist_1</portraitPath>
|
<portraitPath>Wula/Events/Portraits/WULA_FE_Spiritualist_1</portraitPath>
|
||||||
<characterName>帝国修女</characterName>
|
<characterName>帝国修女</characterName>
|
||||||
|
|||||||
@@ -5,21 +5,8 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public class HomingProjectileDef : DefModExtension
|
public class HomingProjectileDef : DefModExtension
|
||||||
{
|
{
|
||||||
public float SpeedChangeTilesPerTickOverride
|
public float SpeedChangeTilesPerTickOverride;
|
||||||
{
|
public FloatRange SpeedRangeTilesPerTickOverride;
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.speedChangePerTick / 100f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloatRange SpeedRangeTilesPerTickOverride
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.speedRangeOverride.Value * 0.01f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float hitChance = 0.5f;
|
public float hitChance = 0.5f;
|
||||||
|
|
||||||
@@ -27,7 +14,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public float initRotateAngle = 30f;
|
public float initRotateAngle = 30f;
|
||||||
|
|
||||||
public float proximityFuseRange = 0f;
|
public float proximityFuseRange = 0.5f; // 调整默认值,使其在接近目标时能正确触发引信
|
||||||
|
|
||||||
public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120);
|
public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120);
|
||||||
|
|
||||||
@@ -37,5 +24,12 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public FloatRange? speedRangeOverride;
|
public FloatRange? speedRangeOverride;
|
||||||
public FleckDef tailFleckDef;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
@@ -9,317 +8,319 @@ using Verse.Sound;
|
|||||||
|
|
||||||
namespace WulaFallenEmpire
|
namespace WulaFallenEmpire
|
||||||
{
|
{
|
||||||
public class Projectile_Homing : Bullet
|
public class Projectile_Homing : Bullet
|
||||||
{
|
{
|
||||||
public HomingProjectileDef HomingDef
|
private HomingProjectileDef homingDefInt;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this.homingDefInt == null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
this.homingDefInt = this.def.GetModExtension<HomingProjectileDef>();
|
|
||||||
}
|
|
||||||
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)
|
private Sustainer ambientSustainer;
|
||||||
{
|
|
||||||
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()
|
private List<ThingComp> comps;
|
||||||
{
|
|
||||||
bool flag = !this.def.projectile.soundAmbient.NullOrUndefined();
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
this.ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this);
|
|
||||||
}
|
|
||||||
this.comps = (List<ThingComp>)NonPublicFields.ThingWithComps_comps.GetValue(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetHitChance(Thing thing)
|
protected Vector3 exactPositionInt;
|
||||||
{
|
|
||||||
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
|
public Vector3 curSpeed;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.exactPositionInt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Quaternion ExactRotation
|
public bool homing = true;
|
||||||
{
|
private int Fleck_MakeFleckTick; // 拖尾特效的计时器
|
||||||
get
|
private Vector3 lastTickPosition; // 记录上一帧的位置,用于计算移动方向
|
||||||
{
|
|
||||||
return Quaternion.LookRotation(this.curSpeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void MovementTick()
|
private static class NonPublicFields
|
||||||
{
|
{
|
||||||
Vector3 vect = this.ExactPosition + this.curSpeed;
|
public static FieldInfo Projectile_AmbientSustainer = typeof(Projectile).GetField("ambientSustainer", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
ShootLine shootLine = new ShootLine(this.ExactPosition.ToIntVec3(), vect.ToIntVec3());
|
public static FieldInfo ThingWithComps_comps = typeof(ThingWithComps).GetField("comps", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
Vector3 vector = (this.intendedTarget.Cell.ToVector3() - this.ExactPosition).Yto0();
|
public static MethodInfo ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
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()
|
public HomingProjectileDef HomingDef
|
||||||
{
|
{
|
||||||
this.ThingWithCompsTick();
|
get
|
||||||
this.lifetime--;
|
{
|
||||||
if (this.HomingDef.tailFleckDef != null)
|
if (homingDefInt == null)
|
||||||
{
|
{
|
||||||
FleckMaker.Static(this.ExactPosition, base.Map, this.HomingDef.tailFleckDef, 1f);
|
homingDefInt = def.GetModExtension<HomingProjectileDef>();
|
||||||
}
|
if (homingDefInt == null)
|
||||||
bool landed = this.landed;
|
{
|
||||||
if (!landed)
|
Log.ErrorOnce($"HomingProjectileDef for {this.def.defName} is null. Creating a default instance.", this.thingIDNumber ^ 0x12345678);
|
||||||
{
|
this.homingDefInt = new HomingProjectileDef();
|
||||||
Vector3 exactPosition = this.ExactPosition;
|
}
|
||||||
this.ticksToImpact--;
|
}
|
||||||
this.MovementTick();
|
return homingDefInt;
|
||||||
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()
|
public override Vector3 ExactPosition => exactPositionInt;
|
||||||
{
|
|
||||||
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)
|
public override Quaternion ExactRotation => Quaternion.LookRotation(curSpeed);
|
||||||
{
|
|
||||||
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()
|
public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null)
|
||||||
{
|
{
|
||||||
base.ExposeData();
|
bool flag = false;
|
||||||
Scribe_Values.Look<Vector3>(ref this.exactPositionInt, "exactPosition", default(Vector3), false);
|
if (usedTarget.HasThing && usedTarget.Thing is IAttackTarget)
|
||||||
Scribe_Values.Look<Vector3>(ref this.curSpeed, "curSpeed", default(Vector3), false);
|
{
|
||||||
Scribe_Values.Look<bool>(ref this.homing, "homing", false, false);
|
if (Rand.Chance(GetHitChance(usedTarget.Thing)))
|
||||||
bool flag = Scribe.mode == LoadSaveMode.PostLoadInit;
|
{
|
||||||
if (flag)
|
hitFlags |= ProjectileHitFlags.IntendedTarget;
|
||||||
{
|
intendedTarget = usedTarget;
|
||||||
this.ReflectInit();
|
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;
|
||||||
|
}
|
||||||
|
ticksToImpact = int.MaxValue;
|
||||||
|
lifetime = int.MaxValue;
|
||||||
|
ReflectInit();
|
||||||
|
}
|
||||||
|
|
||||||
private HomingProjectileDef homingDefInt;
|
protected void ReflectInit()
|
||||||
|
{
|
||||||
|
if (!def.projectile.soundAmbient.NullOrUndefined())
|
||||||
|
{
|
||||||
|
ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this);
|
||||||
|
}
|
||||||
|
comps = (List<ThingComp>)NonPublicFields.ThingWithComps_comps.GetValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
private Sustainer ambientSustainer;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private List<ThingComp> comps;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
protected Vector3 exactPositionInt;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
public Vector3 curSpeed;
|
protected override void Tick()
|
||||||
|
{
|
||||||
|
ThingWithCompsTick();
|
||||||
|
lifetime--;
|
||||||
|
|
||||||
public bool homing = true;
|
// 处理拖尾特效
|
||||||
|
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;
|
||||||
|
|
||||||
private static MethodInfo ProjectileCheckForFreeInterceptBetween = typeof(Projectile).GetMethod("CheckForFreeInterceptBetween", BindingFlags.Instance | BindingFlags.NonPublic);
|
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<HomingProjectileDef>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -84,19 +84,32 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
if (!infinitePenetration && hitCounter >= maxHits) break;
|
if (!infinitePenetration && hitCounter >= maxHits) break;
|
||||||
|
|
||||||
if (thing is Pawn pawn && pawn != launcher && !alreadyDamaged.Contains(pawn))
|
// 统一处理 Pawn 和 Building 的伤害逻辑
|
||||||
|
// 确保 Thing 未被伤害过且不是发射者
|
||||||
|
if (thing != launcher && !alreadyDamaged.Contains(thing))
|
||||||
{
|
{
|
||||||
bool shouldDamage = false;
|
bool shouldDamage = false;
|
||||||
if (intendedTarget.Thing == pawn) shouldDamage = true;
|
Pawn pawn = thing as Pawn;
|
||||||
else if (pawn.HostileTo(launcher)) shouldDamage = true;
|
Building building = thing as Building;
|
||||||
else if (!shouldPreventFriendlyFire) shouldDamage = true;
|
|
||||||
|
if (pawn != null) // 如果是 Pawn
|
||||||
|
{
|
||||||
|
if (intendedTarget.Thing == pawn) shouldDamage = true;
|
||||||
|
else if (pawn.HostileTo(launcher)) shouldDamage = true;
|
||||||
|
else if (!shouldPreventFriendlyFire) shouldDamage = true;
|
||||||
|
}
|
||||||
|
else if (building != null) // 如果是 Building
|
||||||
|
{
|
||||||
|
shouldDamage = true; // 默认对 Building 造成伤害
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldDamage)
|
if (shouldDamage)
|
||||||
{
|
{
|
||||||
ApplyPathDamage(pawn, props);
|
ApplyPathDamage(thing, props); // 传递 Thing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (thing.def.Fillage == FillCategory.Full && thing.def.blockLight)
|
// 只有当遇到完全阻挡的 Thing 且不是 Pawn 或 Building 时才停止穿透
|
||||||
|
else if (thing.def.Fillage == FillCategory.Full && thing.def.blockLight && !(thing is Pawn) && !(thing is Building))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -105,9 +118,15 @@ namespace WulaFallenEmpire
|
|||||||
this.Destroy(DestroyMode.Vanish);
|
this.Destroy(DestroyMode.Vanish);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyPathDamage(Pawn pawn, Wula_BeamPierce_Extension props)
|
private void ApplyPathDamage(Thing targetThing, Wula_BeamPierce_Extension props) // 接受 Thing 参数
|
||||||
{
|
{
|
||||||
float damageMultiplier = Mathf.Pow(1f - props.damageFalloff, hitCounter);
|
float damageMultiplier = 1f;
|
||||||
|
if (targetThing is Pawn) // 只有 Pawn 才计算穿透衰减
|
||||||
|
{
|
||||||
|
damageMultiplier = Mathf.Pow(1f - props.damageFalloff, hitCounter);
|
||||||
|
}
|
||||||
|
// Building 不受穿透衰减影响,或者 Building 的穿透衰减始终为 1 (不衰减)
|
||||||
|
|
||||||
int damageAmount = (int)(this.DamageAmount * damageMultiplier);
|
int damageAmount = (int)(this.DamageAmount * damageMultiplier);
|
||||||
|
|
||||||
if (damageAmount <= 0) return;
|
if (damageAmount <= 0) return;
|
||||||
@@ -123,9 +142,13 @@ namespace WulaFallenEmpire
|
|||||||
DamageInfo.SourceCategory.ThingOrUnknown,
|
DamageInfo.SourceCategory.ThingOrUnknown,
|
||||||
this.intendedTarget.Thing);
|
this.intendedTarget.Thing);
|
||||||
|
|
||||||
pawn.TakeDamage(dinfo);
|
targetThing.TakeDamage(dinfo); // 对 targetThing 造成伤害
|
||||||
alreadyDamaged.Add(pawn);
|
alreadyDamaged.Add(targetThing);
|
||||||
hitCounter++;
|
|
||||||
|
if (targetThing is Pawn) // 只有 Pawn 才增加 hitCounter
|
||||||
|
{
|
||||||
|
hitCounter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Tick() { }
|
protected override void Tick() { }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace WulaFallenEmpire
|
|||||||
public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef
|
public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Projectile_WulaLineAttack : Projectile
|
public class Projectile_WulaLineAttack : Bullet
|
||||||
{
|
{
|
||||||
private int hitCounter = 0;
|
private int hitCounter = 0;
|
||||||
private List<Thing> alreadyDamaged = new List<Thing>();
|
private List<Thing> alreadyDamaged = new List<Thing>();
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using RimWorld;
|
using RimWorld;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Verse.Sound;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Verse;
|
using Verse;
|
||||||
|
|
||||||
@@ -22,150 +20,74 @@ namespace WulaFallenEmpire
|
|||||||
public float subExplosionSpread = 6f;
|
public float subExplosionSpread = 6f;
|
||||||
public DamageDef subDamageDef;
|
public DamageDef subDamageDef;
|
||||||
public SoundDef subSoundExplode;
|
public SoundDef subSoundExplode;
|
||||||
public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef
|
|
||||||
public float homingSpeed = 0.1f;
|
// 新增的弹道配置参数
|
||||||
public float initRotateAngle = 30f;
|
public float bezierArcHeightFactor = 0.05f; // 贝塞尔曲线高度因子
|
||||||
public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120);
|
public float bezierMinArcHeight = 2f; // 贝塞尔曲线最小高度
|
||||||
public float speedChangePerTick;
|
public float bezierMaxArcHeight = 6f; // 贝塞尔曲线最大高度
|
||||||
public FloatRange? speedRangeOverride;
|
public float bezierHorizontalOffsetFactor = 0.1f; // 贝塞尔曲线水平偏移因子
|
||||||
public float proximityFuseRange = 0f;
|
public float bezierSideOffsetFactor = 0.2f; // 贝塞尔曲线侧向偏移因子
|
||||||
|
public float bezierRandomOffsetScale = 0.5f; // 贝塞尔曲线随机偏移缩放
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Projectile_CruiseMissile : Projectile_Explosive
|
public class Projectile_CruiseMissile : Projectile_Explosive
|
||||||
{
|
{
|
||||||
private CruiseMissileProperties settings;
|
private CruiseMissileProperties settings;
|
||||||
protected Vector3 exactPositionInt;
|
private bool flag2;
|
||||||
public Vector3 curSpeed;
|
private Vector3 Randdd;
|
||||||
public bool homing = true;
|
private Vector3 position2;
|
||||||
private Sustainer ambientSustainer;
|
public Vector3 ExPos;
|
||||||
private List<ThingComp> 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)
|
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||||
{
|
{
|
||||||
base.SpawnSetup(map, respawningAfterLoad);
|
base.SpawnSetup(map, respawningAfterLoad);
|
||||||
settings = def.GetModExtension<CruiseMissileProperties>() ?? new CruiseMissileProperties();
|
settings = def.GetModExtension<CruiseMissileProperties>() ?? new CruiseMissileProperties();
|
||||||
this.ReflectInit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Launch(Thing launcherParam, Vector3 originParam, LocalTargetInfo usedTargetParam, LocalTargetInfo intendedTargetParam, ProjectileHitFlags hitFlagsParam, bool preventFriendlyFireParam = false, Thing equipmentParam = null, ThingDef targetCoverDefParam = null)
|
private void RandFactor()
|
||||||
{
|
{
|
||||||
this.launcher = launcherParam;
|
// 调整随机范围,用于控制C形弹道的随机偏移
|
||||||
this.origin = originParam;
|
Randdd = new Vector3(
|
||||||
this.usedTarget = usedTargetParam;
|
Rand.Range(-settings.bezierRandomOffsetScale, settings.bezierRandomOffsetScale), // X轴的随机偏移
|
||||||
this.intendedTarget = intendedTargetParam;
|
Rand.Range(0f, 0f), // Y轴(高度)不进行随机,保持平稳
|
||||||
this.HitFlags = hitFlagsParam;
|
Rand.Range(-settings.bezierRandomOffsetScale, settings.bezierRandomOffsetScale) // Z轴的随机偏移
|
||||||
this.preventFriendlyFire = preventFriendlyFireParam;
|
);
|
||||||
this.equipment = equipmentParam;
|
flag2 = true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ReflectInit()
|
public Vector3 BPos(float t)
|
||||||
{
|
{
|
||||||
if (NonPublicFields.Projectile_AmbientSustainer == null)
|
if (!flag2) RandFactor();
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool flag = !this.def.projectile.soundAmbient.NullOrUndefined();
|
// 计算水平距离
|
||||||
if (flag)
|
float horizontalDistance = Vector3.Distance(new Vector3(origin.x, 0, origin.z),
|
||||||
{
|
new Vector3(destination.x, 0, destination.z));
|
||||||
this.ambientSustainer = (Sustainer)NonPublicFields.Projectile_AmbientSustainer.GetValue(this);
|
|
||||||
}
|
// 动态调整控制点高度,使其更扁平,使用XML配置的高度因子
|
||||||
this.comps = (List<ThingComp>)NonPublicFields.ThingWithComps_comps.GetValue(this);
|
float arcHeight = Mathf.Clamp(horizontalDistance * settings.bezierArcHeightFactor, settings.bezierMinArcHeight, settings.bezierMaxArcHeight);
|
||||||
|
|
||||||
|
// 计算从起点到终点的方向向量
|
||||||
|
Vector3 direction = (destination - origin).normalized;
|
||||||
|
// 计算垂直于方向向量的水平向量(用于侧向偏移),确保C形弯曲方向一致
|
||||||
|
Vector3 perpendicularDirection = Vector3.Cross(direction, Vector3.up).normalized;
|
||||||
|
|
||||||
|
// 调整控制点以形成扁平 C 形,使用XML配置的偏移因子
|
||||||
|
// P1: 在起点附近,向前偏移,向上偏移,并向一侧偏移
|
||||||
|
Vector3 p1 = origin + direction * horizontalDistance * settings.bezierHorizontalOffsetFactor + Vector3.up * arcHeight + perpendicularDirection * horizontalDistance * settings.bezierSideOffsetFactor + Randdd;
|
||||||
|
// P2: 在终点附近,向后偏移,向上偏移,并向同一侧偏移
|
||||||
|
Vector3 p2 = destination - direction * horizontalDistance * settings.bezierHorizontalOffsetFactor + Vector3.up * arcHeight + perpendicularDirection * horizontalDistance * settings.bezierSideOffsetFactor + Randdd;
|
||||||
|
|
||||||
|
return BezierCurve(origin, p1, p2, destination, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetHitChance(Thing thing)
|
private Vector3 BezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||||
{
|
{
|
||||||
float num = this.settings.homingSpeed;
|
float u = 1 - t;
|
||||||
bool flag = thing == null;
|
return u * u * u * p0
|
||||||
float result;
|
+ 3 * u * u * t * p1
|
||||||
if (flag)
|
+ 3 * u * t * t * p2
|
||||||
{
|
+ t * t * t * p3;
|
||||||
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<IntVec3> GetValidCells(Map map)
|
private IEnumerable<IntVec3> GetValidCells(Map map)
|
||||||
@@ -230,149 +152,43 @@ namespace WulaFallenEmpire
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Quaternion ExactRotation
|
protected override void DrawAt(Vector3 position, bool flip = false)
|
||||||
{
|
{
|
||||||
get
|
position2 = BPos(DistanceCoveredFraction - 0.01f);
|
||||||
{
|
ExPos = position = BPos(DistanceCoveredFraction);
|
||||||
return Quaternion.LookRotation(this.curSpeed);
|
base.DrawAt(position, flip);
|
||||||
}
|
|
||||||
}
|
|
||||||
public override Vector3 ExactPosition
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.exactPositionInt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Tick()
|
protected override void Tick()
|
||||||
{
|
{
|
||||||
this.ThingWithCompsTick();
|
if (intendedTarget.Thing is Pawn pawn && pawn.Spawned && !pawn.Destroyed)
|
||||||
this.lifetime--;
|
|
||||||
if (this.settings.tailFleckDef != null)
|
|
||||||
{
|
{
|
||||||
this.Fleck_MakeFleckTick++;
|
if ((pawn.Dead || pawn.Downed) && DistanceCoveredFraction < 0.6f)
|
||||||
if (this.Fleck_MakeFleckTick >= this.Fleck_MakeFleckTickMax)
|
|
||||||
{
|
{
|
||||||
this.Fleck_MakeFleckTick = 0;
|
FindNextTarget(pawn.DrawPos);
|
||||||
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 MovementTick()
|
private void FindNextTarget(Vector3 center)
|
||||||
{
|
{
|
||||||
if (this.homing)
|
var map = base.Map;
|
||||||
|
if (map == null) return;
|
||||||
|
|
||||||
|
foreach (IntVec3 cell in GenRadial.RadialCellsAround(IntVec3.FromVector3(center), 7f, true))
|
||||||
{
|
{
|
||||||
if (this.intendedTarget != null && this.intendedTarget.Thing != null)
|
if (!cell.InBounds(map)) continue;
|
||||||
|
|
||||||
|
Pawn target = cell.GetFirstPawn(map);
|
||||||
|
if (target != null && target.Faction.HostileTo(launcher?.Faction))
|
||||||
{
|
{
|
||||||
Vector3 vector = (this.intendedTarget.Thing.DrawPos - this.exactPositionInt).normalized;
|
intendedTarget = target;
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.settings.speedChangePerTick != 0f)
|
intendedTarget = CellRect.CenteredOn(IntVec3.FromVector3(center), 7).RandomCell;
|
||||||
{
|
|
||||||
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<Vector3>(ref this.exactPositionInt, "exactPosition", default(Vector3), false);
|
|
||||||
Scribe_Values.Look<Vector3>(ref this.curSpeed, "curSpeed", default(Vector3), false);
|
|
||||||
Scribe_Values.Look<bool>(ref this.homing, "homing", true, false);
|
|
||||||
Scribe_Values.Look<int>(ref this.ticksToDestroy, "ticksToDestroy", -1, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class NonPublicFields
|
|
||||||
{
|
|
||||||
public static FieldInfo Projectile_AmbientSustainer;
|
|
||||||
public static FieldInfo ThingWithComps_comps;
|
|
||||||
public static MethodInfo ProjectileCheckForFreeInterceptBetween;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user