protected virtual void Explode() { this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; float explosionSpawnChance = this.def.projectile.explosionSpawnChance; GenExplosion.DoExplosion(base.Position, this.def.projectile.explosionRadius, this.def.projectile.damageDef, this.launcher, this.def.projectile.soundExplode, this.def, this.equipmentDef, this.def.projectile.postExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1, propsCR == null ? false : propsCR.damageAdjacentTiles, preExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1); ThrowBigExplode(base.Position.ToVector3Shifted() + Gen.RandomHorizontalVector(def.projectile.explosionRadius * 0.7f), def.projectile.explosionRadius * 0.6f); CompExplosiveCR comp = this.TryGetComp <CompExplosiveCR>(); if (comp != null) { comp.Explode(launcher, this.Position); } }
protected virtual void Explode() { this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; GenExplosion.DoExplosion(base.Position, this.def.projectile.explosionRadius, this.def.projectile.damageDef, this.launcher, this.def.projectile.soundExplode, this.def, this.equipmentDef, this.def.projectile.postExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, propsCR == null ? false : propsCR.damageAdjacentTiles, preExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance); CompExplosiveCR comp = this.TryGetComp <CompExplosiveCR>(); if (comp != null) { comp.Explode(launcher); } }
protected override void Impact(Thing hitThing) { base.Impact(hitThing); if (hitThing != null) { int damageAmountBase = this.def.projectile.damageAmountBase; BodyPartDamageInfo value; DamageDef_CR damDefCR = def.projectile.damageDef as DamageDef_CR; if (damDefCR != null && damDefCR.harmOnlyOutsideLayers) { value = new BodyPartDamageInfo(null, BodyPartDepth.Outside); } else { value = new BodyPartDamageInfo(null, null); } DamageInfo dinfo = new DamageInfo(this.def.projectile.damageDef, damageAmountBase, this.launcher, this.ExactRotation.eulerAngles.y, new BodyPartDamageInfo?(value), this.def); ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; if (propsCR != null && !propsCR.secondaryDamage.NullOrEmpty()) { // Get the correct body part Pawn pawn = hitThing as Pawn; if (pawn != null && def.projectile.damageDef.workerClass == typeof(DamageWorker_AddInjuryCR)) { dinfo = new DamageInfo(dinfo.Def, dinfo.Amount, dinfo.Instigator, dinfo.Angle, new BodyPartDamageInfo(DamageWorker_AddInjuryCR.GetExactPartFromDamageInfo(dinfo, pawn), false, (HediffDef)null), dinfo.Source); } List <DamageInfo> dinfoList = new List <DamageInfo>() { dinfo }; foreach (SecondaryDamage secDamage in propsCR.secondaryDamage) { dinfoList.Add(new DamageInfo(secDamage.def, secDamage.amount, dinfo.Instigator, dinfo.Part, dinfo.Source)); } foreach (DamageInfo curDinfo in dinfoList) { hitThing.TakeDamage(curDinfo); } } else { hitThing.TakeDamage(dinfo); } } else { SoundDefOf.BulletImpactGround.PlayOneShot(base.Position); MoteThrower.ThrowStatic(this.ExactPosition, ThingDefOf.Mote_ShotHit_Dirt, 1f); } }
/// <summary> /// Takes into account the target being downed and the projectile having been fired while the target was downed, and the target's bodySize /// </summary> private bool ImpactThroughBodySize(Thing thing, float height) { Pawn pawn = thing as Pawn; if (pawn != null) { //Add suppression CompSuppressable compSuppressable = pawn.TryGetComp <CompSuppressable>(); if (compSuppressable != null) { float suppressionAmount = this.def.projectile.damageAmountBase; ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; float penetrationAmount = propsCR == null ? 0f : propsCR.armorPenetration; suppressionAmount *= 1 - Mathf.Clamp(compSuppressable.parentArmor - penetrationAmount, 0, 1); compSuppressable.AddSuppression(suppressionAmount, this.origin.ToIntVec3()); } //Check horizontal distance Vector3 dest = this.destination; Vector3 orig = this.origin; Vector3 pawnPos = pawn.DrawPos; float closestDistToPawn = Math.Abs((dest.z - orig.z) * pawnPos.x - (dest.x - orig.x) * pawnPos.z + dest.x * orig.z - dest.z * orig.x) / (float)Math.Sqrt((dest.z - orig.z) * (dest.z - orig.z) + (dest.x - orig.x) * (dest.x - orig.x)); if (closestDistToPawn <= Utility.GetCollisionWidth(pawn)) { //Check vertical distance float pawnHeight = Utility.GetCollisionHeight(pawn); if (height < pawnHeight) { this.Impact(thing); return(true); } } } if (thing.def.fillPercent > 0 || thing.def.Fillage == FillCategory.Full) { if (height < Utility.GetCollisionHeight(thing) || thing.def.Fillage == FillCategory.Full) { this.Impact(thing); return(true); } } return(false); }
protected virtual void Explode() { Map map = base.Map; this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; float explosionSpawnChance = this.def.projectile.explosionSpawnChance; GenExplosion.DoExplosion(base.Position, map, this.def.projectile.explosionRadius, this.def.projectile.damageDef, this.launcher, this.def.projectile.soundExplode, this.def, this.equipmentDef, this.def.projectile.postExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1, false, // propsCR == null ? false : propsCR.damageAdjacentTiles, preExplosionSpawnThingDef, explosionSpawnChance, 1); if (map != null && base.Position.IsValid) { ThrowBigExplode(base.Position.ToVector3Shifted() + Gen.RandomHorizontalVector(def.projectile.explosionRadius * 0.5f), base.Map, def.projectile.explosionRadius * 0.4f); } CompExplosiveCR comp = this.TryGetComp <CompExplosiveCR>(); if (comp != null && this.launcher != null && this.Position.IsValid) { comp.Explode(launcher, this.Position, Find.VisibleMap); } }
public override string GetDescription() { if (ammoDef != null && ammoDef.ammoClass != null && ammoDef.linkedProjectile != null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(base.GetDescription()); // Append ammo class description if (!string.IsNullOrEmpty(ammoDef.ammoClass.description)) { stringBuilder.AppendLine("\n" + (string.IsNullOrEmpty(ammoDef.ammoClass.LabelCap) ? "" : ammoDef.ammoClass.LabelCap + ":\n") + ammoDef.ammoClass.description); } // Append ammo stats ProjectilePropertiesCR props = ammoDef.linkedProjectile.projectile as ProjectilePropertiesCR; if (props != null) { // Damage type/amount stringBuilder.AppendLine("\n" + "CR_DescDamage".Translate() + ": "); stringBuilder.AppendLine(" " + GenText.ToStringByStyle(props.damageAmountBase, ToStringStyle.Integer) + " (" + props.damageDef.LabelCap + ")"); if (!props.secondaryDamage.NullOrEmpty()) { foreach (SecondaryDamage sec in props.secondaryDamage) { stringBuilder.AppendLine(" " + GenText.ToStringByStyle(sec.amount, ToStringStyle.Integer) + " (" + sec.def.LabelCap + ")"); } } // Explosion radius if (props.explosionRadius > 0) { stringBuilder.AppendLine("CR_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(props.explosionRadius, ToStringStyle.FloatOne)); } // Secondary explosion CompProperties_ExplosiveCR secExpProps = ammoDef.linkedProjectile.GetCompProperties <CompProperties_ExplosiveCR>(); if (secExpProps != null) { if (secExpProps.explosionRadius > 0) { stringBuilder.AppendLine("CR_DescSecondaryExplosion".Translate() + ":"); stringBuilder.AppendLine(" " + "CR_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionRadius, ToStringStyle.FloatOne)); stringBuilder.AppendLine(" " + "CR_DescDamage".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionDamage, ToStringStyle.Integer) + " (" + secExpProps.explosionDamageDef.LabelCap + ")"); } if (secExpProps.fragRange > 0) { stringBuilder.AppendLine("CR_DescFragRange".Translate() + ": " + GenText.ToStringByStyle(secExpProps.fragRange, ToStringStyle.FloatTwo)); } } // CR stats stringBuilder.AppendLine("CR_DescArmorPenetration".Translate() + ": " + GenText.ToStringByStyle(props.armorPenetration, ToStringStyle.PercentOne)); if (props.pelletCount > 1) { stringBuilder.AppendLine("CR_DescPelletCount".Translate() + ": " + GenText.ToStringByStyle(props.pelletCount, ToStringStyle.Integer)); } if (props.spreadMult != 1) { stringBuilder.AppendLine("CR_DescSpreadMult".Translate() + ": " + GenText.ToStringByStyle(props.spreadMult, ToStringStyle.PercentZero)); } } return(stringBuilder.ToString()); } return(base.GetDescription()); }
public static readonly DamageDef absorbDamageDef = DamageDefOf.Blunt; //The damage def to convert absorbed shots into /// <summary> /// Calculates deflection chance and damage through armor /// </summary> public static int GetAfterArmorDamage(Pawn pawn, int damAmountInt, BodyPartRecord part, DamageInfo dinfo, bool damageArmor, ref bool deflected) { DamageDef damageDef = dinfo.Def; if (damageDef.armorCategory == DamageArmorCategory.IgnoreArmor) { return(damAmountInt); } float damageAmount = (float)damAmountInt; StatDef deflectionStat = damageDef.armorCategory.DeflectionStat(); // Get armor penetration value float pierceAmount = 0f; if (dinfo.Source != null) { ProjectilePropertiesCR projectileProps = dinfo.Source.projectile as ProjectilePropertiesCR; if (projectileProps != null) { pierceAmount = projectileProps.armorPenetration; } else if (dinfo.Instigator != null) { Pawn instigatorPawn = dinfo.Instigator as Pawn; if (instigatorPawn != null) { if (instigatorPawn.equipment != null && instigatorPawn.equipment.Primary != null) { pierceAmount = instigatorPawn.equipment.Primary.GetStatValue(StatDef.Named("ArmorPenetration")); } else { pierceAmount = instigatorPawn.GetStatValue(StatDef.Named("ArmorPenetration")); } } } } // Run armor calculations on all apparel if (pawn.apparel != null) { List <Apparel> wornApparel = new List <Apparel>(pawn.apparel.WornApparel); for (int i = wornApparel.Count - 1; i >= 0; i--) { if (wornApparel[i].def.apparel.CoversBodyPart(part)) { Thing armorThing = damageArmor ? wornApparel[i] : null; //Check for deflection if (Utility.ApplyArmor(ref damageAmount, ref pierceAmount, wornApparel[i].GetStatValue(deflectionStat, true), armorThing, damageDef)) { deflected = true; if (damageDef != absorbDamageDef) { damageDef = absorbDamageDef; deflectionStat = damageDef.armorCategory.DeflectionStat(); i++; } } if (damageAmount < 0.001) { return(0); } } } } float pawnArmorAmount = 0f; bool partCoveredByArmor = false; if (part.IsInGroup(DefDatabase <BodyPartGroupDef> .GetNamed("CoveredByNaturalArmor"))) { partCoveredByArmor = true; } else { BodyPartRecord outerPart = part; while (outerPart.parent != null && outerPart.depth != BodyPartDepth.Outside) { outerPart = outerPart.parent; } partCoveredByArmor = outerPart != part && outerPart.IsInGroup(DefDatabase <BodyPartGroupDef> .GetNamed("CoveredByNaturalArmor")); } if (partCoveredByArmor) { pawnArmorAmount = pawn.GetStatValue(deflectionStat); } if (pawnArmorAmount > 0 && Utility.ApplyArmor(ref damageAmount, ref pierceAmount, pawnArmorAmount, null, damageDef)) { deflected = true; if (damageAmount < 0.001) { return(0); } damageDef = absorbDamageDef; deflectionStat = damageDef.armorCategory.DeflectionStat(); Utility.ApplyArmor(ref damageAmount, ref pierceAmount, pawn.GetStatValue(deflectionStat, true), pawn, damageDef); } return(Mathf.RoundToInt(damageAmount)); }
/// <summary> /// Takes into account the target being downed and the projectile having been fired while the target was downed, and /// the target's bodySize /// </summary> private bool ImpactThroughBodySize(Thing thing, float height) { Pawn pawn = thing as Pawn; if (pawn != null) { PersonalShield shield = null; if (pawn.RaceProps.Humanlike) { // check for shield user List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { if (wornApparel[i] is PersonalShield) { shield = (PersonalShield)wornApparel[i]; break; } } } //Add suppression CompSuppressable compSuppressable = pawn.TryGetComp <CompSuppressable>(); if (compSuppressable != null) { if (shield == null || (shield != null && shield?.ShieldState == ShieldState.Resetting)) { /* * if (pawn.skills.GetSkill(SkillDefOf.Shooting).level >= 1) * { * suppressionAmount = (def.projectile.damageAmountBase * (1f - ((pawn.skills.GetSkill(SkillDefOf.Shooting).level) / 100) * 3)); * } * else suppressionAmount = def.projectile.damageAmountBase; */ suppressionAmount = def.projectile.damageAmountBase; ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; float penetrationAmount = propsCR == null ? 0f : propsCR.armorPenetration; suppressionAmount *= 1 - Mathf.Clamp(compSuppressable.parentArmor - penetrationAmount, 0, 1); compSuppressable.AddSuppression(suppressionAmount, origin.ToIntVec3()); } } //Check horizontal distance Vector3 dest = destination; Vector3 orig = origin; Vector3 pawnPos = pawn.DrawPos; float closestDistToPawn = Math.Abs((dest.z - orig.z) * pawnPos.x - (dest.x - orig.x) * pawnPos.z + dest.x * orig.z - dest.z * orig.x) / (float) Math.Sqrt((dest.z - orig.z) * (dest.z - orig.z) + (dest.x - orig.x) * (dest.x - orig.x)); if (closestDistToPawn <= CR_Utility.GetCollisionWidth(pawn)) { //Check vertical distance float pawnHeight = CR_Utility.GetCollisionHeight(pawn); if (height < pawnHeight) { Impact(thing); return(true); } } } if (thing.def.fillPercent > 0 || thing.def.Fillage == FillCategory.Full) { if (height < CR_Utility.GetCollisionHeight(thing) || thing.def.Fillage == FillCategory.Full) { Impact(thing); return(true); } } return(false); }
protected override void Impact(Thing hitThing) { Map map = base.Map; base.Impact(hitThing); if (hitThing != null) { int damageAmountBase = def.projectile.damageAmountBase; ThingDef equipmentDef = this.equipmentDef; DamageDef_CR damDefCR = def.projectile.damageDef as DamageDef_CR; DamageInfo dinfo = new DamageInfo( def.projectile.damageDef, damageAmountBase, ExactRotation.eulerAngles.y, launcher, null, equipmentDef); // if (damDefCR != null && damDefCR.harmOnlyOutsideLayers) dinfo.ForceHitPart.depth = BodyPartDepth.Outside; ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR; if (propsCR != null && !propsCR.secondaryDamage.NullOrEmpty()) { // Log.Message("propsCR: " + propsCR.ToString()); // Get the correct body part Pawn pawn = hitThing as Pawn; if (pawn != null && def.projectile.damageDef.workerClass == typeof(DamageWorker_AddInjuryCR)) { BodyPartRecord exactPartFromDamageInfo = DamageWorker_AddInjuryCR.GetExactPartFromDamageInfo(dinfo, pawn); dinfo = new DamageInfo( dinfo.Def, dinfo.Amount, dinfo.Angle, dinfo.Instigator, exactPartFromDamageInfo = (DamageWorker_AddInjuryCR.GetExactPartFromDamageInfo(dinfo, pawn)), dinfo.WeaponGear); } List <DamageInfo> dinfoList = new List <DamageInfo>() { dinfo }; foreach (SecondaryDamage secDamage in propsCR.secondaryDamage) { dinfoList.Add(new DamageInfo( secDamage.def, secDamage.amount, dinfo.Angle, dinfo.Instigator, dinfo.ForceHitPart, dinfo.WeaponGear)); } foreach (DamageInfo curDinfo in dinfoList) { hitThing.TakeDamage(curDinfo); } } else { hitThing.TakeDamage(dinfo); } } else { SoundDefOf.BulletImpactGround.PlayOneShot(new TargetInfo(base.Position, map, false)); MoteMaker.MakeStaticMote(ExactPosition, map, ThingDefOf.Mote_ShotHit_Dirt, 1f); } }