/// <summary> /// Performs parry calculations. Deflects damage from defender-pawn onto parryThing, applying armor reduction in the process. /// On critical parry does a riposte against this verb's CasterPawn. /// </summary> /// <param name="defender">Pawn doing the parrying</param> /// <param name="parryThing">Thing used to parry the blow (weapon/shield)</param> /// <param name="isRiposte">Whether to do a riposte</param> private void DoParry(Pawn defender, Thing parryThing, bool isRiposte = false) { if (parryThing != null) { foreach (var dinfo in DamageInfosToApply(defender)) { LastAttackVerb = this; ArmorUtilityCE.ApplyParryDamage(dinfo, parryThing); LastAttackVerb = null; } } if (isRiposte) { SoundDef sound = null; if (parryThing is Apparel_Shield) { // Shield bash DamageInfo dinfo = new DamageInfo(DamageDefOf.Blunt, 6, parryThing.GetStatValue(CE_StatDefOf.MeleePenetrationFactor), -1, defender, null, parryThing.def); dinfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside); dinfo.SetAngle((CasterPawn.Position - defender.Position).ToVector3()); caster.TakeDamage(dinfo); if (!parryThing.Stuff.stuffProps.soundMeleeHitBlunt.NullOrUndefined()) { sound = parryThing.Stuff.stuffProps.soundMeleeHitBlunt; } } else { Verb_MeleeAttackCE verb = defender.meleeVerbs.TryGetMeleeVerb(caster) as Verb_MeleeAttackCE; if (verb == null) { Log.Error("CE failed to get attack verb for riposte from Pawn " + defender.ToString()); } else { verb.ApplyMeleeDamageToTarget(caster); sound = verb.SoundHitPawn(); } } // Held, because the caster may have died and despawned sound?.PlayOneShot(new TargetInfo(caster.PositionHeld, caster.MapHeld)); } // Register with parry tracker ParryTracker tracker = defender.MapHeld?.GetComponent <ParryTracker>(); if (tracker == null) { Log.Error("CE failed to find ParryTracker to register pawn " + defender.ToString()); } else { tracker.RegisterParryFor(defender, verbProps.AdjustedCooldownTicks(this, defender)); } }
/// <summary> /// Performs parry calculations. Deflects damage from defender-pawn onto parryThing, applying armor reduction in the process. /// On critical parry does a riposte against this verb's CasterPawn. /// </summary> /// <param name="defender">Pawn doing the parrying</param> /// <param name="parryThing">Thing used to parry the blow (weapon/shield)</param> /// <param name="isRiposte">Whether to do a riposte</param> private void DoParry(Pawn defender, Thing parryThing, bool isRiposte = false) { if (parryThing != null) { foreach (var dinfo in DamageInfosToApply(defender)) { ArmorUtilityCE.ApplyParryDamage(dinfo, parryThing); } } if (isRiposte) { SoundDef sound = null; if (parryThing is Apparel_Shield) { // Shield bash DamageInfo dinfo = new DamageInfo(DamageDefOf.Blunt, 6, -1, defender, null, parryThing.def); caster.TakeDamage(dinfo); if (!parryThing.Stuff.stuffProps.soundMeleeHitBlunt.NullOrUndefined()) { sound = parryThing.Stuff.stuffProps.soundMeleeHitBlunt; } } else { Verb_MeleeAttackCE verb = defender.meleeVerbs.TryGetMeleeVerb() as Verb_MeleeAttackCE; if (verb == null) { Log.Error("CE failed to get attack verb for riposte from Pawn " + defender.ToString()); } else { verb.ApplyMeleeDamageToTarget(caster); sound = verb.SoundHitPawn(); } } sound?.PlayOneShot(new TargetInfo(caster.Position, caster.Map)); } // Register with parry tracker ParryTracker tracker = defender.Map.GetComponent <ParryTracker>(); if (tracker == null) { Log.Error("CE failed to find ParryTracker to register pawn " + defender.ToString()); } else { tracker.RegisterParryFor(defender, verbProps.AdjustedCooldownTicks(ownerEquipment)); } }
private void ApplyDamageToPart(DamageInfo dinfo, Pawn pawn, ref DamageWorker_AddInjuryCE.LocalInjuryResult result) { BodyPartRecord exactPartFromDamageInfo = GetExactPartFromDamageInfo(dinfo, pawn); if (exactPartFromDamageInfo == null) { return; } bool involveArmor = !dinfo.InstantOldInjury; DamageInfo postArmorDinfo = dinfo; bool shieldAbsorbed = false; if (involveArmor) { postArmorDinfo = ArmorUtilityCE.GetAfterArmorDamage(dinfo, pawn, exactPartFromDamageInfo, out shieldAbsorbed); if (dinfo.ForceHitPart == null && postArmorDinfo.ForceHitPart != null && exactPartFromDamageInfo != postArmorDinfo.ForceHitPart) { exactPartFromDamageInfo = postArmorDinfo.ForceHitPart; // If the shot was deflected, update our body part if (pawn.Spawned) { LessonAutoActivator.TeachOpportunity(CE_ConceptDefOf.CE_ArmorSystem, OpportunityType.Critical); // Inform the player about armor deflection } } } // Vanilla code - apply hediff if ((double)postArmorDinfo.Amount < 0.001) { result.deflected = true; return; } HediffDef hediffDefFromDamage = HealthUtility.GetHediffDefFromDamage(postArmorDinfo.Def, pawn, exactPartFromDamageInfo); Hediff_Injury hediff_Injury = (Hediff_Injury)HediffMaker.MakeHediff(hediffDefFromDamage, pawn, null); hediff_Injury.Part = exactPartFromDamageInfo; hediff_Injury.source = postArmorDinfo.WeaponGear; hediff_Injury.sourceBodyPartGroup = postArmorDinfo.WeaponBodyPartGroup; hediff_Injury.sourceHediffDef = postArmorDinfo.WeaponLinkedHediff; hediff_Injury.Severity = (float)postArmorDinfo.Amount; if (postArmorDinfo.InstantOldInjury) { HediffComp_GetsOld hediffComp_GetsOld = hediff_Injury.TryGetComp <HediffComp_GetsOld>(); if (hediffComp_GetsOld != null) { hediffComp_GetsOld.IsOld = true; } else { Log.Error(string.Concat(new object[] { "Tried to create instant old injury on Hediff without a GetsOld comp: ", hediffDefFromDamage, " on ", pawn })); } } result.wounded = true; result.lastHitPart = hediff_Injury.Part; if (DamageWorker_AddInjuryCE.IsHeadshot(postArmorDinfo, hediff_Injury, pawn)) { result.headshot = true; } if (postArmorDinfo.InstantOldInjury && (hediff_Injury.def.CompPropsFor(typeof(HediffComp_GetsOld)) == null || hediff_Injury.Part.def.oldInjuryBaseChance == 0f || hediff_Injury.Part.def.IsSolid(hediff_Injury.Part, pawn.health.hediffSet.hediffs) || pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(hediff_Injury.Part))) { return; } this.FinalizeAndAddInjury(pawn, hediff_Injury, postArmorDinfo, ref result); this.CheckPropagateDamageToInnerSolidParts(postArmorDinfo, pawn, hediff_Injury, involveArmor, ref result); this.CheckDuplicateDamageToOuterParts(postArmorDinfo, pawn, hediff_Injury, involveArmor, ref result); // Apply secondary damage if (!shieldAbsorbed) { var props = dinfo.WeaponGear?.projectile as ProjectilePropertiesCE; if (props != null && !props.secondaryDamage.NullOrEmpty() && dinfo.Def == props.damageDef) { foreach (SecondaryDamage sec in props.secondaryDamage) { if (pawn.Dead) { return; } var secDinfo = sec.GetDinfo(postArmorDinfo); secDinfo.SetForcedHitPart(exactPartFromDamageInfo); pawn.TakeDamage(secDinfo); } } } }