private static void HandleStances() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWPlayer damager = data.Damager.Object; NWItem damagerWeapon = _.GetLastWeaponUsed(damager); if (damager.IsPlayer) { CustomEffectType stance = CustomEffectService.GetCurrentStanceType(damager); switch (stance) { case CustomEffectType.ShieldOath: data.AdjustAllByPercent(-0.30f); break; case CustomEffectType.PrecisionTargeting: if (damagerWeapon.CustomItemType == CustomItemType.BlasterPistol || damagerWeapon.CustomItemType == CustomItemType.BlasterRifle) { data.AdjustAllByPercent(0.20f); } break; } } NWNXDamage.SetDamageEventData(data); }
private static void HandleWeaponStatBonuses() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWPlayer player = data.Damager.Object; NWItem weapon = _.GetLastWeaponUsed(player); if (weapon.CustomItemType == CustomItemType.BlasterPistol || weapon.CustomItemType == CustomItemType.BlasterRifle) { int statBonus = (int)(player.DexterityModifier * 0.5f); data.Base += statBonus; } else if (weapon.CustomItemType == CustomItemType.Lightsaber || weapon.CustomItemType == CustomItemType.Saberstaff || weapon.GetLocalInt("LIGHTSABER") == TRUE) { int statBonus = (int)(player.CharismaModifier * 0.25f); data.Base += statBonus; } NWNXDamage.SetDamageEventData(data); }
private static void HandleRecoveryBlast() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWObject damager = data.Damager; bool isActive = damager.GetLocalInt("RECOVERY_BLAST_ACTIVE") == TRUE; damager.DeleteLocalInt("RECOVERY_BLAST_ACTIVE"); NWItem weapon = _.GetLastWeaponUsed(damager.Object); if (!isActive || weapon.CustomItemType != CustomItemType.BlasterRifle) { return; } data.Bludgeoning = 0; data.Pierce = 0; data.Slash = 0; data.Magical = 0; data.Acid = 0; data.Cold = 0; data.Divine = 0; data.Electrical = 0; data.Fire = 0; data.Negative = 0; data.Positive = 0; data.Sonic = 0; data.Base = 0; NWNXDamage.SetDamageEventData(data); }
private static void HandleTranquilizerEffect() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWObject self = NWGameObject.OBJECT_SELF; // Ignore the first damage because it occurred during the application of the effect. if (self.GetLocalInt("TRANQUILIZER_EFFECT_FIRST_RUN") > 0) { self.DeleteLocalInt("TRANQUILIZER_EFFECT_FIRST_RUN"); return; } for (Effect effect = _.GetFirstEffect(self.Object); _.GetIsEffectValid(effect) == TRUE; effect = _.GetNextEffect(self.Object)) { if (_.GetEffectTag(effect) == "TRANQUILIZER_EFFECT") { _.RemoveEffect(self, effect); } } }
private static void OnModuleApplyDamage() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWPlayer player = data.Damager.Object; NWCreature target = NWGameObject.OBJECT_SELF; int attackType = target.GetLocalInt(AbilityService.LAST_ATTACK + player.GlobalID); LoggingService.Trace(TraceComponent.LastAttack, "Last attack from " + player.GlobalID + " on " + _.GetName(target) + " was type " + attackType); if (attackType == AbilityService.ATTACK_PHYSICAL) { // Only apply bonus damage from physical attacks. HandleWeaponStatBonuses(); HandleEvadeOrDeflectBlasterFire(); HandleApplySneakAttackDamage(); } HandleDamageImmunity(); HandleAbsorptionFieldEffect(); HandleRecoveryBlast(); HandleTranquilizerEffect(); HandleStances(); }
private static void OnModuleApplyDamage() { var data = NWNXDamage.GetDamageEventData(); if (data.Base <= 0) { return; } NWObject damager = data.Damager; if (!damager.IsPlayer) { return; } NWCreature target = NWGameObject.OBJECT_SELF; // Check that this was a normal attack, and not (say) a damage over time effect. if (target.GetLocalInt(AbilityService.LAST_ATTACK + damager.GlobalID) != AbilityService.ATTACK_PHYSICAL) { return; } NWItem weapon = (_.GetLastWeaponUsed(damager.Object)); int damageBonus = weapon.DamageBonus; NWPlayer player = (damager.Object); int itemLevel = weapon.RecommendedLevel; SkillType skill = ItemService.GetSkillTypeForItem(weapon); if (skill == SkillType.Unknown) { return; } int rank = SkillService.GetPCSkillRank(player, skill); int delta = itemLevel - rank; if (delta >= 1) { damageBonus--; } damageBonus = damageBonus - delta / 5; if (damageBonus <= 0) { damageBonus = 0; } data.Base += damageBonus; NWNXDamage.SetDamageEventData(data); }
private static void HandleApplySneakAttackDamage() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWObject damager = data.Damager; int sneakAttackType = damager.GetLocalInt("SNEAK_ATTACK_ACTIVE"); if (damager.IsPlayer && sneakAttackType > 0) { NWPlayer player = damager.Object; NWCreature target = _.OBJECT_SELF; var pcPerk = PerkService.GetPCPerkByID(damager.GlobalID, (int)PerkType.SneakAttack); int perkRank = pcPerk?.PerkLevel ?? 0; int perkBonus = 1; // Rank 4 increases damage bonus by 2x (total: 3x) if (perkRank == 4) { perkBonus = 2; } float perkRate; if (sneakAttackType == 1) // Player is behind target. { perkRate = 1.0f * perkBonus; } else // Player is anywhere else. { perkRate = 0.5f * perkBonus; } var effectiveStats = PlayerStatService.GetPlayerItemEffectiveStats(player); float damageRate = 1.0f + perkRate + effectiveStats.SneakAttack * 0.05f; data.Base = (int)(data.Base * damageRate); if (target.IsNPC) { EnmityService.AdjustEnmity(target, player, 5 * data.Base); } NWNXDamage.SetDamageEventData(data); } damager.DeleteLocalInt("SNEAK_ATTACK_ACTIVE"); }
private static void HandleAbsorptionFieldEffect() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWObject target = NWGameObject.OBJECT_SELF; if (!target.IsPlayer) { return; } NWPlayer player = target.Object; int effectLevel = CustomEffectService.GetCustomEffectLevel(player, CustomEffectType.AbsorptionField); if (effectLevel <= 0) { return; } // Remove effect if player activates ability and removes the armor. if (player.Chest.CustomItemType != CustomItemType.ForceArmor) { CustomEffectService.RemovePCCustomEffect(player, CustomEffectType.AbsorptionField); } float absorptionRate = effectLevel * 0.1f; int absorbed = (int)(data.Total * absorptionRate); if (absorbed < 1) { absorbed = 1; } AbilityService.RestorePlayerFP(player, absorbed); }
private static void SetModuleEventScripts() { // Vanilla NWN Event Hooks _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_ACQUIRE_ITEM, "mod_on_acquire"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_ACTIVATE_ITEM, "mod_on_activate"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_CLIENT_ENTER, "mod_on_enter"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_CLIENT_EXIT, "mod_on_leave"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_CANCEL_CUTSCENE, "mod_on_csabort"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_HEARTBEAT, "mod_on_heartbeat"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_CHAT, "mod_on_chat"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_DEATH, "mod_on_death"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_DYING, "mod_on_dying"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_EQUIP_ITEM, "mod_on_equip"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_LEVEL_UP, "mod_on_levelup"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_RESPAWN_BUTTON_PRESSED, "mod_on_respawn"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_PLAYER_REST, "mod_on_rest"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_UNEQUIP_ITEM, "mod_on_unequip"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_LOSE_ITEM, "mod_on_unacquire"); _.SetEventScript(_.GetModule(), _.EVENT_SCRIPT_MODULE_ON_USER_DEFINED_EVENT, "mod_on_user"); // NWNX Hooks NWNXEvents.SubscribeEvent(EventType.StartCombatRoundBefore, "mod_on_attack"); NWNXEvents.SubscribeEvent(EventType.ExamineObjectBefore, "mod_on_examine"); NWNXEvents.SubscribeEvent(EventType.UseFeatBefore, "mod_on_usefeat"); NWNXEvents.SubscribeEvent(EventType.EnterStealthAfter, "mod_on_entstlth"); NWNXDamage.SetDamageEventScript("mod_on_applydmg"); // DM Hooks NWNXEvents.SubscribeEvent(EventType.DMAppearBefore, "dm_appear"); NWNXEvents.SubscribeEvent(EventType.DMChangeDifficultyBefore, "dm_change_diff"); NWNXEvents.SubscribeEvent(EventType.DMDisableTrapBefore, "dm_disab_trap"); NWNXEvents.SubscribeEvent(EventType.DMDisappearBefore, "dm_disappear"); NWNXEvents.SubscribeEvent(EventType.DMForceRestBefore, "dm_force_rest"); NWNXEvents.SubscribeEvent(EventType.DMGetVariableBefore, "dm_get_var"); NWNXEvents.SubscribeEvent(EventType.DMGiveGoldBefore, "dm_give_gold"); NWNXEvents.SubscribeEvent(EventType.DMGiveItemBefore, "dm_give_item"); NWNXEvents.SubscribeEvent(EventType.DMGiveLevelBefore, "dm_give_level"); NWNXEvents.SubscribeEvent(EventType.DMGiveXPBefore, "dm_give_xp"); NWNXEvents.SubscribeEvent(EventType.DMHealBefore, "dm_heal"); NWNXEvents.SubscribeEvent(EventType.DMJumpBefore, "dm_jump"); NWNXEvents.SubscribeEvent(EventType.DMJumpAllPlayersToPointBefore, "dm_jump_all"); NWNXEvents.SubscribeEvent(EventType.DMJumpTargetToPointBefore, "dm_jump_target"); NWNXEvents.SubscribeEvent(EventType.DMKillBefore, "dm_kill"); NWNXEvents.SubscribeEvent(EventType.DMLimboBefore, "dm_limbo"); NWNXEvents.SubscribeEvent(EventType.DMPossessBefore, "dm_possess"); NWNXEvents.SubscribeEvent(EventType.DMSetDateBefore, "dm_set_date"); NWNXEvents.SubscribeEvent(EventType.DMSetStatBefore, "dm_set_stat"); NWNXEvents.SubscribeEvent(EventType.DMSetTimeBefore, "dm_set_time"); NWNXEvents.SubscribeEvent(EventType.DMSetVariableBefore, "dm_set_var"); NWNXEvents.SubscribeEvent(EventType.DMSpawnCreatureAfter, "dm_spawn_crea"); NWNXEvents.SubscribeEvent(EventType.DMSpawnEncounterAfter, "dm_spawn_enco"); NWNXEvents.SubscribeEvent(EventType.DMSpawnItemAfter, "dm_spawn_item"); NWNXEvents.SubscribeEvent(EventType.DMSpawnPlaceableAfter, "dm_spawn_plac"); NWNXEvents.SubscribeEvent(EventType.DMSpawnPortalAfter, "dm_spawn_port"); NWNXEvents.SubscribeEvent(EventType.DMSpawnTrapOnObjectAfter, "dm_spawn_trap"); NWNXEvents.SubscribeEvent(EventType.DMSpawnTriggerAfter, "dm_spawn_trigg"); NWNXEvents.SubscribeEvent(EventType.DMSpawnWaypointAfter, "dm_spawn_wayp"); NWNXEvents.SubscribeEvent(EventType.DMTakeItemBefore, "dm_take_item"); NWNXEvents.SubscribeEvent(EventType.DMToggleImmortalBefore, "dm_togg_immo"); NWNXEvents.SubscribeEvent(EventType.DMToggleAIBefore, "dm_toggle_ai"); NWNXEvents.SubscribeEvent(EventType.DMToggleLockBefore, "dm_toggle_lock"); }
private static void OnModuleApplyDamage() { var data = NWNXDamage.GetDamageEventData(); if (data.Base <= 0) { return; } NWObject damager = data.Damager; if (!damager.IsPlayer) { return; } NWCreature target = _.OBJECT_SELF; // Check that this was a normal attack, and not (say) a damage over time effect. if (target.GetLocalInt(AbilityService.LAST_ATTACK + damager.GlobalID) != AbilityService.ATTACK_PHYSICAL) { return; } NWItem weapon = (_.GetLastWeaponUsed(damager.Object)); if (!weapon.IsValid) { // Double weapons don't show up correctly when their offhand makes an attack. // So check for that case here. if (_.GetObjectType(damager) == ObjectType.Creature) { NWCreature attacker = data.Damager.Object; if (attacker.RightHand.BaseItemType == BaseItem.Saberstaff || attacker.RightHand.BaseItemType == BaseItem.TwoBladedSword || attacker.RightHand.BaseItemType == BaseItem.DoubleAxe || attacker.RightHand.BaseItemType == BaseItem.DireMace) { weapon = attacker.RightHand; } } } int damageBonus = weapon.DamageBonus; NWPlayer player = (damager.Object); int itemLevel = weapon.RecommendedLevel; SkillType skill = ItemService.GetSkillTypeForItem(weapon); if (skill == SkillType.Unknown) { return; } int rank = SkillService.GetPCSkillRank(player, skill); int delta = itemLevel - rank; if (delta >= 1) { damageBonus--; } damageBonus = damageBonus - delta / 5; if (damageBonus <= 0) { damageBonus = 0; } data.Base += damageBonus; NWNXDamage.SetDamageEventData(data); }
private static void SetModuleEventScripts() { // Vanilla NWN Event Hooks _.SetEventScript(_.GetModule(), EventScript.Module_OnAcquireItem, "mod_on_acquire"); _.SetEventScript(_.GetModule(), EventScript.Module_OnActivateItem, "mod_on_activate"); _.SetEventScript(_.GetModule(), EventScript.Module_OnClientEnter, "mod_on_enter"); _.SetEventScript(_.GetModule(), EventScript.Module_OnClientExit, "mod_on_leave"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerCancelCutscene, "mod_on_csabort"); _.SetEventScript(_.GetModule(), EventScript.Module_OnHeartbeat, "mod_on_heartbeat"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerChat, "mod_on_chat"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerDeath, "mod_on_death"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerDying, "mod_on_dying"); _.SetEventScript(_.GetModule(), EventScript.Module_OnEquipItem, "mod_on_equip"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerLevelUp, "mod_on_levelup"); _.SetEventScript(_.GetModule(), EventScript.Module_OnRespawnButtonPressed, "mod_on_respawn"); _.SetEventScript(_.GetModule(), EventScript.Module_OnPlayerRest, "mod_on_rest"); _.SetEventScript(_.GetModule(), EventScript.Module_OnUnequipItem, "mod_on_unequip"); _.SetEventScript(_.GetModule(), EventScript.Module_OnLoseItem, "mod_on_unacquire"); _.SetEventScript(_.GetModule(), EventScript.Module_OnUserDefined, "mod_on_user"); // NWNX Hooks NWNXEvents.SubscribeEvent(EventType.StartCombatRoundBefore, "mod_on_attack"); NWNXEvents.SubscribeEvent(EventType.ExamineObjectBefore, "mod_on_examine"); NWNXEvents.SubscribeEvent(EventType.UseFeatBefore, "mod_on_usefeat"); NWNXEvents.SubscribeEvent(EventType.EnterStealthAfter, "mod_on_entstlth"); NWNXEvents.SubscribeEvent(EventType.DecrementItemStackSizeBefore, "item_dec_stack"); NWNXEvents.SubscribeEvent(EventType.UseItemBefore, "item_use_before"); NWNXEvents.SubscribeEvent(EventType.UseItemAfter, "item_use_after"); NWNXEvents.SubscribeEvent(EventType.ItemInventoryRemoveItemAfter, "item_inventory_disturb_after"); NWNXEvents.SubscribeEvent(EventType.ItemInventoryAddItemAfter, "item_inventory_disturb_after"); NWNXDamage.SetDamageEventScript("mod_on_applydmg"); // DM Hooks NWNXEvents.SubscribeEvent(EventType.DMAppearBefore, "dm_appear"); NWNXEvents.SubscribeEvent(EventType.DMChangeDifficultyBefore, "dm_change_diff"); NWNXEvents.SubscribeEvent(EventType.DMDisableTrapBefore, "dm_disab_trap"); NWNXEvents.SubscribeEvent(EventType.DMDisappearBefore, "dm_disappear"); NWNXEvents.SubscribeEvent(EventType.DMForceRestBefore, "dm_force_rest"); NWNXEvents.SubscribeEvent(EventType.DMGetVariableBefore, "dm_get_var"); NWNXEvents.SubscribeEvent(EventType.DMGiveGoldBefore, "dm_give_gold"); NWNXEvents.SubscribeEvent(EventType.DMGiveItemBefore, "dm_give_item"); NWNXEvents.SubscribeEvent(EventType.DMGiveLevelBefore, "dm_give_level"); NWNXEvents.SubscribeEvent(EventType.DMGiveXPBefore, "dm_give_xp"); NWNXEvents.SubscribeEvent(EventType.DMHealBefore, "dm_heal"); NWNXEvents.SubscribeEvent(EventType.DMJumpBefore, "dm_jump"); NWNXEvents.SubscribeEvent(EventType.DMJumpAllPlayersToPointBefore, "dm_jump_all"); NWNXEvents.SubscribeEvent(EventType.DMJumpTargetToPointBefore, "dm_jump_target"); NWNXEvents.SubscribeEvent(EventType.DMKillBefore, "dm_kill"); NWNXEvents.SubscribeEvent(EventType.DMLimboBefore, "dm_limbo"); NWNXEvents.SubscribeEvent(EventType.DMPossessBefore, "dm_possess"); NWNXEvents.SubscribeEvent(EventType.DMSetDateBefore, "dm_set_date"); NWNXEvents.SubscribeEvent(EventType.DMSetStatBefore, "dm_set_stat"); NWNXEvents.SubscribeEvent(EventType.DMSetTimeBefore, "dm_set_time"); NWNXEvents.SubscribeEvent(EventType.DMSetVariableBefore, "dm_set_var"); NWNXEvents.SubscribeEvent(EventType.DMSpawnCreatureAfter, "dm_spawn_crea"); NWNXEvents.SubscribeEvent(EventType.DMSpawnEncounterAfter, "dm_spawn_enco"); NWNXEvents.SubscribeEvent(EventType.DMSpawnItemAfter, "dm_spawn_item"); NWNXEvents.SubscribeEvent(EventType.DMSpawnPlaceableAfter, "dm_spawn_plac"); NWNXEvents.SubscribeEvent(EventType.DMSpawnPortalAfter, "dm_spawn_port"); NWNXEvents.SubscribeEvent(EventType.DMSpawnTrapOnObjectAfter, "dm_spawn_trap"); NWNXEvents.SubscribeEvent(EventType.DMSpawnTriggerAfter, "dm_spawn_trigg"); NWNXEvents.SubscribeEvent(EventType.DMSpawnWaypointAfter, "dm_spawn_wayp"); NWNXEvents.SubscribeEvent(EventType.DMTakeItemBefore, "dm_take_item"); NWNXEvents.SubscribeEvent(EventType.DMToggleImmortalBefore, "dm_togg_immo"); NWNXEvents.SubscribeEvent(EventType.DMToggleAIBefore, "dm_toggle_ai"); NWNXEvents.SubscribeEvent(EventType.DMToggleLockBefore, "dm_toggle_lock"); }
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 + ")")); } }
private static void HandleDamageImmunity() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWCreature target = NWGameObject.OBJECT_SELF; NWItem shield = target.LeftHand; var concentrationEffect = AbilityService.GetActiveConcentrationEffect(target); double reduction = 0.0f; // Shield damage reduction and absorb energy are calculated here. They don't stack, so the one // with the highest reduction will take precedence. // Calculate shield damage reduction. if (ItemService.ShieldBaseItemTypes.Contains(shield.BaseItemType)) { // Apply damage scaling based on shield presence int perkLevel = PerkService.GetCreaturePerkLevel(target.Object, PerkType.ShieldProficiency); float perkBonus = 0.02f * perkLevel; // DI = 10% + 1% / 3 AC bonuses on the shield + 2% per perk bonus. reduction = (0.1 + 0.01 * shield.AC / 3) + perkBonus; } // Calculate Absorb Energy concentration effect reduction. if (concentrationEffect.Type == PerkType.AbsorbEnergy) { double perkReduction = concentrationEffect.Tier * 0.1; if (perkReduction > reduction) { reduction = perkReduction; // Calculate and award force XP based on total damage reduced. int xp = (int)(data.Total * reduction * 3); if (xp < 5) { xp = 5; } SkillService.GiveSkillXP(target.Object, SkillType.ForceControl, xp); // Play a visual effect signifying the ability was activated. _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_BLUR), target, 0.5f); } } // No reduction found. Bail out early. if (reduction <= 0.0f) { return; } target.SendMessage("Damage reduced by " + (int)(reduction * 100) + "%"); reduction = 1.0f - reduction; data.Bludgeoning = (int)(data.Bludgeoning * reduction); data.Pierce = (int)(data.Pierce * reduction); data.Slash = (int)(data.Slash * reduction); data.Magical = (int)(data.Magical * reduction); data.Acid = (int)(data.Acid * reduction); data.Cold = (int)(data.Cold * reduction); data.Divine = (int)(data.Divine * reduction); data.Electrical = (int)(data.Electrical * reduction); data.Fire = (int)(data.Fire * reduction); data.Negative = (int)(data.Negative * reduction); data.Positive = (int)(data.Positive * reduction); data.Sonic = (int)(data.Sonic * reduction); data.Base = (int)(data.Base * reduction); NWNXDamage.SetDamageEventData(data); }
private static void HandleBattlemagePerk() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Base <= 0) { return; } NWObject target = Object.OBJECT_SELF; if (!data.Damager.IsPlayer || !target.IsNPC) { return; } if (_.GetHasFeat((int)CustomFeatType.Battlemage, data.Damager.Object) == FALSE) { return; } NWPlayer player = data.Damager.Object; NWItem weapon = _.GetLastWeaponUsed(player.Object); if (weapon.CustomItemType != CustomItemType.Baton) { return; } if (player.Chest.CustomItemType != CustomItemType.ForceArmor) { return; } int perkRank = PerkService.GetPCPerkLevel(player, PerkType.Battlemage); int restoreAmount = 0; bool metRoll = RandomService.Random(100) + 1 <= 50; switch (perkRank) { case 1 when metRoll: restoreAmount = 1; break; case 2: restoreAmount = 1; break; case 3: restoreAmount = 1; if (metRoll) { restoreAmount++; } break; case 4: restoreAmount = 2; break; case 5: restoreAmount = 2; if (metRoll) { restoreAmount++; } break; case 6: restoreAmount = 3; break; } if (restoreAmount > 0) { AbilityService.RestoreFP(player, restoreAmount); } }