protected virtual void Explode() { Map map = base.Map; this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; 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, // propsCE == null ? false : propsCE.damageAdjacentTiles, preExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1); ThrowBigExplode(base.Position.ToVector3Shifted() + Gen.RandomHorizontalVector(def.projectile.explosionRadius * 0.5f), map, def.projectile.explosionRadius * 0.4f); CompExplosiveCE comp = this.TryGetComp <CompExplosiveCE>(); if (comp != null) { comp.Explode(launcher, this.Position, Find.VisibleMap); } }
protected virtual void Explode() { this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; float explosionSpawnChance = this.def.projectile.explosionSpawnChance; GenExplosion.DoExplosion(base.Position, base.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, propsCE == null ? false : propsCE.damageAdjacentTiles, preExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1); CompExplosiveCE comp = this.TryGetComp <CompExplosiveCE>(); if (comp != null) { comp.Explode(launcher, this.Position, Find.VisibleMap); } }
private void ApplySuppression(Pawn pawn) { ShieldBelt shield = null; if (pawn.RaceProps.Humanlike) { // check for shield user List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { var personalShield = wornApparel[i] as ShieldBelt; if (personalShield != null) { shield = personalShield; break; } } } //Add suppression CompSuppressable compSuppressable = pawn.TryGetComp <CompSuppressable>(); if (compSuppressable != null && pawn.Faction != launcher?.Faction && (shield == null || shield?.ShieldState == ShieldState.Resetting)) { suppressionAmount = def.projectile.damageAmountBase; ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; float penetrationAmount = propsCE == null ? 0f : propsCE.armorPenetration; suppressionAmount *= 1 - Mathf.Clamp(compSuppressable.ParentArmor - penetrationAmount, 0, 1); compSuppressable.AddSuppression(suppressionAmount, OriginIV3); } }
protected virtual void Explode() { Map map = base.Map; //this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; GenExplosion.DoExplosion(ExactPosition.ToIntVec3(), 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, propsCE != null && propsCE.damageAdjacentTiles, this.def.projectile.preExplosionSpawnThingDef, this.def.projectile.explosionSpawnChance, 1); //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() }
protected virtual void Explode() { Map map = base.Map; //this.Destroy(DestroyMode.Vanish); ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; GenExplosion.DoExplosion(ExactPosition.ToIntVec3(), map, def.projectile.explosionRadius, def.projectile.damageDef, launcher, def.projectile.damageAmountBase, def.projectile.soundExplode, equipmentDef, def, def.projectile.postExplosionSpawnThingDef, def.projectile.postExplosionSpawnChance, def.projectile.postExplosionSpawnThingCount, def.projectile.applyDamageToExplosionCellsNeighbors, def.projectile.preExplosionSpawnThingDef, def.projectile.preExplosionSpawnChance, def.projectile.preExplosionSpawnThingCount, def.projectile.explosionChanceToStartFire, def.projectile.explosionDealMoreDamageAtCenter); //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> /// Determines the armor penetration value of a given dinfo. Checks WeaponGear to see if it is a projectile, melee weapon or pawn and tries to retrieve the penetration value accordingly. /// </summary> /// <param name="dinfo">DamageInfo to determine penetration for</param> /// <returns>Armor penetration value for attack used, 0 if it can't be determined</returns> private static float GetPenetrationValue(DamageInfo dinfo) { if (dinfo.Def.isExplosive) { return(dinfo.Amount * 0.1f); // Explosions have 10% of their damage as penetration } if (dinfo.WeaponGear != null) { // Case 1: projectile attack ProjectilePropertiesCE projectileProps = dinfo.WeaponGear.projectile as ProjectilePropertiesCE; if (projectileProps != null) { return(projectileProps.armorPenetration); } // Case 2: melee attack Pawn instigatorPawn = dinfo.Instigator as Pawn; if (instigatorPawn != null) { // Pawn is using melee weapon if (dinfo.WeaponGear.IsMeleeWeapon) { if (instigatorPawn.equipment == null || instigatorPawn.equipment.Primary == null || instigatorPawn.equipment.Primary.def != dinfo.WeaponGear) { Log.Error("CE tried getting armor penetration from melee weapon " + dinfo.WeaponGear.defName + " but instigator " + dinfo.Instigator.ToString() + " equipment does not match"); return(0); } return(instigatorPawn.equipment.Primary.GetStatValue(CE_StatDefOf.MeleeWeapon_Penetration)); } // Pawn is using body parts if (instigatorPawn.def == dinfo.WeaponGear) { // Pawn is augmented if (dinfo.WeaponLinkedHediff != null) { HediffCompProperties_VerbGiver compProps = dinfo.WeaponLinkedHediff.CompPropsFor(typeof(HediffComp_VerbGiver)) as HediffCompProperties_VerbGiver; if (compProps != null) { VerbPropertiesCE verbProps = compProps.verbs.FirstOrDefault(v => v as VerbPropertiesCE != null) as VerbPropertiesCE; if (verbProps != null) { return(verbProps.meleeArmorPenetration); } } return(0); } // Regular pawn melee if (dinfo.WeaponBodyPartGroup != null && instigatorPawn.verbTracker != null && !instigatorPawn.verbTracker.AllVerbs.NullOrEmpty()) { Verb verb = instigatorPawn.verbTracker.AllVerbs.FirstOrDefault(v => v.verbProps.linkedBodyPartsGroup == dinfo.WeaponBodyPartGroup); if (verb == null) { Log.Error("CE could not find matching verb on Pawn " + instigatorPawn.ToString() + " for BodyPartGroup " + dinfo.WeaponBodyPartGroup.ToString()); return(0); } VerbPropertiesCE verbProps = verb.verbProps as VerbPropertiesCE; if (verbProps != null) { return(verbProps.meleeArmorPenetration); } } } } } #if DEBUG Log.Warning("CE could not determine armor penetration, defaulting"); #endif return(9999); // Really high default value so vanilla damage sources such as GiveInjuriesToKill always penetrate }
/// <summary> /// Determines the armor penetration value of a given dinfo. Checks WeaponGear to see if it is a projectile, melee weapon or pawn and tries to retrieve the penetration value accordingly. /// </summary> /// <param name="dinfo">DamageInfo to determine penetration for</param> /// <returns>Armor penetration value for attack used, 0 if it can't be determined</returns> private static float GetPenetrationValue(DamageInfo dinfo) { if (dinfo.Def.isExplosive) { return(dinfo.Amount * 0.1f); // Explosions have 10% of their damage as penetration } if (dinfo.Weapon != null) { // Case 1: projectile attack ProjectilePropertiesCE projectileProps = dinfo.Weapon.projectile as ProjectilePropertiesCE; if (projectileProps != null) { return(projectileProps.armorPenetration); } // Case 2: melee attack Pawn instigatorPawn = dinfo.Instigator as Pawn; if (instigatorPawn != null) { // Pawn is using melee weapon if (dinfo.Weapon.IsWeapon) { var equipment = instigatorPawn.equipment?.Primary; if (equipment == null || equipment.def != dinfo.Weapon) { Log.Error("CE tried getting armor penetration from melee weapon " + dinfo.Weapon.defName + " but instigator " + dinfo.Instigator.ToString() + " equipment does not match"); return(0); } var penetrationMult = equipment.GetStatValue(CE_StatDefOf.MeleePenetrationFactor); var tool = equipment.def.tools.FirstOrDefault(t => t.linkedBodyPartsGroup == dinfo.WeaponBodyPartGroup) as ToolCE; return(tool.armorPenetration * penetrationMult); } // Get penetration from tool if (instigatorPawn.verbTracker != null && !instigatorPawn.verbTracker.AllVerbs.NullOrEmpty()) { Verb verb = instigatorPawn.verbTracker.AllVerbs.FirstOrDefault(v => v.tool.linkedBodyPartsGroup == dinfo.WeaponBodyPartGroup); if (verb == null) { Log.Error("CE could not find matching verb on Pawn " + instigatorPawn.ToString() + " for BodyPartGroup " + dinfo.WeaponBodyPartGroup.ToString()); return(0); } var tool = verb.tool as ToolCE; if (tool != null) { return(tool.armorPenetration); } } /* * // Pawn is using body parts * if (instigatorPawn.def == dinfo.Weapon) * { * // Pawn is augmented * if (dinfo.WeaponLinkedHediff != null) * { * HediffCompProperties_VerbGiver compProps = dinfo.WeaponLinkedHediff.CompPropsFor(typeof(HediffComp_VerbGiver)) as HediffCompProperties_VerbGiver; * if (compProps != null) * { * VerbPropertiesCE verbProps = compProps.verbs.FirstOrDefault(v => v as VerbPropertiesCE != null) as VerbPropertiesCE; * if (verbProps != null) return verbProps.meleeArmorPenetration; * } * return 0; * } * * // Regular pawn melee * if (dinfo.WeaponBodyPartGroup != null * && instigatorPawn.verbTracker != null * && !instigatorPawn.verbTracker.AllVerbs.NullOrEmpty()) * { * Verb verb = instigatorPawn.verbTracker.AllVerbs.FirstOrDefault(v => v.verbProps.linkedBodyPartsGroup == dinfo.WeaponBodyPartGroup); * if (verb == null) * { * Log.Error("CE could not find matching verb on Pawn " + instigatorPawn.ToString() + " for BodyPartGroup " + dinfo.WeaponBodyPartGroup.ToString()); * return 0; * } * var tool = verb.tool as ToolCE; * if (tool != null) return tool.armorPenetration; * } * } */ } } #if DEBUG Log.Warning("CE could not determine armor penetration, defaulting"); #endif return(9999); // Really high default value so vanilla damage sources such as GiveInjuriesToKill always penetrate }
/// <summary> /// Determines the armor penetration value of a given dinfo. Attempts to extract the tool/verb from the damage info. /// </summary> /// <param name="dinfo">DamageInfo to determine penetration for</param> /// <returns>Armor penetration value for attack used, 0 if it can't be determined</returns> private static float GetPenetrationValue(DamageInfo dinfo) { if (dinfo.Def.isExplosive) { return(dinfo.Amount * 0.1f); // Explosions have 10% of their damage as penetration } if (dinfo.Weapon != null) { // Case 1: projectile attack ProjectilePropertiesCE projectileProps = dinfo.Weapon.projectile as ProjectilePropertiesCE; if (projectileProps != null) { return(projectileProps.armorPenetration); } // Case 2: melee attack Pawn instigatorPawn = dinfo.Instigator as Pawn; if (instigatorPawn != null) { // Case 2.1: .. of an equiped melee weapon if (dinfo.Weapon.IsMeleeWeapon) { ThingWithComps equipment = instigatorPawn.equipment?.Primary; if (equipment == null || equipment.def != dinfo.Weapon) { Log.Error("CE tried getting armor penetration from melee weapon " + dinfo.Weapon.defName + " but instigator " + dinfo.Instigator.ToString() + " equipment does not match"); return(0); } var penetrationMult = equipment.GetStatValue(CE_StatDefOf.MeleePenetrationFactor); var tool = equipment.def.tools.OfType <ToolCE>().GetUsedTool(dinfo); return(tool.armorPenetration * penetrationMult); } // Case 2.2: .. of a ranged weapon if (dinfo.Weapon.IsRangedWeapon) { var tool = dinfo.Weapon.tools.OfType <ToolCE>().GetUsedTool(dinfo); return(tool.armorPenetration); } // Case 2.3: .. of the pawn if (instigatorPawn.def == dinfo.Weapon) { Verb availableVerb = instigatorPawn.meleeVerbs.TryGetMeleeVerb(); // Case 2.3.1: .. of a weaponized hediff (power claw, scyther blade) HediffCompProperties_VerbGiver compProps = dinfo.WeaponLinkedHediff?.CompPropsFor(typeof(HediffComp_VerbGiver)) as HediffCompProperties_VerbGiver; if (compProps != null) { var tool = compProps.tools.OfType <ToolCE>().GetUsedTool(dinfo); if (tool != null) { return(tool.armorPenetration); } VerbPropertiesCE verbProps = compProps.verbs?.FirstOrDefault(v => v is VerbPropertiesCE) as VerbPropertiesCE; var verbs = compProps.verbs; if (verbs.Count() > 1) { Log.ErrorOnce("CE :: HediffCompProperties_VerbGiver for " + dinfo.WeaponLinkedHediff + " has multiple VerbPropertiesCE. [While evaluating DamageInfo " + dinfo.ToString() + "]", dinfo.WeaponLinkedHediff.GetHashCode() + 128937921); } if (verbProps != null) { Log.ErrorOnce("CE :: HediffCompProperties_VerbGiver from DamageInfo " + dinfo.ToString() + " has VerbPropertiesCE, but these should be moved to <tools> for B18", dinfo.WeaponLinkedHediff.GetHashCode() + 128937921); return(verbProps.meleeArmorPenetration); } } // AllVerbs: bodyparts of the pawn // meleeVerbs: all verbs considered "melee worthy" // Case 2.4: .. of a tool naturally on the body (hands/fist, head) if (instigatorPawn.verbTracker != null && !instigatorPawn.verbTracker.AllVerbs.NullOrEmpty()) { var verbs = instigatorPawn.verbTracker.AllVerbs.Where(v => v.tool is ToolCE && v.tool.linkedBodyPartsGroup == dinfo.WeaponBodyPartGroup); if (verbs.Count() > 1) { Log.ErrorOnce("CE :: Race " + instigatorPawn.def + " has multiple ToolCE with linkedBodyPartsGroup=" + dinfo.WeaponBodyPartGroup.ToString() + " which can not be distunguished between. Consider using different linkedBodyPartsGroups. [While evaluating DamageInfo " + dinfo.ToString() + "]", instigatorPawn.def.GetHashCode() + 128937921); } if (!verbs.Any()) { Log.ErrorOnce("CE :: Pawn " + instigatorPawn.ToString() + " for BodyPartGroup " + dinfo.WeaponBodyPartGroup.ToString() + " could not find matching verb (in AllVerbs: " + String.Join(",", instigatorPawn.verbTracker.AllVerbs.Select(x => x.ToString()).ToArray()) + ") [While evaluating DamageInfo " + dinfo.ToString() + "]", instigatorPawn.def.GetHashCode() + 128937921); return(0); } return((verbs.First().tool as ToolCE).armorPenetration); } } } } #if DEBUG Log.Warning("CE could not determine armor penetration, defaulting"); #endif return(9999); // Really high default value so vanilla damage sources such as GiveInjuriesToKill always penetrate }
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_CE damDefCE = def.projectile.damageDef as DamageDef_CE; DamageInfo dinfo = new DamageInfo( def.projectile.damageDef, damageAmountBase, ExactRotation.eulerAngles.y, launcher, null, equipmentDef); // if (damDefCE != null && damDefCE.harmOnlyOutsideLayers) dinfo.ForceHitPart.depth = BodyPartDepth.Outside; ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; if (propsCE != null && !propsCE.secondaryDamage.NullOrEmpty()) { // Log.Message("propsCE: " + propsCE.ToString()); // Get the correct body part Pawn pawn = hitThing as Pawn; if (pawn != null && def.projectile.damageDef.workerClass == typeof(DamageWorker_AddInjuryCE)) { BodyPartRecord exactPartFromDamageInfo = DamageWorker_AddInjuryCE.GetExactPartFromDamageInfo(dinfo, pawn); dinfo = new DamageInfo( dinfo.Def, dinfo.Amount, dinfo.Angle, dinfo.Instigator, exactPartFromDamageInfo = (DamageWorker_AddInjuryCE.GetExactPartFromDamageInfo(dinfo, pawn)), dinfo.WeaponGear); } List <DamageInfo> dinfoList = new List <DamageInfo>() { dinfo }; foreach (SecondaryDamage secDamage in propsCE.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); } }
/// <summary> /// Generates a readout text for a projectile with the damage amount, type, secondary explosion and other CE stats for display in info-box /// </summary> /// <param name="projectileDef">The projectile's ThingDef</param> /// <returns>Formatted string listing projectile stats</returns> public static string GetProjectileReadout(this ThingDef projectileDef) { // Append ammo stats ProjectilePropertiesCE props = projectileDef?.projectile as ProjectilePropertiesCE; if (props == null) { Log.Error("CE tried getting projectile readout with null props"); return(""); } StringBuilder stringBuilder = new StringBuilder(); // Damage type/amount string dmgList = " " + "CE_DescDamage".Translate() + ": "; if (!props.secondaryDamage.NullOrEmpty()) { // If we have multiple damage types, put every one in its own line stringBuilder.AppendLine(dmgList); stringBuilder.AppendLine(" " + GenText.ToStringByStyle(props.damageAmountBase, ToStringStyle.Integer) + " (" + props.damageDef.LabelCap + ")"); foreach (SecondaryDamage sec in props.secondaryDamage) { stringBuilder.AppendLine(" " + GenText.ToStringByStyle(sec.amount, ToStringStyle.Integer) + " (" + sec.def.LabelCap + ")"); } } else { stringBuilder.AppendLine(dmgList + GenText.ToStringByStyle(props.damageAmountBase, ToStringStyle.Integer) + " (" + props.damageDef.LabelCap + ")"); } // Explosion radius if (props.explosionRadius > 0) { stringBuilder.AppendLine(" " + "CE_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(props.explosionRadius, ToStringStyle.FloatOne)); } // Secondary explosion CompProperties_ExplosiveCE secExpProps = projectileDef.GetCompProperties <CompProperties_ExplosiveCE>(); if (secExpProps != null) { if (secExpProps.explosionRadius > 0) { stringBuilder.AppendLine(" " + "CE_DescSecondaryExplosion".Translate() + ":"); stringBuilder.AppendLine(" " + " " + "CE_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionRadius, ToStringStyle.FloatOne)); stringBuilder.AppendLine(" " + " " + "CE_DescDamage".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionDamage, ToStringStyle.Integer) + " (" + secExpProps.explosionDamageDef.LabelCap + ")"); } if (secExpProps.fragRange > 0) { stringBuilder.AppendLine(" " + "CE_DescFragRange".Translate() + ": " + GenText.ToStringByStyle(secExpProps.fragRange, ToStringStyle.FloatTwo)); } } // CE stats stringBuilder.AppendLine(" " + "CE_DescArmorPenetration".Translate() + ": " + GenText.ToStringByStyle(props.armorPenetration, ToStringStyle.PercentOne)); if (props.pelletCount > 1) { stringBuilder.AppendLine(" " + "CE_DescPelletCount".Translate() + ": " + GenText.ToStringByStyle(props.pelletCount, ToStringStyle.Integer)); } if (props.spreadMult != 1) { stringBuilder.AppendLine(" " + "CE_DescSpreadMult".Translate() + ": " + GenText.ToStringByStyle(props.spreadMult, ToStringStyle.PercentZero)); } return(stringBuilder.ToString()); }
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 ProjectilePropertiesCE props = ammoDef.linkedProjectile.projectile as ProjectilePropertiesCE; if (props != null) { // Damage type/amount stringBuilder.AppendLine("\n" + "CE_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("CE_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(props.explosionRadius, ToStringStyle.FloatOne)); } // Secondary explosion CompProperties_ExplosiveCE secExpProps = ammoDef.linkedProjectile.GetCompProperties <CompProperties_ExplosiveCE>(); if (secExpProps != null) { if (secExpProps.explosionRadius > 0) { stringBuilder.AppendLine("CE_DescSecondaryExplosion".Translate() + ":"); stringBuilder.AppendLine(" " + "CE_DescExplosionRadius".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionRadius, ToStringStyle.FloatOne)); stringBuilder.AppendLine(" " + "CE_DescDamage".Translate() + ": " + GenText.ToStringByStyle(secExpProps.explosionDamage, ToStringStyle.Integer) + " (" + secExpProps.explosionDamageDef.LabelCap + ")"); } if (secExpProps.fragRange > 0) { stringBuilder.AppendLine("CE_DescFragRange".Translate() + ": " + GenText.ToStringByStyle(secExpProps.fragRange, ToStringStyle.FloatTwo)); } } // CE stats stringBuilder.AppendLine("CE_DescArmorPenetration".Translate() + ": " + GenText.ToStringByStyle(props.armorPenetration, ToStringStyle.PercentOne)); if (props.pelletCount > 1) { stringBuilder.AppendLine("CE_DescPelletCount".Translate() + ": " + GenText.ToStringByStyle(props.pelletCount, ToStringStyle.Integer)); } if (props.spreadMult != 1) { stringBuilder.AppendLine("CE_DescSpreadMult".Translate() + ": " + GenText.ToStringByStyle(props.spreadMult, ToStringStyle.PercentZero)); } } return(stringBuilder.ToString()); } return(base.GetDescription()); }
public virtual void RayCast(Thing launcher, VerbProperties verbProps, Vector2 origin, float shotAngle, float shotRotation, float shotHeight = 0f, float shotSpeed = -1f, float spreadDegrees = 0f, float aperatureSize = 0.03f, Thing equipment = null) { float magicSpreadFactor = Mathf.Sin(0.06f / 2 * Mathf.Deg2Rad) + aperatureSize; float magicLaserDamageConstant = 1 / (magicSpreadFactor * magicSpreadFactor * 3.14159f); ProjectilePropertiesCE pprops = def.projectile as ProjectilePropertiesCE; shotRotation = Mathf.Deg2Rad * shotRotation + (float)(3.14159 / 2.0f); Vector3 direction = new Vector3(Mathf.Cos(shotRotation) * Mathf.Cos(shotAngle), Mathf.Sin(shotAngle), Mathf.Sin(shotRotation) * Mathf.Cos(shotAngle)); Vector3 origin3 = new Vector3(origin.x, shotHeight, origin.y); Map map = launcher.Map; Vector3 destination = direction * verbProps.range + origin3; this.shotAngle = shotAngle; this.shotHeight = shotHeight; this.shotRotation = shotRotation; this.launcher = launcher; this.origin = origin; equipmentDef = equipment?.def ?? null; Ray ray = new Ray(origin3, direction); var lbce = this as LaserBeamCE; float spreadRadius = Mathf.Sin(spreadDegrees / 2.0f * Mathf.Deg2Rad); LaserGunDef defWeapon = equipmentDef as LaserGunDef; Vector3 muzzle = ray.GetPoint((defWeapon == null ? 0.9f : defWeapon.barrelLength)); var it_bounds = CE_Utility.GetBoundsFor(intendedTarget); for (int i = 1; i < verbProps.range; i++) { float spreadArea = (i * spreadRadius + aperatureSize) * (i * spreadRadius + aperatureSize) * 3.14159f; if (pprops.damageFalloff) { lbce.DamageModifier = 1 / (magicLaserDamageConstant * spreadArea); } Vector3 tp = ray.GetPoint(i); if (tp.y > CollisionVertical.WallCollisionHeight) { break; } if (tp.y < 0) { destination = tp; landed = true; ExactPosition = tp; Position = ExactPosition.ToIntVec3(); break; } foreach (Thing thing in Map.thingGrid.ThingsListAtFast(tp.ToIntVec3())) { if (this == thing) { continue; } var bounds = CE_Utility.GetBoundsFor(thing); if (!bounds.IntersectRay(ray, out var dist)) { continue; } if (i < 2 && thing != intendedTarget) { continue; } if (thing is Plant plant) { if (!Rand.Chance(thing.def.fillPercent * plant.Growth)) { continue; } } else if (thing is Building) { if (!Rand.Chance(thing.def.fillPercent)) { continue; } } ExactPosition = tp; destination = tp; landed = true; LastPos = destination; ExactPosition = destination; Position = ExactPosition.ToIntVec3(); lbce.SpawnBeam(muzzle, destination); lbce.Impact(thing, muzzle); return; } } if (lbce != null) { lbce.SpawnBeam(muzzle, destination); Destroy(DestroyMode.Vanish); return; } }
/// <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; ProjectilePropertiesCE propsCE = def.projectile as ProjectilePropertiesCE; float penetrationAmount = propsCE == null ? 0f : propsCE.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 <= CE_Utility.GetCollisionWidth(pawn)) { //Check vertical distance float pawnHeight = CE_Utility.GetCollisionHeight(pawn); if (height < pawnHeight) { Impact(thing); return(true); } } } if (thing.def.fillPercent > 0 || thing.def.Fillage == FillCategory.Full) { if (height < CE_Utility.GetCollisionHeight(thing) || thing.def.Fillage == FillCategory.Full) { Impact(thing); return(true); } } return(false); }
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.WeaponGear != null) { Pawn instigatorPawn = dinfo.Instigator as Pawn; if (dinfo.WeaponGear.Verbs.Find(s => s.projectileDef != null) != null) { ProjectilePropertiesCE projectileProps = dinfo.WeaponGear.Verbs.Find(s => s.projectileDef != null).projectileDef.projectile as ProjectilePropertiesCE; // ProjectilePropertiesCE projectileProps = dinfo.WeaponGear.projectile as ProjectilePropertiesCE; if (projectileProps != null) { pierceAmount = projectileProps.armorPenetration; } } else if (dinfo.Instigator != null) { 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 (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; BodyPartRecord outerPart = part; while (outerPart.parent != null && outerPart.depth != BodyPartDepth.Outside) { outerPart = outerPart.parent; } if (outerPart.IsInGroup(DefDatabase <BodyPartGroupDef> .GetNamed("CoveredByNaturalArmor"))) { pawnArmorAmount = pawn.GetStatValue(deflectionStat); } if (pawnArmorAmount > 0 && ApplyArmor(ref damageAmount, ref pierceAmount, pawnArmorAmount, null, damageDef)) { deflected = true; if (damageAmount < 0.001) { return(0); } damageDef = absorbDamageDef; deflectionStat = damageDef.armorCategory.DeflectionStat(); ApplyArmor(ref damageAmount, ref pierceAmount, pawn.GetStatValue(deflectionStat, true), pawn, damageDef); } return(Mathf.RoundToInt(damageAmount)); }