protected virtual void Explode() { ExplosionCE explosion = GenSpawn.Spawn(CE_ThingDefOf.ExplosionCE, ExactPosition.ToIntVec3(), Map) as ExplosionCE; explosion.height = ExactPosition.y; explosion.radius = def.projectile.explosionRadius; explosion.damType = def.projectile.damageDef; explosion.instigator = launcher; explosion.damAmount = def.projectile.GetDamageAmount(1); explosion.weapon = equipmentDef; explosion.projectile = def; explosion.preExplosionSpawnThingDef = def.projectile.preExplosionSpawnThingDef; explosion.preExplosionSpawnChance = def.projectile.preExplosionSpawnChance; explosion.preExplosionSpawnThingCount = def.projectile.preExplosionSpawnThingCount; explosion.postExplosionSpawnThingDef = def.projectile.postExplosionSpawnThingDef; explosion.postExplosionSpawnChance = def.projectile.postExplosionSpawnChance; explosion.postExplosionSpawnThingCount = def.projectile.postExplosionSpawnThingCount; explosion.applyDamageToExplosionCellsNeighbors = def.projectile.applyDamageToExplosionCellsNeighbors; explosion.chanceToStartFire = def.projectile.explosionChanceToStartFire; explosion.damageFalloff = def.projectile.explosionDamageFalloff; explosion.StartExplosion(def.projectile.soundExplode); explosion.armorPenetration = explosion.damAmount * 0.1f; //This code was disabled because it didn't run under previous circumstances. Could be enabled if necessary /* * if (map != null && base.ExactPosition.ToIntVec3().IsValid) * { * ThrowBigExplode(base.ExactPosition + Gen.RandomHorizontalVector(def.projectile.explosionRadius * 0.5f), base.Map, def.projectile.explosionRadius * 0.4f); * } */ base.Impact(null); // base.Impact() handles this.Destroy() and comp.Explode() }
/// <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. /// 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, Vector3 pos, Map map, float scaleFactor = 1) { var posIV = pos.ToIntVec3(); if (map == null) { Log.Warning("Tried to do explodeCE in a null map."); return; } if (!posIV.InBounds(map)) { Log.Warning("Tried to explodeCE out of bounds"); return; } if (!Props.fragments.NullOrEmpty()) { var projCE = parent as ProjectileCE; var edifice = posIV.GetEdifice(map); var edificeHeight = edifice == null ? 0 : new CollisionVertical(edifice).Max; var height = projCE != null?Mathf.Max(edificeHeight, pos.y) : edificeHeight; foreach (var fragment in Props.fragments) { _monoDummy.GetComponent <MonoDummy>().StartCoroutine(FragRoutine(pos, map, height, instigator, fragment, Props.fragSpeedFactor)); } } // Regular explosion stuff if (Props.explosionRadius > 0 && Props.explosionDamage > 0 && parent.def != null && GenGrid.InBounds(posIV, map)) { // Copy-paste from GenExplosion ExplosionCE explosion = GenSpawn.Spawn(CE_ThingDefOf.ExplosionCE, posIV, map) as ExplosionCE; explosion.height = pos.y; explosion.radius = Props.explosionRadius * scaleFactor; explosion.damType = Props.explosionDamageDef; explosion.instigator = instigator; explosion.damAmount = GenMath.RoundRandom(Props.explosionDamage * scaleFactor); explosion.weapon = null; explosion.projectile = parent.def; explosion.preExplosionSpawnThingDef = Props.preExplosionSpawnThingDef; explosion.preExplosionSpawnChance = Props.preExplosionSpawnChance; explosion.preExplosionSpawnThingCount = Props.preExplosionSpawnThingCount; explosion.postExplosionSpawnThingDef = Props.postExplosionSpawnThingDef; explosion.postExplosionSpawnChance = Props.postExplosionSpawnChance; explosion.postExplosionSpawnThingCount = Props.postExplosionSpawnThingCount; explosion.applyDamageToExplosionCellsNeighbors = Props.applyDamageToExplosionCellsNeighbors; explosion.armorPenetration = explosion.damAmount * 0.1f; explosion.damageFalloff = Props.damageFalloff; explosion.chanceToStartFire = Props.chanceToStartFire; explosion.StartExplosion(Props.soundExplode ?? Props.explosionDamageDef.soundExplosion); } }
/// <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. /// 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, Vector3 pos, Map map, float scaleFactor = 1) { var posIV = pos.ToIntVec3(); if (map == null) { Log.Warning("Tried to do explodeCE in a null map."); return; } if (!posIV.InBounds(map)) { Log.Warning("Tried to explodeCE out of bounds"); return; } var projCE = parent as ProjectileCE; #region Fragmentation if (!Props.fragments.NullOrEmpty()) { float edificeHeight = (new CollisionVertical(posIV.GetEdifice(map))).Max; Vector2 exactOrigin = new Vector2(pos.x, pos.z); float height; //Fragments fly from a 0 to 45 degree angle away from the explosion var range = new FloatRange(0, Mathf.PI / 8f); if (projCE != null) { height = Mathf.Max(edificeHeight, pos.y); if (edificeHeight < height) { //If the projectile exploded above the ground, they can fly 45 degree away at the bottom as well range.min = -Mathf.PI / 8f; } // TODO : Check for hitting the bottom or top of a roof } else { //Height is not tracked on non-CE projectiles, so we assume this one's on top of the edifice height = edificeHeight; } foreach (ThingCountClass fragment in Props.fragments) { for (int i = 0; i < fragment.count; i++) { ProjectileCE projectile = (ProjectileCE)ThingMaker.MakeThing(fragment.thingDef, null); GenSpawn.Spawn(projectile, posIV, map); projectile.canTargetSelf = true; projectile.minCollisionSqr = 1f; //TODO : Don't hardcode at FragmentShadowChance, make XML-modifiable projectile.castShadow = (UnityEngine.Random.value < FragmentShadowChance); projectile.logMisses = false; projectile.Launch( instigator, exactOrigin, range.RandomInRange, UnityEngine.Random.Range(0, 360), height, Props.fragSpeedFactor * projectile.def.projectile.speed, projCE ); } } } #endregion // Regular explosion stuff if (Props.explosionRadius > 0 && Props.explosionDamage > 0 && parent.def != null && GenGrid.InBounds(posIV, map)) { // Copy-paste from GenExplosion ExplosionCE explosion = GenSpawn.Spawn(CE_ThingDefOf.ExplosionCE, posIV, map) as ExplosionCE; explosion.height = pos.y; explosion.radius = Props.explosionRadius * scaleFactor; explosion.damType = Props.explosionDamageDef; explosion.instigator = instigator; explosion.damAmount = GenMath.RoundRandom(Props.explosionDamage * scaleFactor); explosion.weapon = null; explosion.projectile = parent.def; explosion.preExplosionSpawnThingDef = Props.preExplosionSpawnThingDef; explosion.preExplosionSpawnChance = Props.preExplosionSpawnChance; explosion.preExplosionSpawnThingCount = Props.preExplosionSpawnThingCount; explosion.postExplosionSpawnThingDef = Props.postExplosionSpawnThingDef; explosion.postExplosionSpawnChance = Props.postExplosionSpawnChance; explosion.postExplosionSpawnThingCount = Props.postExplosionSpawnThingCount; explosion.applyDamageToExplosionCellsNeighbors = Props.applyDamageToExplosionCellsNeighbors; // TODO: for some reason projectile goes to null if (parent.def.projectile != null) { explosion.chanceToStartFire = parent.def.projectile.explosionChanceToStartFire; explosion.dealMoreDamageAtCenter = parent.def.projectile.explosionDealMoreDamageAtCenter; } explosion.StartExplosion(Props.explosionDamageDef.soundExplosion); } }