示例#1
0
        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);
        }
示例#2
0
        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);
        }
示例#3
0
        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);
        }
示例#4
0
        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);
                }
            }
        }
示例#5
0
        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);
        }
示例#6
0
        private static void HandleDamageImmunity()
        {
            DamageEventData data = NWNXDamage.GetDamageEventData();

            if (data.Total <= 0)
            {
                return;
            }

            NWCreature target = _.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% AC bonuses on the shield + 2% per perk bonus.
                reduction = (0.1 + (0.01 * shield.CustomAC)) + 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 * 3);
                    if (xp < 5)
                    {
                        xp = 5;
                    }

                    SkillService.GiveSkillXP(target.Object, SkillType.ForceControl, xp);
                    // Play a visual effect signifying the ability was activated.
                    _.ApplyEffectToObject(DurationType.Temporary, EffectVisualEffect(VisualEffect.Dur_Blur), target, 0.5f);
                }
            }
            //Shield Oath Damage Immunity
            NWPlayer player = _.OBJECT_SELF;

            if (target.IsPC)
            {
                if (CustomEffectService.GetCurrentStanceType(player) == CustomEffectType.ShieldOath)
                {
                    reduction += 0.2f;
                }
            }

            // No reduction found. Bail out early.
            if (reduction <= 0.0f)
            {
                return;
            }
            target.SendMessage("Total Damage: " + data.Total);
            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); -- special damage types, such as force rage
            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);

            target.SendMessage("Total Damage: " + data.Total);

            NWNXDamage.SetDamageEventData(data);
        }