private static void HandleEvadeOrDeflectBlasterFire() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWCreature damager = data.Damager.Object; NWCreature target = NWGameObject.OBJECT_SELF; NWItem damagerWeapon = _.GetLastWeaponUsed(damager); NWItem targetWeapon = target.RightHand; int perkLevel; // Attacker isn't using a pistol or rifle. Return. if (damagerWeapon.CustomItemType != CustomItemType.BlasterPistol && damagerWeapon.CustomItemType != CustomItemType.BlasterRifle) { return; } int modifier; string action; // Check target's equipped weapon, armor and perk. if (target.Chest.CustomItemType == CustomItemType.LightArmor && (targetWeapon.CustomItemType == CustomItemType.MartialArtWeapon || !target.RightHand.IsValid && !target.LeftHand.IsValid)) { // Martial Arts (weapon or unarmed) uses the Evade Blaster Fire perk which is primarily DEX based. perkLevel = PerkService.GetCreaturePerkLevel(target.Object, PerkType.EvadeBlasterFire); modifier = target.DexterityModifier; action = "evade"; } else if (target.Chest.CustomItemType == CustomItemType.ForceArmor && (targetWeapon.CustomItemType == CustomItemType.Lightsaber || targetWeapon.CustomItemType == CustomItemType.Saberstaff || targetWeapon.GetLocalInt("LIGHTSABER") == TRUE)) { // Lightsabers (lightsaber or saberstaff) uses the Deflect Blaster Fire perk which is primarily CHA based. perkLevel = PerkService.GetCreaturePerkLevel(target.Object, PerkType.DeflectBlasterFire); modifier = target.CharismaModifier; action = "deflect"; } else { return; } // Don't have the perk. Return. if (perkLevel <= 0) { return; } // Check attacker's DEX against the primary stat of the perk. int delta = modifier - damager.DexterityModifier; if (delta <= 0) { return; } // Has the delay between block/evade attempts past? DateTime cooldown = DateTime.UtcNow; string lastAttemptVar = target.GetLocalString("EVADE_OR_DEFLECT_BLASTER_FIRE_COOLDOWN"); if (!string.IsNullOrWhiteSpace(lastAttemptVar)) { cooldown = DateTime.Parse(lastAttemptVar); } // Cooldown hasn't expired yet. Not ready to attempt a deflect. if (cooldown >= DateTime.UtcNow) { return; } // Ready to attempt a deflect. Adjust chance based on the delta of attacker DEX versus primary stat of defender. int chanceToDeflect = 5 * delta; if (chanceToDeflect > 80) { chanceToDeflect = 80; } int delay; // Seconds delay between deflect attempts. switch (perkLevel) { case 1: delay = 18; break; case 2: delay = 12; break; case 3: delay = 6; break; default: throw new Exception("HandleEvadeOrDeflectBlasterFire -> Perk Level " + perkLevel + " unsupported."); } cooldown = DateTime.UtcNow.AddSeconds(delay); target.SetLocalString("EVADE_OR_DEFLECT_BLASTER_FIRE_COOLDOWN", cooldown.ToString(CultureInfo.InvariantCulture)); int roll = RandomService.D100(1); if (roll <= chanceToDeflect) { target.SendMessage(ColorTokenService.Gray("You " + action + " a blaster shot.")); data.AdjustAllByPercent(-1); NWNXDamage.SetDamageEventData(data); } else { target.SendMessage(ColorTokenService.Gray("You fail to " + action + " a blaster shot. (" + roll + " vs " + chanceToDeflect + ")")); } }