private static void HandleGrenadeProficiency(NWPlayer oPC, NWObject target) { NWItem weapon = _.GetSpellCastItem(); if (weapon.BaseItemType != BaseItem.Grenade) { return; } int perkLevel = PerkService.GetCreaturePerkLevel(oPC, PerkType.GrenadeProficiency); int chance = 10 * perkLevel; float duration; switch (perkLevel) { case 1: case 2: case 3: case 4: duration = 6; break; case 5: case 6: case 7: case 8: case 9: duration = 9; break; default: return; } if (RandomService.D100(1) <= chance) { _.ApplyEffectToObject(DurationType.Temporary, AbilityService.EffectKnockdown(target, duration), target, duration); } }
private static void HandleGrenadeProficiency(NWPlayer oPC, NWObject target) { NWItem weapon = _.GetSpellCastItem(); if (weapon.BaseItemType != BASE_ITEM_GRENADE) { return; } int perkLevel = PerkService.GetPCPerkLevel(oPC, PerkType.GrenadeProficiency); int chance = 10 * perkLevel; float duration; switch (perkLevel) { case 1: case 2: case 3: case 4: duration = 6; break; case 5: case 6: case 7: case 8: case 9: duration = 9; break; default: return; } if (RandomService.D100(1) <= chance) { _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, _.EffectKnockdown(), target, duration); } }
public static void HandlePlasmaCellPerk(NWPlayer player, NWObject target) { if (!player.IsPlayer) { return; } if (!_.GetHasFeat(Feat.PlasmaCell, player)) { return; // Check if player has the perk } if (player.RightHand.CustomItemType != CustomItemType.BlasterPistol && player.RightHand.CustomItemType != CustomItemType.BlasterRifle) { return; // Check if player has the right weapons } if (GetLocalBool(target, "TRANQUILIZER_EFFECT_FIRST_RUN") == true) { return; // Check if Tranquilizer is on to avoid conflict } if (GetLocalBool(player, "PLASMA_CELL_TOGGLE_OFF") == true) { return; // Check if Plasma Cell toggle is on or off } if (GetLocalBool(target, "TRANQUILIZER_EFFECT_FIRST_RUN") == true) { return; } int perkLevel = PerkService.GetCreaturePerkLevel(player, PerkType.PlasmaCell); int chance; CustomEffectType[] damageTypes; switch (perkLevel) { case 1: chance = 10; damageTypes = new[] { CustomEffectType.FireCell }; break; case 2: chance = 10; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell }; break; case 3: chance = 20; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell }; break; case 4: chance = 20; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell }; break; case 5: chance = 30; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell }; break; case 6: chance = 30; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell }; break; case 7: chance = 40; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell }; break; case 8: chance = 40; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell }; break; case 9: chance = 50; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell }; break; case 10: chance = 50; damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell, CustomEffectType.DivineCell }; break; default: return; } foreach (var effect in damageTypes) { if (RandomService.D100(1) <= chance) { CustomEffectService.ApplyCustomEffect(player, target.Object, effect, RandomService.D6(1), perkLevel, null); } } }
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 + ")")); } }
/// <summary> /// Calculates ability resistance for an ability. /// The attacker and defender's skills, ability modifiers, and balance affinity will be /// used to make this determination. /// </summary> /// <param name="attacker">The creature using the ability.</param> /// <param name="defender">The creature being targeted by the ability.</param> /// <param name="skill">The skill used for this ability.</param> /// <param name="balanceType">The force balance type to use for this ability.</param> /// <param name="sendRollMessage">If true, the roll message will be sent. Otherwise it won't be.</param> /// <returns>Data regarding the ability resistance roll</returns> public static AbilityResistanceResult CalculateAbilityResistance(NWCreature attacker, NWCreature defender, SkillType skill, ForceBalanceType balanceType, bool sendRollMessage = true) { int abilityScoreType; switch (skill) { case SkillType.ForceAlter: abilityScoreType = ABILITY_INTELLIGENCE; break; case SkillType.ForceControl: abilityScoreType = ABILITY_WISDOM; break; case SkillType.ForceSense: abilityScoreType = ABILITY_CHARISMA; break; default: throw new ArgumentException("Invalid skill type called for " + nameof(CalculateAbilityResistance) + ", value '" + skill + "' not supported."); } AbilityResistanceResult result = new AbilityResistanceResult(); int attackerSkill = SkillService.GetPCSkillRank(attacker.Object, skill); int attackerAbility = _.GetAbilityModifier(abilityScoreType, attacker); int defenderSkill = SkillService.GetPCSkillRank(defender.Object, skill); int defenderAbility = _.GetAbilityModifier(abilityScoreType, defender); // If the defender is equipped with a lightsaber, we check their lightsaber skill if (defender.RightHand.CustomItemType == CustomItemType.Lightsaber || defender.LeftHand.CustomItemType == CustomItemType.Lightsaber) { int lightsaberSkill = SkillService.GetPCSkillRank(defender.Object, SkillType.Lightsaber); if (lightsaberSkill > defenderSkill) { defenderSkill = lightsaberSkill; } } // If the defender's martial arts skill is greater than the current skill they're using, we'll use that instead. int defenderMASkill = SkillService.GetPCSkillRank(defender.Object, SkillType.MartialArts); if (defenderMASkill > defenderSkill) { defenderSkill = defenderMASkill; } int attackerAffinity = 0; int defenderAffinity = 0; // Only check affinity if ability has a force balance type. if (balanceType == ForceBalanceType.Dark || balanceType == ForceBalanceType.Light) { attackerAffinity = GetBalanceAffinity(attacker.Object, balanceType); defenderAffinity = GetBalanceAffinity(defender.Object, balanceType); } float attackerCR = attacker.IsPlayer ? 0f : attacker.ChallengeRating * 5f; float defenderCR = defender.IsPlayer ? 0f : defender.ChallengeRating * 5f; float attackerTotal = attackerSkill + attackerAbility + attackerAffinity + attackerCR; float defenderTotal = defenderSkill + defenderAbility + defenderAffinity + defenderCR; float divisor = attackerTotal + defenderTotal + 1; // +1 to prevent division by zero. //Console.WriteLine("attackerCR = " + attackerCR); //Console.WriteLine("defenderCR = " + defenderCR); //Console.WriteLine("attackerSkill = " + attackerSkill); //Console.WriteLine("attackerAbility = " + attackerAbility); //Console.WriteLine("attackerAffinity = " + attackerAffinity); //Console.WriteLine("defenderSkill = " + defenderSkill); //Console.WriteLine("defenderAbility = " + defenderAbility); //Console.WriteLine("defenderAffinity = " + defenderAffinity); //Console.WriteLine("attackerTotal = " + attackerTotal); //Console.WriteLine("defenderTotal = " + defenderTotal); //Console.WriteLine("divisor = " + divisor); result.DC = (int)(attackerTotal / divisor * 100); result.Roll = RandomService.D100(1); if (sendRollMessage) { string resisted = result.IsResisted ? ColorTokenService.Red(" [RESISTED " + Math.Abs(result.Delta) + "%]") : string.Empty; string message = ColorTokenService.SavingThrow("Roll: " + result.Roll + " VS " + result.DC + " DC") + resisted; attacker.SendMessage(message); defender.SendMessage(message); } return(result); }
public static ForceResistanceResult CalculateResistanceRating( NWCreature caster, NWCreature target, ForceAbilityType forceAbility) { int accuracy = CalculateForceAccuracy(caster, target, forceAbility); ForceResistanceResult result = new ForceResistanceResult(); // Do four checks to see if the attacker overcomes the defender's // resistance. The more checks you succeed, the lower the resistance. int successes = 0; if (RandomService.D100(1) <= accuracy) { successes++; if (RandomService.D100(1) <= accuracy) { successes++; if (RandomService.D100(1) <= accuracy) { successes++; if (RandomService.D100(1) <= accuracy) { successes++; } } } } switch (successes) { case 0: result.Amount = 0f; result.Type = ResistanceType.Full; break; case 1: result.Amount = 0.125f; result.Type = ResistanceType.Eighth; break; case 2: result.Amount = 0.25f; result.Type = ResistanceType.Fourth; break; case 3: result.Amount = 0.5f; result.Type = ResistanceType.Half; break; case 4: result.Amount = 1.0f; result.Type = ResistanceType.Zero; break; } return(result); }