/// <summary> /// Produces a secondary explosion on impact using the explosion values from the projectile's projectile def. Requires the projectile's launcher to be passed on due to protection level, /// only works when parent can be cast as ProjectileCR. Intended use is for HEAT and similar weapons that spawn secondary explosions while also penetrating, NOT explosive ammo of /// anti-materiel rifles as the explosion just spawns on top of the pawn, not inside the hit body part. /// /// Additionally handles fragmentation effects if defined. /// </summary> /// <param name="instigator">Launcher of the projectile calling the method</param> public virtual void Explode(Thing instigator, IntVec3 pos, Map map) { if (map == null) { Log.Warning("Tried to do explodeCR in a null map."); return; } // Regular explosion stuff if (Props.explosionRadius > 0 && Props.explosionDamage > 0 && parent.def != null && GenGrid.InBounds(pos, map)) { GenExplosion.DoExplosion (pos, map, Props.explosionRadius, Props.explosionDamageDef, instigator, Props.soundExplode == null ? Props.explosionDamageDef.soundExplosion : Props.soundExplode, parent.def, null, Props.postExplosionSpawnThingDef = null, Props.postExplosionSpawnChance = 0f, Props.postExplosionSpawnThingCount = 1, Props.applyDamageToExplosionCellsNeighbors = false, Props.preExplosionSpawnThingDef = null, Props.explosionSpawnChance = 0, Props.preExplosionSpawnThingCount); } // Fragmentation stuff if (!Props.fragments.NullOrEmpty() && GenGrid.InBounds(pos, map)) { if (Props.fragRange <= 0) { Log.Error(parent.LabelCap + " has fragments but no fragRange"); } else { Vector3 exactOrigin = new Vector3(0, 0, 0); exactOrigin.x = parent.DrawPos.x; exactOrigin.z = parent.DrawPos.z; foreach (ThingCountClass fragment in Props.fragments) { for (int i = 0; i < fragment.count; i++) { ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(fragment.thingDef, null); projectile.canFreeIntercept = true; Vector3 exactTarget = exactOrigin + (new Vector3(1, 0, 1) * UnityEngine.Random.Range(0, Props.fragRange)).RotatedBy(UnityEngine.Random.Range(0, 360)); LocalTargetInfo targetCell = exactTarget.ToIntVec3(); GenSpawn.Spawn(projectile, parent.Position, map); projectile.Launch(instigator, exactOrigin, targetCell, exactTarget, null); } } } } }
/// <summary> /// Fires a projectile using the new aiming system /// </summary> /// <returns>True for successful shot, false otherwise</returns> protected override bool TryCastShot() { ShootLine shootLine; if (!base.TryFindShootLineFromTo(this.caster.Position, this.currentTarget, out shootLine)) { return(false); } if (this.projectilePropsCR.pelletCount < 1) { Log.Error(this.ownerEquipment.LabelBaseCap + " tried firing with pelletCount less than 1."); return(false); } for (int i = 0; i < this.projectilePropsCR.pelletCount; i++) { Vector3 casterExactPosition = this.caster.DrawPos; ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(projectileDef, null); GenSpawn.Spawn(projectile, shootLine.Source); float lengthHorizontalSquared = (this.currentTarget.Cell - this.caster.Position).LengthHorizontalSquared; //New aiming algorithm projectile.canFreeIntercept = true; ShiftVecReport report = this.ShiftVecReportFor(this.currentTarget); Vector3 targetVec3 = this.ShiftTarget(report); projectile.shotAngle = this.shotAngle; projectile.shotHeight = this.shotHeight; projectile.shotSpeed = this.shotSpeed; if (this.currentTarget.Thing != null) { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(this.currentTarget.Thing), targetVec3, this.ownerEquipment); } else { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(shootLine.Dest), targetVec3, this.ownerEquipment); } } this.numShotsFired++; return(true); }
/// <summary> /// Produces a secondary explosion on impact using the explosion values from the projectile's projectile def. Requires the projectile's launcher to be passed on due to protection level, /// only works when parent can be cast as ProjectileCR. Intended use is for HEAT and similar weapons that spawn secondary explosions while also penetrating, NOT explosive ammo of /// anti-materiel rifles as the explosion just spawns on top of the pawn, not inside the hit body part. /// /// Additionally handles fragmentation effects if defined. /// </summary> /// <param name="instigator">Launcher of the projectile calling the method</param> public virtual void Explode(Thing instigator, Verse.IntVec3 pos) { // Regular explosion stuff if (this.Props.explosionRadius > 0 && this.Props.explosionDamage > 0) { Explosion explosion = new Explosion(); explosion.position = pos; explosion.radius = Props.explosionRadius; explosion.damType = Props.explosionDamageDef; explosion.instigator = instigator; explosion.damAmount = GenMath.RoundRandom(Props.explosionDamage); explosion.source = parent.def; explosion.preExplosionSpawnThingDef = Props.preExplosionSpawnThingDef; explosion.preExplosionSpawnChance = Props.explosionSpawnChance; explosion.postExplosionSpawnThingDef = Props.postExplosionSpawnThingDef; explosion.postExplosionSpawnChance = Props.explosionSpawnChance; explosion.applyDamageToExplosionCellsNeighbors = Props.damageAdjacentTiles; Find.Map.GetComponent <ExplosionManager>().StartExplosion(explosion, Props.soundExplode == null ? Props.explosionDamageDef.soundExplosion : Props.soundExplode); } // Fragmentation stuff if (!Props.fragments.NullOrEmpty()) { if (Props.fragRange <= 0) { Log.Error(this.parent.LabelCap + " has fragments but no fragRange"); } else { Vector3 exactOrigin = new Vector3(0, 0, 0); exactOrigin.x = this.parent.DrawPos.x; exactOrigin.z = this.parent.DrawPos.z; foreach (ThingCount fragment in Props.fragments) { for (int i = 0; i < fragment.count; i++) { ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(fragment.thingDef, null); projectile.canFreeIntercept = true; Vector3 exactTarget = exactOrigin + (new Vector3(1, 0, 1) * UnityEngine.Random.Range(0, Props.fragRange)).RotatedBy(UnityEngine.Random.Range(0, 360)); TargetInfo targetCell = exactTarget.ToIntVec3(); GenSpawn.Spawn(projectile, this.parent.Position); projectile.Launch(instigator, exactOrigin, targetCell, exactTarget, null); } } } } }
/// <summary> /// Fires a projectile using the new aiming system /// </summary> /// <returns>True for successful shot</returns> protected override bool TryCastShot() { ShootLine shootLine; if (!base.TryFindShootLineFromTo(this.caster.Position, this.currentTarget, out shootLine)) { return(false); } /*if (!this.CanHitTargetFrom(this.caster.Position, this.currentTarget)) * { * return false; * }*/ Vector3 casterExactPosition = this.caster.DrawPos; ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(this.verbProps.projectileDef, null); GenSpawn.Spawn(projectile, shootLine.Source); float lengthHorizontalSquared = (this.currentTarget.Cell - this.caster.Position).LengthHorizontalSquared; //New aiming algorithm projectile.canFreeIntercept = true; Vector3 targetVec3 = this.ShiftTarget(); projectile.shotAngle = this.shotAngle; projectile.shotHeight = this.shotHeight; projectile.shotSpeed = this.shotSpeed; if (this.currentTarget.Thing != null) { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(this.currentTarget.Thing), targetVec3, this.ownerEquipment); } else { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(shootLine.Dest), targetVec3, this.ownerEquipment); } return(true); }
/// <summary> /// Scatters fragments around /// </summary> protected virtual void ScatterFragments(ThingDef projectileDef) { ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(projectileDef, null); projectile.canFreeIntercept = true; /* * projectile.shotAngle = Random.Range(-3.0f, 0.5f); * projectile.shotHeight = 0.1f; */ Vector3 exactTarget = this.ExactPosition + (new Vector3(1, 0, 1) * Random.Range(0, this.fragRange)).RotatedBy(Random.Range(0, 360)); TargetInfo targetCell = exactTarget.ToIntVec3(); GenSpawn.Spawn(projectile, this.Position); projectile.Launch(this, this.ExactPosition, targetCell, exactTarget, equipment); }