private static int EffectiveArmorClass(EffectiveItemStats stats, NWPlayer player) { int baseAC = stats.AC + CustomEffectService.CalculateEffectAC(player); int totalAC = _.GetAC(player) - baseAC; // Shield Oath and Precision Targeting affect a percentage of the TOTAL armor class on a creature. var stance = CustomEffectService.GetCurrentStanceType(player); if (stance == CustomEffectType.ShieldOath) { int bonus = (int)(totalAC * 0.2f); baseAC = baseAC + bonus; } else if (stance == CustomEffectType.PrecisionTargeting) { int penalty = (int)(totalAC * 0.3f); baseAC = baseAC - penalty; } if (baseAC < 0) { baseAC = 0; } return(baseAC); }
public static int CalculateItemPotencyBonus(NWCreature caster, ForceAbilityType abilityType) { if (!caster.IsPlayer) { return(0); } EffectiveItemStats itemStats = PlayerStatService.GetPlayerItemEffectiveStats(caster.Object); int itemBonus = itemStats.ForcePotency; switch (abilityType) { case ForceAbilityType.Electrical: itemBonus += itemStats.ElectricalPotency; break; case ForceAbilityType.Mind: itemBonus += itemStats.MindPotency; break; case ForceAbilityType.Light: itemBonus += itemStats.LightPotency; break; case ForceAbilityType.Dark: itemBonus += itemStats.DarkPotency; break; default: throw new ArgumentOutOfRangeException(nameof(abilityType), abilityType, null); } return(itemBonus); }
private static int EffectiveArmorClass(NWPlayer player, NWItem ignoreItem, EffectiveItemStats stats) { int baseAC = stats.AC + CustomEffectService.CalculateEffectAC(player); // Calculate AC bonus granted by skill ranks. // Only chest armor is checked for this bonus. if (ignoreItem != player.Chest) { CustomItemType armorType = player.Chest.CustomItemType; int skillRank = 0; switch (armorType) { case CustomItemType.LightArmor: skillRank = SkillService.GetPCSkillRank(player, SkillType.LightArmor); break; case CustomItemType.HeavyArmor: skillRank = SkillService.GetPCSkillRank(player, SkillType.HeavyArmor); break; case CustomItemType.ForceArmor: skillRank = SkillService.GetPCSkillRank(player, SkillType.ForceArmor); break; } // +1 AC per 10 skill ranks, while wearing the appropriate armor. int skillACBonus = skillRank / 10; baseAC += skillACBonus; } int totalAC = _.GetAC(player) - baseAC; // Shield Oath and Precision Targeting affect a percentage of the TOTAL armor class on a creature. var stance = CustomEffectService.GetCurrentStanceType(player); if (stance == CustomEffectType.ShieldOath) { int bonus = (int)(totalAC * 0.2f); baseAC += bonus; } else if (stance == CustomEffectType.PrecisionTargeting) { int penalty = (int)(totalAC * 0.3f); baseAC -= penalty; } if (baseAC < 0) { baseAC = 0; } return(baseAC); }
private int EffectiveMaxFP(NWPlayer player, EffectiveItemStats stats) { int fp = 20; fp += (player.IntelligenceModifier + player.WisdomModifier + player.CharismaModifier) * 5; fp += _perk.GetPCPerkLevel(player, PerkType.FP) * 5; fp += stats.FP; if (fp < 0) { fp = 0; } return(fp); }
private int EffectiveMaxHitPoints(NWPlayer player, EffectiveItemStats stats) { int hp = 25 + player.ConstitutionModifier * 5; float effectPercentBonus = _customEffect.CalculateEffectHPBonusPercent(player); hp += _perk.GetPCPerkLevel(player, PerkType.Health) * 5; hp += stats.HP; hp = hp + (int)(hp * effectPercentBonus); if (hp > 1275) { hp = 1275; } if (hp < 20) { hp = 20; } return(hp); }
// New component items will be spawned and the appropriate properties from the base item will be transferred. public bool Run(params object[] args) { _player = (NWPlayer)args[0]; _playerItemStats = PlayerStatService.GetPlayerItemEffectiveStats(_player); int xp = 100; // Always grant at least this much XP to player. // Remove the immobilization effect foreach (var effect in _player.Effects) { if (_.GetEffectTag(effect) == "CRAFTING_IMMOBILIZATION") { _.RemoveEffect(_player, effect); } } string serializedSalvageItem = (string)args[1]; NWPlaceable tempStorage = _.GetObjectByTag("TEMP_ITEM_STORAGE"); NWItem item = SerializationService.DeserializeItem(serializedSalvageItem, tempStorage); int salvageComponentTypeID = (int)args[2]; _componentType = DataService.Get <ComponentType>(salvageComponentTypeID); // Create an item with no bonuses every time. _.CreateItemOnObject(_componentType.ReassembledResref, _player); // First check is for attack bonuses foreach (var prop in item.ItemProperties) { int propTypeID = _.GetItemPropertyType(prop); if (propTypeID == _.ITEM_PROPERTY_ATTACK_BONUS) { // Get the amount of Attack Bonus int amount = _.GetItemPropertyCostTableValue(prop); xp += ProcessProperty(amount, 3, ComponentBonusType.AttackBonusUp); } } // Now check specific custom properties which are stored as local variables on the item. xp += ProcessProperty(item.CustomAC, 3, ComponentBonusType.ACUp); xp += ProcessProperty(item.HarvestingBonus, 3, ComponentBonusType.HarvestingUp); xp += ProcessProperty(item.PilotingBonus, 3, ComponentBonusType.PilotingUp); xp += ProcessProperty(item.ScanningBonus, 3, ComponentBonusType.ScanningUp); xp += ProcessProperty(item.ScavengingBonus, 3, ComponentBonusType.ScavengingUp); xp += ProcessProperty(item.CastingSpeed, 3, ComponentBonusType.CastingSpeedUp); xp += ProcessProperty(item.CraftBonusArmorsmith, 3, ComponentBonusType.ArmorsmithUp); xp += ProcessProperty(item.CraftBonusWeaponsmith, 3, ComponentBonusType.WeaponsmithUp); xp += ProcessProperty(item.CraftBonusCooking, 3, ComponentBonusType.CookingUp); xp += ProcessProperty(item.CraftBonusEngineering, 3, ComponentBonusType.EngineeringUp); xp += ProcessProperty(item.CraftBonusFabrication, 3, ComponentBonusType.FabricationUp); xp += ProcessProperty(item.HPBonus, 5, ComponentBonusType.HPUp, 0.5f); xp += ProcessProperty(item.FPBonus, 5, ComponentBonusType.FPUp, 0.5f); xp += ProcessProperty(item.EnmityRate, 3, ComponentBonusType.EnmityUp); xp += ProcessProperty(item.ForcePotencyBonus, 3, ComponentBonusType.ForcePotencyUp); xp += ProcessProperty(item.ForceAccuracyBonus, 3, ComponentBonusType.ForceAccuracyUp); xp += ProcessProperty(item.ForceDefenseBonus, 3, ComponentBonusType.ForceDefenseUp); xp += ProcessProperty(item.ElectricalPotencyBonus, 3, ComponentBonusType.ElectricalPotencyUp); xp += ProcessProperty(item.MindPotencyBonus, 3, ComponentBonusType.MindPotencyUp); xp += ProcessProperty(item.LightPotencyBonus, 3, ComponentBonusType.LightPotencyUp); xp += ProcessProperty(item.DarkPotencyBonus, 3, ComponentBonusType.DarkPotencyUp); xp += ProcessProperty(item.ElectricalDefenseBonus, 3, ComponentBonusType.ElectricalDefenseUp); xp += ProcessProperty(item.MindDefenseBonus, 3, ComponentBonusType.MindDefenseUp); xp += ProcessProperty(item.LightDefenseBonus, 3, ComponentBonusType.LightDefenseUp); xp += ProcessProperty(item.DarkDefenseBonus, 3, ComponentBonusType.DarkDefenseUp); xp += ProcessProperty(item.LuckBonus, 3, ComponentBonusType.LuckUp); xp += ProcessProperty(item.MeditateBonus, 3, ComponentBonusType.MeditateUp); xp += ProcessProperty(item.RestBonus, 3, ComponentBonusType.RestUp); xp += ProcessProperty(item.MedicineBonus, 3, ComponentBonusType.MedicineUp); xp += ProcessProperty(item.HPRegenBonus, 3, ComponentBonusType.HPRegenUp); xp += ProcessProperty(item.FPRegenBonus, 3, ComponentBonusType.FPRegenUp); xp += ProcessProperty(item.BaseAttackBonus, 3, ComponentBonusType.BaseAttackBonusUp, 6f); xp += ProcessProperty(item.StructureBonus, 3, ComponentBonusType.StructureBonusUp); xp += ProcessProperty(item.SneakAttackBonus, 3, ComponentBonusType.SneakAttackUp); xp += ProcessProperty(item.DamageBonus, 3, ComponentBonusType.DamageUp); xp += ProcessProperty(item.StrengthBonus, 3, ComponentBonusType.StrengthUp); xp += ProcessProperty(item.DexterityBonus, 3, ComponentBonusType.DexterityUp); xp += ProcessProperty(item.ConstitutionBonus, 3, ComponentBonusType.ConstitutionUp); xp += ProcessProperty(item.WisdomBonus, 3, ComponentBonusType.WisdomUp); xp += ProcessProperty(item.IntelligenceBonus, 3, ComponentBonusType.IntelligenceUp); xp += ProcessProperty(item.CharismaBonus, 3, ComponentBonusType.CharismaUp); xp += ProcessProperty(item.DurationBonus, 3, ComponentBonusType.DurationUp); item.Destroy(); SkillService.GiveSkillXP(_player, SkillType.Harvesting, xp); return(true); }
private 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 = _item.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 = _data.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 += _perk.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 void ApplyStatChanges(NWPlayer player, NWItem ignoreItem, bool isInitialization = false) { if (!player.IsPlayer) { return; } if (!player.IsInitializedAsPlayer) { return; } // Don't fire for ammo as it reapplies bonuses **just** removed from blasters. if (ignoreItem != null && (ignoreItem.BaseItemType == BASE_ITEM_BOLT || ignoreItem.BaseItemType == BASE_ITEM_ARROW || ignoreItem.BaseItemType == BASE_ITEM_BULLET)) { return; } Player pcEntity = _data.Get <Player>(player.GlobalID); List <PCSkill> skills = _data.Where <PCSkill>(x => x.PlayerID == player.GlobalID && x.Rank > 0).ToList(); EffectiveItemStats itemBonuses = GetPlayerItemEffectiveStats(player, ignoreItem); float strBonus = 0.0f; float dexBonus = 0.0f; float conBonus = 0.0f; float intBonus = 0.0f; float wisBonus = 0.0f; float chaBonus = 0.0f; using (new Profiler("PlayerStatService::ApplyStatChanges::AttributeApplication")) { foreach (PCSkill pcSkill in skills) { Skill skill = _data.Get <Skill>(pcSkill.SkillID); CustomAttribute primary = (CustomAttribute)skill.Primary; CustomAttribute secondary = (CustomAttribute)skill.Secondary; CustomAttribute tertiary = (CustomAttribute)skill.Tertiary; // Primary Bonuses if (primary == CustomAttribute.STR) { strBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.DEX) { dexBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.CON) { conBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.INT) { intBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.WIS) { wisBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.CHA) { chaBonus += PrimaryIncrease * pcSkill.Rank; } // Secondary Bonuses if (secondary == CustomAttribute.STR) { strBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.DEX) { dexBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.CON) { conBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.INT) { intBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.WIS) { wisBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.CHA) { chaBonus += SecondaryIncrease * pcSkill.Rank; } // Tertiary Bonuses if (tertiary == CustomAttribute.STR) { strBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.DEX) { dexBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.CON) { conBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.INT) { intBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.WIS) { wisBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.CHA) { chaBonus += TertiaryIncrease * pcSkill.Rank; } } } // Check caps. if (strBonus > MaxAttributeBonus) { strBonus = MaxAttributeBonus; } if (dexBonus > MaxAttributeBonus) { dexBonus = MaxAttributeBonus; } if (conBonus > MaxAttributeBonus) { conBonus = MaxAttributeBonus; } if (intBonus > MaxAttributeBonus) { intBonus = MaxAttributeBonus; } if (wisBonus > MaxAttributeBonus) { wisBonus = MaxAttributeBonus; } if (chaBonus > MaxAttributeBonus) { chaBonus = MaxAttributeBonus; } // Apply item bonuses strBonus += itemBonuses.Strength; dexBonus += itemBonuses.Dexterity; conBonus += itemBonuses.Constitution; wisBonus += itemBonuses.Wisdom; intBonus += itemBonuses.Intelligence; chaBonus += itemBonuses.Charisma; // Check final caps if (strBonus > 100) { strBonus = 100; } if (dexBonus > 100) { dexBonus = 100; } if (conBonus > 100) { conBonus = 100; } if (intBonus > 100) { intBonus = 100; } if (wisBonus > 100) { wisBonus = 100; } if (chaBonus > 100) { chaBonus = 100; } // Apply attributes _nwnxCreature.SetRawAbilityScore(player, ABILITY_STRENGTH, (int)strBonus + pcEntity.STRBase); _nwnxCreature.SetRawAbilityScore(player, ABILITY_DEXTERITY, (int)dexBonus + pcEntity.DEXBase); _nwnxCreature.SetRawAbilityScore(player, ABILITY_CONSTITUTION, (int)conBonus + pcEntity.CONBase); _nwnxCreature.SetRawAbilityScore(player, ABILITY_INTELLIGENCE, (int)intBonus + pcEntity.INTBase); _nwnxCreature.SetRawAbilityScore(player, ABILITY_WISDOM, (int)wisBonus + pcEntity.WISBase); _nwnxCreature.SetRawAbilityScore(player, ABILITY_CHARISMA, (int)chaBonus + pcEntity.CHABase); // Apply AC using (new Profiler("PlayerStatService::ApplyStatChanges::CalcAC")) { int ac = EffectiveArmorClass(itemBonuses, player); _nwnxCreature.SetBaseAC(player, ac); } // Apply BAB using (new Profiler("PlayerStatService::ApplyStatChanges::CalcBAB")) { int bab = CalculateBAB(player, ignoreItem, itemBonuses); _nwnxCreature.SetBaseAttackBonus(player, bab); } // Apply HP using (new Profiler("PlayerStatService::ApplyStatChanges::CalcHP")) { int hp = EffectiveMaxHitPoints(player, itemBonuses); for (int level = 1; level <= 5; level++) { hp--; _nwnxCreature.SetMaxHitPointsByLevel(player, level, 1); } for (int level = 1; level <= 5; level++) { if (hp > 255) // Levels can only contain a max of 255 HP { _nwnxCreature.SetMaxHitPointsByLevel(player, level, 255); hp = hp - 255; } else // Remaining value gets set to the level. (<255 hp) { _nwnxCreature.SetMaxHitPointsByLevel(player, level, hp + 1); break; } } } if (player.CurrentHP > player.MaxHP) { int amount = player.CurrentHP - player.MaxHP; Effect damage = _.EffectDamage(amount); _.ApplyEffectToObject(DURATION_TYPE_INSTANT, damage, player.Object); } // Apply FP using (new Profiler("PlayerStatService::ApplyStatChanges::CalcFP")) { pcEntity.MaxFP = EffectiveMaxFP(player, itemBonuses); if (isInitialization) { pcEntity.CurrentFP = pcEntity.MaxFP; } _data.SubmitDataChange(pcEntity, DatabaseActionType.Update); } }
public EffectiveItemStats GetPlayerItemEffectiveStats(NWPlayer player, NWItem ignoreItem = null) { using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats")) { List <PCSkill> pcArmorSkills; using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::GetPCArmorSkills")) { pcArmorSkills = _data.Where <PCSkill>(x => x.PlayerID == player.GlobalID && (x.SkillID == (int)SkillType.HeavyArmor || x.SkillID == (int)SkillType.LightArmor || x.SkillID == (int)SkillType.ForceArmor)) .ToList(); } int heavyRank = pcArmorSkills.Single(x => x.SkillID == (int)SkillType.HeavyArmor).Rank; int lightRank = pcArmorSkills.Single(x => x.SkillID == (int)SkillType.LightArmor).Rank; int forceRank = pcArmorSkills.Single(x => x.SkillID == (int)SkillType.ForceArmor).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 = _item.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 = _data.Single <PCSkill>(x => x.PlayerID == player.GlobalID && 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.DarkAbility += CalculateAdjustedValue(item.DarkAbilityBonus, item.RecommendedLevel, rank, 0); stats.LightAbility += CalculateAdjustedValue(item.LightAbilityBonus, 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.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 { 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 = _customEffect.GetCurrentStanceType(player); if (stance == CustomEffectType.ShieldOath) { stats.EnmityRate = stats.EnmityRate + 0.2f; } return(stats); } } }
public EffectiveItemStats GetPlayerItemEffectiveStats(NWPlayer player, NWItem ignoreItem = null) { EffectiveItemStats stats = new EffectiveItemStats(); stats.EnmityRate = 1.0f; for (int itemSlot = 0; itemSlot < NUM_INVENTORY_SLOTS; itemSlot++) { NWItem item = _.GetItemInSlot(itemSlot, player); if (!item.IsValid || item.Equals(ignoreItem)) { continue; } SkillType skill = _item.GetSkillTypeForItem(item); int rank = _data.Single <PCSkill>(x => x.PlayerID == player.GlobalID && x.SkillID == (int)skill).Rank; // 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); } else { stats.CastingSpeed += item.CastingSpeed; } stats.EnmityRate += CalculateAdjustedValue(0.01f * item.EnmityRate, item.RecommendedLevel, rank, 0.00f); stats.DarkAbility += CalculateAdjustedValue(item.DarkAbilityBonus, item.RecommendedLevel, rank, 0); stats.LightAbility += CalculateAdjustedValue(item.LightAbilityBonus, 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.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); } // 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 = _customEffect.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 void ApplyStatChanges(NWPlayer player, NWItem ignoreItem, bool isInitialization = false) { if (!player.IsPlayer) { return; } if (!player.IsInitializedAsPlayer) { return; } if (player.GetLocalInt("IS_SHIP") == 1) { return; } // Don't fire for ammo as it reapplies bonuses we **just** removed from blasters. if (ignoreItem != null && (ignoreItem.BaseItemType == BaseItem.Bolt || ignoreItem.BaseItemType == BaseItem.Arrow || ignoreItem.BaseItemType == BaseItem.Bullet)) { return; } Player pcEntity = DataService.Player.GetByID(player.GlobalID); List <PCSkill> skills = DataService.PCSkill .GetAllByPlayerID(player.GlobalID) .Where(x => x.Rank > 0).ToList(); EffectiveItemStats itemBonuses = GetPlayerItemEffectiveStats(player, ignoreItem); float strBonus = 0.0f; float dexBonus = 0.0f; float conBonus = 0.0f; float intBonus = 0.0f; float wisBonus = 0.0f; float chaBonus = 0.0f; foreach (PCSkill pcSkill in skills) { Skill skill = DataService.Skill.GetByID(pcSkill.SkillID); CustomAttribute primary = (CustomAttribute)skill.Primary; CustomAttribute secondary = (CustomAttribute)skill.Secondary; CustomAttribute tertiary = (CustomAttribute)skill.Tertiary; // Primary Bonuses if (primary == CustomAttribute.STR) { strBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.DEX) { dexBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.CON) { conBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.INT) { intBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.WIS) { wisBonus += PrimaryIncrease * pcSkill.Rank; } else if (primary == CustomAttribute.CHA) { chaBonus += PrimaryIncrease * pcSkill.Rank; } // Secondary Bonuses if (secondary == CustomAttribute.STR) { strBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.DEX) { dexBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.CON) { conBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.INT) { intBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.WIS) { wisBonus += SecondaryIncrease * pcSkill.Rank; } else if (secondary == CustomAttribute.CHA) { chaBonus += SecondaryIncrease * pcSkill.Rank; } // Tertiary Bonuses if (tertiary == CustomAttribute.STR) { strBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.DEX) { dexBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.CON) { conBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.INT) { intBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.WIS) { wisBonus += TertiaryIncrease * pcSkill.Rank; } else if (tertiary == CustomAttribute.CHA) { chaBonus += TertiaryIncrease * pcSkill.Rank; } } // Check caps. if (strBonus > MaxAttributeBonus) { strBonus = MaxAttributeBonus; } if (dexBonus > MaxAttributeBonus) { dexBonus = MaxAttributeBonus; } if (conBonus > MaxAttributeBonus) { conBonus = MaxAttributeBonus; } if (intBonus > MaxAttributeBonus) { intBonus = MaxAttributeBonus; } if (wisBonus > MaxAttributeBonus) { wisBonus = MaxAttributeBonus; } if (chaBonus > MaxAttributeBonus) { chaBonus = MaxAttributeBonus; } // Apply item bonuses strBonus += itemBonuses.Strength; dexBonus += itemBonuses.Dexterity; conBonus += itemBonuses.Constitution; wisBonus += itemBonuses.Wisdom; intBonus += itemBonuses.Intelligence; chaBonus += itemBonuses.Charisma; // Check final caps if (strBonus > 55) { strBonus = 55; } if (dexBonus > 55) { dexBonus = 55; } if (conBonus > 55) { conBonus = 55; } if (intBonus > 55) { intBonus = 55; } if (wisBonus > 55) { wisBonus = 55; } if (chaBonus > 55) { chaBonus = 55; } // Apply attributes NWNXCreature.SetRawAbilityScore(player, AbilityType.Strength, (int)strBonus + pcEntity.STRBase); NWNXCreature.SetRawAbilityScore(player, AbilityType.Dexterity, (int)dexBonus + pcEntity.DEXBase); NWNXCreature.SetRawAbilityScore(player, AbilityType.Constitution, (int)conBonus + pcEntity.CONBase); NWNXCreature.SetRawAbilityScore(player, AbilityType.Intelligence, (int)intBonus + pcEntity.INTBase); NWNXCreature.SetRawAbilityScore(player, AbilityType.Wisdom, (int)wisBonus + pcEntity.WISBase); NWNXCreature.SetRawAbilityScore(player, AbilityType.Charisma, (int)chaBonus + pcEntity.CHABase); // Apply AC int ac = EffectiveArmorClass(player, ignoreItem, itemBonuses); NWNXCreature.SetBaseAC(player, ac); // Apply BAB int bab = CalculateBAB(player, ignoreItem, itemBonuses); NWNXCreature.SetBaseAttackBonus(player, bab); // Apply HP int hp = EffectiveMaxHitPoints(player, itemBonuses); for (int level = 1; level <= 5; level++) { hp--; NWNXCreature.SetMaxHitPointsByLevel(player, level, 1); } for (int level = 1; level <= 5; level++) { if (hp >= 255) // Levels can only contain a max of 255 HP { NWNXCreature.SetMaxHitPointsByLevel(player, level, 255); hp = hp - 254; } else // Remaining value gets set to the level. (<255 hp) { NWNXCreature.SetMaxHitPointsByLevel(player, level, hp + 1); break; } } if (player.CurrentHP > player.MaxHP) { int amount = player.CurrentHP - player.MaxHP; var damage = _.EffectDamage(amount); _.ApplyEffectToObject(DurationType.Instant, damage, player.Object); } // Apply FP pcEntity.MaxFP = EffectiveMaxFP(player, itemBonuses); if (isInitialization) { pcEntity.CurrentFP = pcEntity.MaxFP; } DataService.SubmitDataChange(pcEntity, DatabaseActionType.Update); // Attempt a refresh of the character sheet UI in a second. _.DelayCommand(1.0f, () => { NWNXPlayer.UpdateCharacterSheet(player); }); }
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); }
// New component items will be spawned and the appropriate properties from the base item will be transferred. public bool Run(params object[] args) { _player = (NWPlayer)args[0]; int xp = 100; // Always grant at least this much XP to player. // Remove the immobilization effect foreach (var effect in _player.Effects) { if (_.GetEffectTag(effect) == "CRAFTING_IMMOBILIZATION") { _.RemoveEffect(_player, effect); } } // Check for a fuel cell in the player's inventory again. If it doesn't exist, we exit early with an error message. NWItem fuel = _.GetItemPossessedBy(_player, "ass_power"); if (!fuel.IsValid) { _player.SendMessage(ColorTokenService.Red("A 'Reassembly Fuel Cell' was not found in your inventory. Reassembly failed.")); return(false); } // Otherwise the fuel cell was found. Destroy it and continue on with the process. fuel.Destroy(); _playerItemStats = PlayerStatService.GetPlayerItemEffectiveStats(_player); string serializedSalvageItem = (string)args[1]; NWPlaceable tempStorage = _.GetObjectByTag("TEMP_ITEM_STORAGE"); NWItem item = SerializationService.DeserializeItem(serializedSalvageItem, tempStorage); int salvageComponentTypeID = (int)args[2]; _componentType = DataService.Get <ComponentType>(salvageComponentTypeID); // Create an item with no bonuses every time. _.CreateItemOnObject(_componentType.ReassembledResref, _player); // Now check specific custom properties which are stored as local variables on the item. xp += ProcessProperty(item.HarvestingBonus, 3, ComponentBonusType.HarvestingUp); xp += ProcessProperty(item.PilotingBonus, 3, ComponentBonusType.PilotingUp); xp += ProcessProperty(item.ScanningBonus, 3, ComponentBonusType.ScanningUp); xp += ProcessProperty(item.ScavengingBonus, 3, ComponentBonusType.ScavengingUp); xp += ProcessProperty(item.CooldownRecovery, 3, ComponentBonusType.CooldownRecoveryUp); xp += ProcessProperty(item.CraftBonusArmorsmith, 3, ComponentBonusType.ArmorsmithUp); xp += ProcessProperty(item.CraftBonusWeaponsmith, 3, ComponentBonusType.WeaponsmithUp); xp += ProcessProperty(item.CraftBonusCooking, 3, ComponentBonusType.CookingUp); xp += ProcessProperty(item.CraftBonusEngineering, 3, ComponentBonusType.EngineeringUp); xp += ProcessProperty(item.CraftBonusFabrication, 3, ComponentBonusType.FabricationUp); xp += ProcessProperty(item.HPBonus, 5, ComponentBonusType.HPUp, 0.5f); xp += ProcessProperty(item.FPBonus, 5, ComponentBonusType.FPUp, 0.5f); xp += ProcessProperty(item.EnmityRate, 3, ComponentBonusType.EnmityUp); xp += ProcessProperty(item.LuckBonus, 3, ComponentBonusType.LuckUp); xp += ProcessProperty(item.MeditateBonus, 3, ComponentBonusType.MeditateUp); xp += ProcessProperty(item.RestBonus, 3, ComponentBonusType.RestUp); xp += ProcessProperty(item.MedicineBonus, 3, ComponentBonusType.MedicineUp); xp += ProcessProperty(item.HPRegenBonus, 3, ComponentBonusType.HPRegenUp); xp += ProcessProperty(item.FPRegenBonus, 3, ComponentBonusType.FPRegenUp); xp += ProcessProperty(item.BaseAttackBonus, 3, ComponentBonusType.BaseAttackBonusUp, 6f); xp += ProcessProperty(item.StructureBonus, 3, ComponentBonusType.StructureBonusUp); xp += ProcessProperty(item.SneakAttackBonus, 3, ComponentBonusType.SneakAttackUp); xp += ProcessProperty(item.DamageBonus, 3, ComponentBonusType.DamageUp); xp += ProcessProperty(item.StrengthBonus, 3, ComponentBonusType.StrengthUp); xp += ProcessProperty(item.DexterityBonus, 3, ComponentBonusType.DexterityUp); xp += ProcessProperty(item.ConstitutionBonus, 3, ComponentBonusType.ConstitutionUp); xp += ProcessProperty(item.WisdomBonus, 3, ComponentBonusType.WisdomUp); xp += ProcessProperty(item.IntelligenceBonus, 3, ComponentBonusType.IntelligenceUp); xp += ProcessProperty(item.CharismaBonus, 3, ComponentBonusType.CharismaUp); xp += ProcessProperty(item.DurationBonus, 3, ComponentBonusType.DurationUp); item.Destroy(); SkillService.GiveSkillXP(_player, SkillType.Harvesting, xp); return(true); }
private static int CalculateForceAccuracy( NWCreature caster, NWCreature target, ForceAbilityType abilityType) { EffectiveItemStats casterItemStats = caster.IsPlayer ? PlayerStatService.GetPlayerItemEffectiveStats(caster.Object) : null; float casterPrimary; float casterSecondary; float casterItemAccuracy = casterItemStats?.ForceAccuracy ?? 0; EffectiveItemStats targetItemStats = target.IsPlayer ? PlayerStatService.GetPlayerItemEffectiveStats(target.Object) : null; float targetPrimary; float targetSecondary; float targetItemDefense = targetItemStats?.ForceDefense ?? 0; switch (abilityType) { case ForceAbilityType.Electrical: casterPrimary = caster.Intelligence; casterSecondary = caster.Wisdom; targetPrimary = target.Intelligence; targetSecondary = target.Wisdom; targetItemDefense = targetItemDefense + targetItemStats?.ElectricalDefense ?? 0; break; case ForceAbilityType.Dark: casterPrimary = caster.Intelligence; casterSecondary = caster.Wisdom; targetPrimary = target.Wisdom; targetSecondary = target.Intelligence; targetItemDefense = targetItemDefense + targetItemStats?.DarkDefense ?? 0; break; case ForceAbilityType.Mind: casterPrimary = caster.Wisdom; casterSecondary = caster.Intelligence; targetPrimary = target.Wisdom; targetSecondary = target.Intelligence; targetItemDefense = targetItemDefense + targetItemStats?.MindDefense ?? 0; break; case ForceAbilityType.Light: casterPrimary = caster.Wisdom; casterSecondary = caster.Intelligence; targetPrimary = target.Intelligence; targetSecondary = target.Wisdom; targetItemDefense = targetItemDefense + targetItemStats?.ElectricalDefense ?? 0; break; default: throw new ArgumentOutOfRangeException(nameof(abilityType), abilityType, null); } // Calculate accuracy based on the caster's primary and secondary stats. Add modifiers for overall item accuracy. float baseAccuracy = caster.Charisma * 0.25f + casterPrimary * 0.75f + casterSecondary * 0.5f + casterItemAccuracy * 0.15f; // Calculate defense based on target's primary and secondary stats. Add modifiers for specific defense types. float baseDefense = target.Charisma * 0.25f + targetPrimary * 0.75f + targetSecondary * 0.5f + targetItemDefense * 0.15f; // Temp defense increases whenever a hostile force ability is used. This is primarily a deterrant towards spamming the same ability over and over. string expiration = target.GetLocalString("TEMP_FORCE_DEFENSE_" + (int)abilityType); if (DateTime.TryParse(expiration, out var unused)) { int tempDefense = target.GetLocalInt("TEMP_FORCE_DEFENSE_" + (int)abilityType); baseDefense += tempDefense; } float delta = baseAccuracy - baseDefense; float finalAccuracy = delta < 0 ? 75 + (float)Math.Floor(delta / 2.0f) : 75 + delta; // Accuracy cannot go above 95% or below 0% if (finalAccuracy > 95) { finalAccuracy = 95; } else if (finalAccuracy < 0) { finalAccuracy = 0; } return((int)finalAccuracy); }