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 OnHitCastSpell() { NWPlayer oPC = Object.OBJECT_SELF; if (!oPC.IsValid || !oPC.IsPlayer) { return; } NWItem oSpellOrigin = (_.GetSpellCastItem()); NWCreature oTarget = (_.GetSpellTargetObject()); SkillType skillType = ItemService.GetSkillTypeForItem(oSpellOrigin); if (skillType == SkillType.Unknown || skillType == SkillType.LightArmor || skillType == SkillType.HeavyArmor || skillType == SkillType.ForceArmor || skillType == SkillType.Shields) { return; } if (oTarget.IsPlayer || oTarget.IsDM) { return; } if (oTarget.ObjectType != OBJECT_TYPE_CREATURE) { return; } int skillID = (int)skillType; CreatureSkillRegistration reg = GetCreatureSkillRegistration(oTarget.GlobalID); int rank = GetPCSkillRank(oPC, skillID); reg.AddSkillRegistrationPoint(oPC, skillID, oSpellOrigin.RecommendedLevel, rank); // Add a registration point if a shield is equipped. This is to prevent players from swapping out a weapon for a shield // just before they kill an enemy. NWItem oShield = oPC.LeftHand; if (oShield.BaseItemType == BASE_ITEM_SMALLSHIELD || oShield.BaseItemType == BASE_ITEM_LARGESHIELD || oShield.BaseItemType == BASE_ITEM_TOWERSHIELD) { rank = GetPCSkillRank(oPC, SkillType.Shields); reg.AddSkillRegistrationPoint(oPC, (int)SkillType.Shields, oShield.RecommendedLevel, rank); } }
private static void CalculateEffectiveStats(NWPlayer player, NWItem item) { if (item == null || !item.IsValid || !player.IsPlayer || player.IsDMPossessed || player.IsDM || !player.IsInitializedAsPlayer) { return; } // Calculating effective stats can be expensive, so we cache it on the item. SkillType skill = ItemService.GetSkillTypeForItem(item); var rank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)skill).Rank; using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::CalculateEffectiveStats")) { // Only scale cooldown recovery if it's a bonus. Penalties remain regardless of skill level difference. item.SetLocalInt("STAT_EFFECTIVE_LEVEL_COOLDOWN_RECOVERY", item.CooldownRecovery > 0 ? CalculateAdjustedValue(item.CooldownRecovery, item.RecommendedLevel, rank, 1) : item.CooldownRecovery); item.SetLocalFloat("STAT_EFFECTIVE_LEVEL_ENMITY_RATE", CalculateAdjustedValue(0.01f * item.EnmityRate, item.RecommendedLevel, rank, 0.00f)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_LUCK_BONUS", CalculateAdjustedValue(item.LuckBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_MEDITATE_BONUS", CalculateAdjustedValue(item.MeditateBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_REST_BONUS", CalculateAdjustedValue(item.RestBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_MEDICINE_BONUS", CalculateAdjustedValue(item.MedicineBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HP_REGEN_BONUS", CalculateAdjustedValue(item.HPRegenBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FP_REGEN_BONUS", CalculateAdjustedValue(item.FPRegenBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_WEAPONSMITH_BONUS", CalculateAdjustedValue(item.CraftBonusWeaponsmith, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_COOKING_BONUS", CalculateAdjustedValue(item.CraftBonusCooking, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_ENGINEERING_BONUS", CalculateAdjustedValue(item.CraftBonusEngineering, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FABRICATION_BONUS", CalculateAdjustedValue(item.CraftBonusFabrication, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_ARMORSMITH_BONUS", CalculateAdjustedValue(item.CraftBonusArmorsmith, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HARVESTING_BONUS", CalculateAdjustedValue(item.HarvestingBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_PILOTING_BONUS", CalculateAdjustedValue(item.PilotingBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_SCAVENGING_BONUS", CalculateAdjustedValue(item.ScavengingBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_SNEAK_ATTACK_BONUS", CalculateAdjustedValue(item.SneakAttackBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_STRENGTH_BONUS", CalculateAdjustedValue(item.StrengthBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_DEXTERITY_BONUS", CalculateAdjustedValue(item.DexterityBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_CONSTITUTION_BONUS", CalculateAdjustedValue(item.ConstitutionBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_WISDOM_BONUS", CalculateAdjustedValue(item.WisdomBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_INTELLIGENCE_BONUS", CalculateAdjustedValue(item.IntelligenceBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_CHARISMA_BONUS", CalculateAdjustedValue(item.CharismaBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HP_BONUS", CalculateAdjustedValue(item.HPBonus, item.RecommendedLevel, rank, 0)); item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FP_BONUS", CalculateAdjustedValue(item.FPBonus, item.RecommendedLevel, rank, 0)); } }
private static void RemoveWeaponPenalties(NWItem oItem) { SkillType skillType = ItemService.GetSkillTypeForItem(oItem); if (skillType == SkillType.Unknown || skillType == SkillType.HeavyArmor || skillType == SkillType.LightArmor || skillType == SkillType.ForceArmor || skillType == SkillType.Shields) { return; } foreach (ItemProperty ip in oItem.ItemProperties) { string tag = _.GetItemPropertyTag(ip); if (tag == IPWeaponPenaltyTag) { _.RemoveItemProperty(oItem.Object, ip); } } }
private static int CalculateBAB(NWPlayer oPC, NWItem ignoreItem, EffectiveItemStats stats) { NWItem weapon = oPC.RightHand; // The unequip event fires before the item is actually unequipped, so we need // to have additional checks to make sure we're not getting the weapon that's about to be // unequipped. if (weapon.Equals(ignoreItem)) { weapon = null; NWItem offHand = oPC.LeftHand; if (offHand.CustomItemType == CustomItemType.Vibroblade || offHand.CustomItemType == CustomItemType.FinesseVibroblade || offHand.CustomItemType == CustomItemType.Baton || offHand.CustomItemType == CustomItemType.HeavyVibroblade || offHand.CustomItemType == CustomItemType.Saberstaff || offHand.CustomItemType == CustomItemType.Polearm || offHand.CustomItemType == CustomItemType.TwinBlade || offHand.CustomItemType == CustomItemType.MartialArtWeapon || offHand.CustomItemType == CustomItemType.BlasterPistol || offHand.CustomItemType == CustomItemType.BlasterRifle || offHand.CustomItemType == CustomItemType.Throwing) { weapon = offHand; } } if (weapon == null || !weapon.IsValid) { weapon = oPC.Arms; } if (!weapon.IsValid) { return(0); } SkillType itemSkill = ItemService.GetSkillTypeForItem(weapon); if (itemSkill == SkillType.Unknown || itemSkill == SkillType.LightArmor || itemSkill == SkillType.HeavyArmor || itemSkill == SkillType.ForceArmor || itemSkill == SkillType.Shields) { return(0); } int weaponSkillID = (int)itemSkill; PCSkill skill = DataService.Single <PCSkill>(x => x.PlayerID == oPC.GlobalID && x.SkillID == weaponSkillID); if (skill == null) { return(0); } int skillBAB = skill.Rank / 10; int perkBAB = 0; int backgroundBAB = 0; BackgroundType background = (BackgroundType)oPC.Class1; bool receivesBackgroundBonus = false; // Apply increased BAB if player is using a weapon for which they have a proficiency. PerkType proficiencyPerk = PerkType.Unknown; SkillType proficiencySkill = SkillType.Unknown; switch (weapon.CustomItemType) { case CustomItemType.Vibroblade: proficiencyPerk = PerkType.VibrobladeProficiency; proficiencySkill = SkillType.OneHanded; break; case CustomItemType.FinesseVibroblade: proficiencyPerk = PerkType.FinesseVibrobladeProficiency; proficiencySkill = SkillType.OneHanded; receivesBackgroundBonus = background == BackgroundType.Duelist; break; case CustomItemType.Baton: proficiencyPerk = PerkType.BatonProficiency; proficiencySkill = SkillType.OneHanded; receivesBackgroundBonus = background == BackgroundType.SecurityOfficer; break; case CustomItemType.HeavyVibroblade: proficiencyPerk = PerkType.HeavyVibrobladeProficiency; proficiencySkill = SkillType.TwoHanded; receivesBackgroundBonus = background == BackgroundType.Soldier; break; case CustomItemType.Saberstaff: proficiencyPerk = PerkType.SaberstaffProficiency; proficiencySkill = SkillType.Lightsaber; break; case CustomItemType.Polearm: proficiencyPerk = PerkType.PolearmProficiency; proficiencySkill = SkillType.TwoHanded; break; case CustomItemType.TwinBlade: proficiencyPerk = PerkType.TwinVibrobladeProficiency; proficiencySkill = SkillType.TwinBlades; receivesBackgroundBonus = background == BackgroundType.Berserker; break; case CustomItemType.MartialArtWeapon: proficiencyPerk = PerkType.MartialArtsProficiency; proficiencySkill = SkillType.MartialArts; receivesBackgroundBonus = background == BackgroundType.TerasKasi; break; case CustomItemType.BlasterPistol: proficiencyPerk = PerkType.BlasterPistolProficiency; proficiencySkill = SkillType.Firearms; receivesBackgroundBonus = background == BackgroundType.Smuggler; break; case CustomItemType.BlasterRifle: proficiencyPerk = PerkType.BlasterRifleProficiency; proficiencySkill = SkillType.Firearms; receivesBackgroundBonus = background == BackgroundType.Sharpshooter || background == BackgroundType.Mandalorian; break; case CustomItemType.Throwing: proficiencyPerk = PerkType.ThrowingProficiency; proficiencySkill = SkillType.Throwing; break; case CustomItemType.Lightsaber: proficiencyPerk = PerkType.LightsaberProficiency; proficiencySkill = SkillType.Lightsaber; break; } if (weapon.GetLocalInt("LIGHTSABER") == TRUE) { proficiencyPerk = PerkType.LightsaberProficiency; proficiencySkill = SkillType.Lightsaber; } if (proficiencyPerk != PerkType.Unknown && proficiencySkill != SkillType.Unknown) { perkBAB += PerkService.GetPCPerkLevel(oPC, proficiencyPerk); } if (receivesBackgroundBonus) { backgroundBAB = background == BackgroundType.Mandalorian ? 1 : 2; } return(1 + skillBAB + perkBAB + stats.BAB + backgroundBAB); // Note: Always add 1 to BAB. 0 will cause a crash in NWNX. }
public static EffectiveItemStats GetPlayerItemEffectiveStats(NWPlayer player, NWItem ignoreItem = null) { using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats")) { var pcSkills = DataService.Where <PCSkill>(x => x.PlayerID == player.GlobalID); int heavyRank = pcSkills.Single(x => x.SkillID == (int)SkillType.HeavyArmor).Rank; int lightRank = pcSkills.Single(x => x.SkillID == (int)SkillType.LightArmor).Rank; int forceRank = pcSkills.Single(x => x.SkillID == (int)SkillType.ForceArmor).Rank; int martialRank = pcSkills.Single(x => x.SkillID == (int)SkillType.MartialArts).Rank; EffectiveItemStats stats = new EffectiveItemStats(); stats.EnmityRate = 1.0f; using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop")) { HashSet <NWItem> processed = new HashSet <NWItem>(); for (int itemSlot = 0; itemSlot < NUM_INVENTORY_SLOTS; itemSlot++) { NWItem item = _.GetItemInSlot(itemSlot, player); if (!item.IsValid || item.Equals(ignoreItem)) { continue; } SkillType skill = ItemService.GetSkillTypeForItem(item); int rank; // Have we already processed this particular item? Skip over it. // NWN likes to include the same weapon in multiple slots for some reasons, so this works around that. // If someone has a better solution to this please feel free to change it. if (processed.Contains(item)) { continue; } processed.Add(item); using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::GetRank")) { rank = pcSkills.Single(x => x.SkillID == (int)skill).Rank; } using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::StatAdjustments")) { // Only scale casting speed if it's a bonus. Penalties remain regardless of skill level difference. if (item.CastingSpeed > 0) { stats.CastingSpeed += CalculateAdjustedValue(item.CastingSpeed, item.RecommendedLevel, rank, 1); } else { stats.CastingSpeed += item.CastingSpeed; } stats.EnmityRate += CalculateAdjustedValue(0.01f * item.EnmityRate, item.RecommendedLevel, rank, 0.00f); stats.ForcePotency += CalculateAdjustedValue(item.ForcePotencyBonus, item.RecommendedLevel, rank, 0); stats.ForceDefense += CalculateAdjustedValue(item.ForceDefenseBonus, item.RecommendedLevel, rank, 0); stats.ForceAccuracy += CalculateAdjustedValue(item.ForceAccuracyBonus, item.RecommendedLevel, rank, 0); stats.ElectricalPotency += CalculateAdjustedValue(item.ElectricalPotencyBonus, item.RecommendedLevel, rank, 0); stats.MindPotency += CalculateAdjustedValue(item.MindPotencyBonus, item.RecommendedLevel, rank, 0); stats.LightPotency += CalculateAdjustedValue(item.LightPotencyBonus, item.RecommendedLevel, rank, 0); stats.DarkPotency += CalculateAdjustedValue(item.DarkPotencyBonus, item.RecommendedLevel, rank, 0); stats.ElectricalDefense += CalculateAdjustedValue(item.ElectricalDefenseBonus, item.RecommendedLevel, rank, 0); stats.MindDefense += CalculateAdjustedValue(item.MindDefenseBonus, item.RecommendedLevel, rank, 0); stats.LightDefense += CalculateAdjustedValue(item.LightDefenseBonus, item.RecommendedLevel, rank, 0); stats.DarkDefense += CalculateAdjustedValue(item.DarkDefenseBonus, item.RecommendedLevel, rank, 0); stats.Luck += CalculateAdjustedValue(item.LuckBonus, item.RecommendedLevel, rank, 0); stats.Meditate += CalculateAdjustedValue(item.MeditateBonus, item.RecommendedLevel, rank, 0); stats.Rest += CalculateAdjustedValue(item.RestBonus, item.RecommendedLevel, rank, 0); stats.Medicine += CalculateAdjustedValue(item.MedicineBonus, item.RecommendedLevel, rank, 0); stats.HPRegen += CalculateAdjustedValue(item.HPRegenBonus, item.RecommendedLevel, rank, 0); stats.FPRegen += CalculateAdjustedValue(item.FPRegenBonus, item.RecommendedLevel, rank, 0); stats.Weaponsmith += CalculateAdjustedValue(item.CraftBonusWeaponsmith, item.RecommendedLevel, rank, 0); stats.Cooking += CalculateAdjustedValue(item.CraftBonusCooking, item.RecommendedLevel, rank, 0); stats.Engineering += CalculateAdjustedValue(item.CraftBonusEngineering, item.RecommendedLevel, rank, 0); stats.Fabrication += CalculateAdjustedValue(item.CraftBonusFabrication, item.RecommendedLevel, rank, 0); stats.Armorsmith += CalculateAdjustedValue(item.CraftBonusArmorsmith, item.RecommendedLevel, rank, 0); stats.Harvesting += CalculateAdjustedValue(item.HarvestingBonus, item.RecommendedLevel, rank, 0); stats.Piloting += CalculateAdjustedValue(item.PilotingBonus, item.RecommendedLevel, rank, 0); stats.Scavenging += CalculateAdjustedValue(item.ScavengingBonus, item.RecommendedLevel, rank, 0); stats.SneakAttack += CalculateAdjustedValue(item.SneakAttackBonus, item.RecommendedLevel, rank, 0); stats.Strength += CalculateAdjustedValue(item.StrengthBonus, item.RecommendedLevel, rank, 0); stats.Dexterity += CalculateAdjustedValue(item.DexterityBonus, item.RecommendedLevel, rank, 0); stats.Constitution += CalculateAdjustedValue(item.ConstitutionBonus, item.RecommendedLevel, rank, 0); stats.Wisdom += CalculateAdjustedValue(item.WisdomBonus, item.RecommendedLevel, rank, 0); stats.Intelligence += CalculateAdjustedValue(item.IntelligenceBonus, item.RecommendedLevel, rank, 0); stats.Charisma += CalculateAdjustedValue(item.CharismaBonus, item.RecommendedLevel, rank, 0); stats.HP += CalculateAdjustedValue(item.HPBonus, item.RecommendedLevel, rank, 0); stats.FP += CalculateAdjustedValue(item.FPBonus, item.RecommendedLevel, rank, 0); } using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::CalcBAB")) { // Calculate base attack bonus int itemLevel = item.RecommendedLevel; int delta = itemLevel - rank; int itemBAB = item.BaseAttackBonus; if (delta >= 1) { itemBAB--; } if (delta > 0) { itemBAB = itemBAB - delta / 5; } if (itemBAB <= 0) { itemBAB = 0; } stats.BAB += itemBAB; } using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::CalcAC")) { // Calculate AC if (ACBaseItemTypes.Contains(item.BaseItemType)) { int skillRankToUse; if (item.CustomItemType == CustomItemType.HeavyArmor) { skillRankToUse = heavyRank; } else if (item.CustomItemType == CustomItemType.LightArmor) { skillRankToUse = lightRank; } else if (item.CustomItemType == CustomItemType.ForceArmor) { skillRankToUse = forceRank; } else if (item.CustomItemType == CustomItemType.MartialArtWeapon) { skillRankToUse = martialRank; } else { continue; } int itemAC = item.CustomAC; itemAC = CalculateAdjustedValue(itemAC, item.RecommendedLevel, skillRankToUse, 0); stats.AC += itemAC; } } } } using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::FinalAdjustments")) { // Final casting speed adjustments if (stats.CastingSpeed < -99) { stats.CastingSpeed = -99; } else if (stats.CastingSpeed > 99) { stats.CastingSpeed = 99; } // Final enmity adjustments if (stats.EnmityRate < 0.5f) { stats.EnmityRate = 0.5f; } else if (stats.EnmityRate > 1.5f) { stats.EnmityRate = 1.5f; } var stance = CustomEffectService.GetCurrentStanceType(player); if (stance == CustomEffectType.ShieldOath) { stats.EnmityRate = stats.EnmityRate + 0.2f; } return(stats); } } }
private static int CalculateBAB(NWPlayer oPC, NWItem ignoreItem, EffectiveItemStats stats) { NWItem weapon = oPC.RightHand; // The unequip event fires before the item is actually unequipped, so we need // to have additional checks to make sure we're not getting the weapon that's about to be // unequipped. if (weapon.Equals(ignoreItem)) { weapon = null; NWItem offHand = oPC.LeftHand; if (offHand.CustomItemType == CustomItemType.Vibroblade || offHand.CustomItemType == CustomItemType.FinesseVibroblade || offHand.CustomItemType == CustomItemType.Baton || offHand.CustomItemType == CustomItemType.HeavyVibroblade || offHand.CustomItemType == CustomItemType.Saberstaff || offHand.CustomItemType == CustomItemType.Polearm || offHand.CustomItemType == CustomItemType.TwinBlade || offHand.CustomItemType == CustomItemType.MartialArtWeapon || offHand.CustomItemType == CustomItemType.BlasterPistol || offHand.CustomItemType == CustomItemType.BlasterRifle || offHand.CustomItemType == CustomItemType.Throwing) { weapon = offHand; } } if (weapon == null || !weapon.IsValid) { weapon = oPC.Arms; } if (!weapon.IsValid) { return(0); } SkillType itemSkill = ItemService.GetSkillTypeForItem(weapon); if (itemSkill == SkillType.Unknown || itemSkill == SkillType.LightArmor || itemSkill == SkillType.HeavyArmor || itemSkill == SkillType.ForceArmor || itemSkill == SkillType.Shields) { return(0); } int weaponSkillID = (int)itemSkill; PCSkill skill = DataService.PCSkill.GetByPlayerIDAndSkillID(oPC.GlobalID, weaponSkillID); if (skill == null) { return(0); } int skillBAB = skill.Rank / 10; int perkBAB = 0; int backgroundBAB = 0; BackgroundType background = (BackgroundType)oPC.Class1; bool receivesBackgroundBonus = false; switch (weapon.CustomItemType) { case CustomItemType.FinesseVibroblade: receivesBackgroundBonus = background == BackgroundType.Duelist; break; case CustomItemType.Baton: receivesBackgroundBonus = background == BackgroundType.SecurityOfficer; break; case CustomItemType.HeavyVibroblade: receivesBackgroundBonus = background == BackgroundType.Soldier; break; case CustomItemType.TwinBlade: receivesBackgroundBonus = background == BackgroundType.Berserker; break; case CustomItemType.MartialArtWeapon: receivesBackgroundBonus = background == BackgroundType.TerasKasi; break; case CustomItemType.BlasterPistol: receivesBackgroundBonus = background == BackgroundType.Smuggler; break; case CustomItemType.BlasterRifle: receivesBackgroundBonus = background == BackgroundType.Sharpshooter || background == BackgroundType.Mandalorian; break; } if (receivesBackgroundBonus) { backgroundBAB = background == BackgroundType.Mandalorian ? 1 : 2; } return(1 + skillBAB + perkBAB + stats.BAB + backgroundBAB); // Note: Always add 1 to BAB. 0 will cause a crash in NWNX. }
public static EffectiveItemStats GetPlayerItemEffectiveStats(NWPlayer player, NWItem ignoreItem = null) { int heavyRank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)SkillType.HeavyArmor).Rank; int lightRank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)SkillType.LightArmor).Rank; int forceRank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)SkillType.ForceArmor).Rank; int martialRank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)SkillType.MartialArts).Rank; EffectiveItemStats stats = new EffectiveItemStats(); stats.EnmityRate = 1.0f; HashSet <NWItem> processed = new HashSet <NWItem>(); for (int itemSlot = 0; itemSlot < NumberOfInventorySlots; itemSlot++) { NWItem item = _.GetItemInSlot((InventorySlot)itemSlot, player); if (!item.IsValid || item.Equals(ignoreItem)) { continue; } // Have we already processed this particular item? Skip over it. // NWN likes to include the same weapon in multiple slots for some reasons, so this works around that. // If someone has a better solution to this please feel free to change it. if (processed.Contains(item)) { continue; } processed.Add(item); SkillType skill = ItemService.GetSkillTypeForItem(item); var rank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)skill).Rank; stats.CooldownRecovery += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_COOLDOWN_RECOVERY"); stats.EnmityRate += item.GetLocalFloat("STAT_EFFECTIVE_LEVEL_ENMITY_RATE"); stats.Luck += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_LUCK_BONUS"); stats.Meditate += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_MEDITATE_BONUS"); stats.Rest += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_REST_BONUS"); stats.Medicine += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_MEDICINE_BONUS"); stats.HPRegen += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_HP_REGEN_BONUS"); stats.FPRegen += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_FP_REGEN_BONUS"); stats.Weaponsmith += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_WEAPONSMITH_BONUS"); stats.Cooking += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_COOKING_BONUS"); stats.Engineering += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_ENGINEERING_BONUS"); stats.Fabrication += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_FABRICATION_BONUS"); stats.Armorsmith += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_ARMORSMITH_BONUS"); stats.Harvesting += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_HARVESTING_BONUS"); stats.Piloting += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_PILOTING_BONUS"); stats.Scavenging += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_SCAVENGING_BONUS"); stats.SneakAttack += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_SNEAK_ATTACK_BONUS"); stats.Strength += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_STRENGTH_BONUS"); stats.Dexterity += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_DEXTERITY_BONUS"); stats.Constitution += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_CONSTITUTION_BONUS"); stats.Wisdom += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_WISDOM_BONUS"); stats.Intelligence += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_INTELLIGENCE_BONUS"); stats.Charisma += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_CHARISMA_BONUS"); stats.HP += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_HP_BONUS"); stats.FP += item.GetLocalInt("STAT_EFFECTIVE_LEVEL_FP_BONUS"); // Calculate base attack bonus if (ItemService.WeaponBaseItemTypes.Contains(item.BaseItemType)) { int itemLevel = item.RecommendedLevel; int delta = itemLevel - rank; int itemBAB = item.BaseAttackBonus; if (delta >= 1) { itemBAB--; } if (delta > 0) { itemBAB = itemBAB - delta / 5; } if (itemBAB <= 0) { itemBAB = 0; } stats.BAB += itemBAB; } // Calculate AC if (ItemService.ArmorBaseItemTypes.Contains(item.BaseItemType)) { int skillRankToUse; int maxAC = 0; if (item.CustomItemType == CustomItemType.HeavyArmor) { skillRankToUse = heavyRank; maxAC = 10; } else if (item.CustomItemType == CustomItemType.LightArmor) { skillRankToUse = lightRank; maxAC = 13; } else if (item.CustomItemType == CustomItemType.ForceArmor) { skillRankToUse = forceRank; maxAC = 11; } else if (item.CustomItemType == CustomItemType.MartialArtWeapon) { skillRankToUse = martialRank; } else { continue; } int itemAC = item.CustomAC; itemAC = CalculateAdjustedValue(itemAC, item.RecommendedLevel, skillRankToUse, 0); if (itemAC > maxAC) { item.CustomAC = maxAC; } stats.AC += itemAC; } } // Final casting speed adjustments if (stats.CooldownRecovery < -99) { stats.CooldownRecovery = -99; } else if (stats.CooldownRecovery > 99) { stats.CooldownRecovery = 99; } // Final enmity adjustments if (stats.EnmityRate < 0.5f) { stats.EnmityRate = 0.5f; } else if (stats.EnmityRate > 1.5f) { stats.EnmityRate = 1.5f; } var stance = CustomEffectService.GetCurrentStanceType(player); if (stance == CustomEffectType.ShieldOath) { stats.EnmityRate = stats.EnmityRate + 0.2f; } return(stats); }
private static void ApplyEquipmentPenalties(NWPlayer oPC, NWItem oItem) { SkillType skill = ItemService.GetSkillTypeForItem(oItem); if (skill == SkillType.Unknown) { return; } int rank = GetPCSkillRank(oPC, skill); int delta = oItem.RecommendedLevel - rank; if (delta <= 0) { return; } int str = 0; int dex = 0; int con = 0; int wis = 0; int @int = 0; int cha = 0; int ab = 0; int eb = 0; foreach (var ip in oItem.ItemProperties) { int type = _.GetItemPropertyType(ip); int value = _.GetItemPropertyCostTableValue(ip); if (type == ITEM_PROPERTY_ABILITY_BONUS) { int abilityType = _.GetItemPropertySubType(ip); switch (abilityType) { case ABILITY_STRENGTH: str += value; break; case ABILITY_CONSTITUTION: con += value; break; case ABILITY_DEXTERITY: dex += value; break; case ABILITY_WISDOM: wis += value; break; case ABILITY_INTELLIGENCE: @int += value; break; case ABILITY_CHARISMA: cha += value; break; } } else if (type == ITEM_PROPERTY_DECREASED_ABILITY_SCORE) { int abilityType = _.GetItemPropertySubType(ip); switch (abilityType) { case ABILITY_STRENGTH: str -= value; break; case ABILITY_CONSTITUTION: con -= value; break; case ABILITY_DEXTERITY: dex -= value; break; case ABILITY_WISDOM: wis -= value; break; case ABILITY_INTELLIGENCE: @int -= value; break; case ABILITY_CHARISMA: cha -= value; break; } } else if (type == ITEM_PROPERTY_ATTACK_BONUS) { ab += value; } else if (type == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER) { ab -= value; } else if (type == ITEM_PROPERTY_ENHANCEMENT_BONUS) { eb += value; } else if (type == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER) { eb -= value; } } // Apply penalties only if total value is greater than 0. Penalties don't scale. if (str > 0) { int newStr = 1 + delta / 5; if (newStr > str) { newStr = str; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_STRENGTH, newStr); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (dex > 0) { int newDex = 1 + delta / 5; if (newDex > dex) { newDex = dex; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_DEXTERITY, newDex); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (con > 0) { int newCon = 1 + delta / 5; if (newCon > con) { newCon = con; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_CONSTITUTION, newCon); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (@int > 0) { int newInt = 1 + delta / 5; if (newInt > @int) { newInt = @int; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_INTELLIGENCE, newInt); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (wis > 0) { int newWis = 1 + delta / 5; if (newWis > wis) { newWis = wis; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_WISDOM, newWis); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (cha > 0) { int newCha = 1 + delta / 5; if (newCha > cha) { newCha = cha; } ItemProperty ip = _.ItemPropertyDecreaseAbility(ABILITY_CHARISMA, newCha); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (ab > 0) { int newAB = 1 + delta / 5; if (newAB > ab) { newAB = ab; } ItemProperty ip = _.ItemPropertyAttackPenalty(newAB); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } if (eb > 0) { int newEB = 1 + delta / 5; if (newEB > eb) { newEB = eb; } ItemProperty ip = _.ItemPropertyEnhancementPenalty(newEB); ip = _.TagItemProperty(ip, IPEquipmentPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ip, 0.0f, AddItemPropertyPolicy.IgnoreExisting, false, false); } }
private static void ApplyWeaponPenalties(NWPlayer oPC, NWItem oItem) { SkillType skillType = ItemService.GetSkillTypeForItem(oItem); if (skillType == SkillType.Unknown || skillType == SkillType.HeavyArmor || skillType == SkillType.LightArmor || skillType == SkillType.ForceArmor || skillType == SkillType.Shields) { return; } int skillID = (int)skillType; int rank = GetPCSkillRank(oPC, skillID); int recommendedRank = oItem.RecommendedLevel; if (rank >= recommendedRank) { return; } int delta = rank - recommendedRank; int penalty; if (delta <= -20) { penalty = 99; } else if (delta <= -16) { penalty = 5; } else if (delta <= -12) { penalty = 4; } else if (delta <= -8) { penalty = 3; } else if (delta <= -4) { penalty = 2; } else if (delta <= 0) { penalty = 1; } else { penalty = 99; } // No combat damage penalty if (penalty == 99) { ItemProperty noDamage = _.ItemPropertyNoDamage(); noDamage = _.TagItemProperty(noDamage, IPWeaponPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, noDamage, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false); penalty = 5; // Reset to 5 so that the following penalties apply. } // Decreased attack penalty ItemProperty ipPenalty = _.ItemPropertyAttackPenalty(penalty); ipPenalty = _.TagItemProperty(ipPenalty, IPWeaponPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ipPenalty, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false); // Decreased damage penalty ipPenalty = _.ItemPropertyDamagePenalty(penalty); ipPenalty = _.TagItemProperty(ipPenalty, IPWeaponPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ipPenalty, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false); // Decreased enhancement bonus penalty ipPenalty = _.ItemPropertyEnhancementPenalty(penalty); ipPenalty = _.TagItemProperty(ipPenalty, IPWeaponPenaltyTag); BiowareXP2.IPSafeAddItemProperty(oItem, ipPenalty, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false); oPC.SendMessage("A penalty has been applied to your weapon '" + oItem.Name + "' due to your skill being under the recommended level."); }
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); }