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);
        }
Beispiel #2
0
        private static int EffectiveMaxHitPoints(NWPlayer player, EffectiveItemStats stats)
        {
            int   hp = 25 + player.ConstitutionModifier * 5;
            float effectPercentBonus = CustomEffectService.CalculateEffectHPBonusPercent(player);

            hp += PerkService.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);
        }
Beispiel #3
0
        private static void HandleAbsorptionFieldEffect()
        {
            DamageEventData data = NWNXDamage.GetDamageEventData();

            if (data.Total <= 0)
            {
                return;
            }
            NWObject target = NWGameObject.OBJECT_SELF;

            if (!target.IsPlayer)
            {
                return;
            }

            NWPlayer player      = target.Object;
            int      effectLevel = CustomEffectService.GetCustomEffectLevel(player, CustomEffectType.AbsorptionField);

            if (effectLevel <= 0)
            {
                return;
            }

            // Remove effect if player activates ability and removes the armor.
            if (player.Chest.CustomItemType != CustomItemType.ForceArmor)
            {
                CustomEffectService.RemovePCCustomEffect(player, CustomEffectType.AbsorptionField);
            }

            float absorptionRate = effectLevel * 0.1f;
            int   absorbed       = (int)(data.Total * absorptionRate);

            if (absorbed < 1)
            {
                absorbed = 1;
            }

            AbilityService.RestorePlayerFP(player, absorbed);
        }
Beispiel #4
0
        private static void ProcessNPCCustomEffects()
        {
            for (int index = AppCache.NPCEffects.Count - 1; index >= 0; index--)
            {
                var           entry       = AppCache.NPCEffects.ElementAt(index);
                CasterSpellVO casterModel = entry.Key;
                AppCache.NPCEffects[entry.Key] = entry.Value - 1;
                Data.Entity.CustomEffect entity  = DataService.Single <Data.Entity.CustomEffect>(x => x.ID == casterModel.CustomEffectID);
                ICustomEffectHandler     handler = CustomEffectService.GetCustomEffectHandler(casterModel.CustomEffectID);

                try
                {
                    handler?.Tick(casterModel.Caster, casterModel.Target, AppCache.NPCEffects[entry.Key], casterModel.EffectiveLevel, casterModel.Data);
                }
                catch (Exception ex)
                {
                    LoggingService.LogError(ex, "CustomEffectService processor was unable to run specific effect script for custom effect ID: " + entity.ID);
                }


                // Kill the effect if it has expired, target is invalid, or target is dead.
                if (entry.Value <= 0 ||
                    !casterModel.Target.IsValid ||
                    casterModel.Target.CurrentHP <= -11)
                {
                    handler?.WearOff(casterModel.Caster, casterModel.Target, casterModel.EffectiveLevel, casterModel.Data);

                    if (casterModel.Caster.IsValid && casterModel.Caster.IsPlayer)
                    {
                        casterModel.Caster.SendMessage("Your effect '" + casterModel.EffectName + "' has worn off of " + casterModel.Target.Name);
                    }

                    casterModel.Target.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + casterModel.CustomEffectID);

                    AppCache.NPCEffects.Remove(entry.Key);
                }
            }
        }
Beispiel #5
0
        private static void ProcessPCCustomEffects()
        {
            foreach (var player in NWModule.Get().Players)
            {
                if (!player.IsInitializedAsPlayer)
                {
                    continue;                                // Ignored to prevent a timing issue where new characters would be included in this processing.
                }
                List <PCCustomEffect> effects = DataService.Where <PCCustomEffect>(x => x.PlayerID == player.GlobalID &&
                                                                                   x.StancePerkID == null).ToList();

                foreach (var effect in effects)
                {
                    if (player.CurrentHP <= -11)
                    {
                        CustomEffectService.RemovePCCustomEffect(player, effect.CustomEffectID);
                        return;
                    }

                    PCCustomEffect result = RunPCCustomEffectProcess(player, effect);
                    if (result == null)
                    {
                        ICustomEffectHandler handler = CustomEffectService.GetCustomEffectHandler(effect.CustomEffectID);
                        string message = handler.WornOffMessage;
                        player.SendMessage(message);
                        player.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + effect.CustomEffectID);
                        DataService.SubmitDataChange(effect, DatabaseActionType.Delete);
                        handler.WearOff(null, player, effect.EffectiveLevel, effect.Data);
                    }
                    else
                    {
                        DataService.SubmitDataChange(effect, DatabaseActionType.Update);
                    }
                }
            }
        }
        public static void HandlePlasmaCellPerk(NWPlayer player, NWObject target)
        {
            if (!player.IsPlayer)
            {
                return;
            }
            if (!_.GetHasFeat(Feat.PlasmaCell, player))
            {
                return;                                          // Check if player has the perk
            }
            if (player.RightHand.CustomItemType != CustomItemType.BlasterPistol &&
                player.RightHand.CustomItemType != CustomItemType.BlasterRifle)
            {
                return;                                                                 // Check if player has the right weapons
            }
            if (GetLocalBool(target, "TRANQUILIZER_EFFECT_FIRST_RUN") == true)
            {
                return;                                                                  // Check if Tranquilizer is on to avoid conflict
            }
            if (GetLocalBool(player, "PLASMA_CELL_TOGGLE_OFF") == true)
            {
                return;                                                          // Check if Plasma Cell toggle is on or off
            }
            if (GetLocalBool(target, "TRANQUILIZER_EFFECT_FIRST_RUN") == true)
            {
                return;
            }

            int perkLevel = PerkService.GetCreaturePerkLevel(player, PerkType.PlasmaCell);
            int chance;

            CustomEffectType[] damageTypes;
            switch (perkLevel)
            {
            case 1:
                chance      = 10;
                damageTypes = new[] { CustomEffectType.FireCell };
                break;

            case 2:
                chance      = 10;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell };
                break;

            case 3:
                chance      = 20;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell };
                break;

            case 4:
                chance      = 20;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell };
                break;

            case 5:
                chance      = 30;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell };
                break;

            case 6:
                chance      = 30;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell };
                break;

            case 7:
                chance      = 40;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell };
                break;

            case 8:
                chance      = 40;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell };
                break;

            case 9:
                chance      = 50;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell };
                break;

            case 10:
                chance      = 50;
                damageTypes = new[] { CustomEffectType.FireCell, CustomEffectType.ElectricCell, CustomEffectType.SonicCell, CustomEffectType.AcidCell, CustomEffectType.IceCell, CustomEffectType.DivineCell };
                break;

            default: return;
            }

            foreach (var effect in damageTypes)
            {
                if (RandomService.D100(1) <= chance)
                {
                    CustomEffectService.ApplyCustomEffect(player, target.Object, effect, RandomService.D6(1), perkLevel, null);
                }
            }
        }
        /// <summary>
        /// Runs validation checks to ensure activator can use a perk feat.
        /// Activation will fail if any of the following are true:
        ///     - Target is invalid
        ///     - Activator is a ship
        ///     - Feat is not a perk feat
        ///     - Cooldown has not passed
        /// </summary>
        /// <param name="activator">The creature activating a perk feat.</param>
        /// <param name="target">The target of the perk feat.</param>
        /// <param name="featID">The ID number of the feat being used.</param>
        /// <returns>true if able to use perk feat on target, false otherwise.</returns>
        public static bool CanUsePerkFeat(NWCreature activator, NWObject target, Feat featID)
        {
            var perkFeat = DataService.PerkFeat.GetByFeatIDOrDefault((int)featID);

            // There's no matching feat in the DB for this ability. Exit early.
            if (perkFeat == null)
            {
                return(false);
            }

            // Retrieve the perk information.
            Data.Entity.Perk perk = DataService.Perk.GetByIDOrDefault(perkFeat.PerkID);

            // No perk could be found. Exit early.
            if (perk == null)
            {
                return(false);
            }

            // Check to see if we are a spaceship.  Spaceships can't use abilities...
            if (activator.GetLocalInt("IS_SHIP") > 0 || activator.GetLocalInt("IS_GUNNER") > 0)
            {
                activator.SendMessage("You cannot use that ability while piloting a ship.");
                return(false);
            }

            // Retrieve the perk-specific handler logic.
            var handler = PerkService.GetPerkHandler(perkFeat.PerkID);

            // Get the creature's perk level.
            int creaturePerkLevel = PerkService.GetCreaturePerkLevel(activator, perk.ID);

            // If player is disabling an existing stance, remove that effect.
            if (perk.ExecutionTypeID == PerkExecutionType.Stance)
            {
                // Can't process NPC stances at the moment. Need to do some more refactoring before this is possible.
                // todo: handle NPC stances.
                if (!activator.IsPlayer)
                {
                    return(false);
                }

                PCCustomEffect stanceEffect = DataService.PCCustomEffect.GetByStancePerkOrDefault(activator.GlobalID, perk.ID);

                if (stanceEffect != null)
                {
                    if (CustomEffectService.RemoveStance(activator))
                    {
                        return(false);
                    }
                }
            }

            // Check for a valid perk level.
            if (creaturePerkLevel <= 0)
            {
                activator.SendMessage("You do not meet the prerequisites to use this ability.");
                return(false);
            }

            // Verify that this hostile action meets PVP sanctuary restriction rules.
            if (handler.IsHostile() && target.IsPlayer)
            {
                if (!PVPSanctuaryService.IsPVPAttackAllowed(activator.Object, target.Object))
                {
                    return(false);
                }
            }

            // Activator and target must be in the same area and within line of sight.
            if (activator.Area.Resref != target.Area.Resref ||
                _.LineOfSightObject(activator.Object, target.Object) == false)
            {
                activator.SendMessage("You cannot see your target.");
                return(false);
            }

            // Run this perk's specific checks on whether the activator may use this perk on the target.
            string canCast = handler.CanCastSpell(activator, target, perkFeat.PerkLevelUnlocked);

            if (!string.IsNullOrWhiteSpace(canCast))
            {
                activator.SendMessage(canCast);
                return(false);
            }

            // Calculate the FP cost to use this ability. Verify activator has sufficient FP.
            int fpCost    = handler.FPCost(activator, handler.FPCost(activator, perkFeat.BaseFPCost, perkFeat.PerkLevelUnlocked), perkFeat.PerkLevelUnlocked);
            int currentFP = GetCurrentFP(activator);

            if (currentFP < fpCost)
            {
                activator.SendMessage("You do not have enough FP. (Required: " + fpCost + ". You have: " + currentFP + ")");
                return(false);
            }

            // Verify activator isn't busy or dead.
            if (activator.IsBusy || activator.CurrentHP <= 0)
            {
                activator.SendMessage("You are too busy to activate that ability.");
                return(false);
            }

            // verify activator is commandable. https://github.com/zunath/SWLOR_NWN/issues/940#issue-467175951
            if (!activator.IsCommandable)
            {
                activator.SendMessage("You cannot take actions currently.");
                return(false);
            }

            // If we're executing a concentration ability, check and see if the activator currently has this ability
            // active. If it's active, then we immediately remove its effect and bail out.
            // Any other ability (including other concentration abilities) execute as normal.
            if (perk.ExecutionTypeID == PerkExecutionType.ConcentrationAbility)
            {
                // Retrieve the concentration effect for this creature.
                var concentrationEffect = GetActiveConcentrationEffect(activator);
                if ((int)concentrationEffect.Type == perk.ID)
                {
                    // It's active. Time to disable it.
                    EndConcentrationEffect(activator);
                    activator.SendMessage("Concentration ability '" + perk.Name + "' deactivated.");
                    SendAOEMessage(activator, activator.Name + " deactivates concentration ability '" + perk.Name + "'.");
                    return(false);
                }
            }

            // Retrieve the cooldown information and determine the unlock time.
            int?     cooldownCategoryID = handler.CooldownCategoryID(activator, perk.CooldownCategoryID, perkFeat.PerkLevelUnlocked);
            DateTime now            = DateTime.UtcNow;
            DateTime unlockDateTime = cooldownCategoryID == null ? now : GetAbilityCooldownUnlocked(activator, (int)cooldownCategoryID);

            // Check if we've passed the unlock date. Exit early if we have not.
            if (unlockDateTime > now)
            {
                string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false);
                activator.SendMessage("That ability can be used in " + timeToWait + ".");
                return(false);
            }

            // Passed all checks. Return true.
            return(true);
        }
Beispiel #8
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);
                }
            }
        }
Beispiel #9
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);
        }
Beispiel #10
0
        private static void OnModuleUseFeat()
        {
            NWPlayer   pc       = Object.OBJECT_SELF;
            NWCreature target   = NWNXEvents.OnFeatUsed_GetTarget().Object;
            int        featID   = NWNXEvents.OnFeatUsed_GetFeatID();
            var        perkFeat = DataService.SingleOrDefault <PerkFeat>(x => x.FeatID == featID);

            if (perkFeat == null)
            {
                return;
            }
            Data.Entity.Perk perk = DataService.GetAll <Data.Entity.Perk>().SingleOrDefault(x => x.ID == perkFeat.PerkID);
            if (perk == null)
            {
                return;
            }

            // Check to see if we are a spaceship.  Spaceships can't use abilities...
            if (pc.GetLocalInt("IS_SHIP") > 0 || pc.GetLocalInt("IS_GUNNER") > 0)
            {
                pc.SendMessage("You cannot use that ability while piloting a ship.");
                return;
            }

            var perkAction = PerkService.GetPerkHandler(perkFeat.PerkID);

            Player playerEntity = DataService.Get <Player>(pc.GlobalID);
            int    pcPerkLevel  = PerkService.GetPCPerkLevel(pc, perk.ID);

            // If player is disabling an existing stance, remove that effect.
            if (perk.ExecutionTypeID == (int)PerkExecutionType.Stance)
            {
                PCCustomEffect stanceEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.StancePerkID == perk.ID &&
                                                                                           x.PlayerID == pc.GlobalID);

                if (stanceEffect != null)
                {
                    if (CustomEffectService.RemoveStance(pc))
                    {
                        return;
                    }
                }
            }

            if (pcPerkLevel <= 0)
            {
                pc.SendMessage("You do not meet the prerequisites to use this ability.");
                return;
            }

            if (perkAction.IsHostile() && target.IsPlayer)
            {
                if (!PVPSanctuaryService.IsPVPAttackAllowed(pc, target.Object))
                {
                    return;
                }
            }

            if (pc.Area.Resref != target.Area.Resref ||
                _.LineOfSightObject(pc.Object, target.Object) == 0)
            {
                pc.SendMessage("You cannot see your target.");
                return;
            }

            if (!perkAction.CanCastSpell(pc, target))
            {
                pc.SendMessage(perkAction.CannotCastSpellMessage(pc, target) ?? "That ability cannot be used at this time.");
                return;
            }

            int fpCost = perkAction.FPCost(pc, perkAction.FPCost(pc, perk.BaseFPCost, featID), featID);

            if (playerEntity.CurrentFP < fpCost)
            {
                pc.SendMessage("You do not have enough FP. (Required: " + fpCost + ". You have: " + playerEntity.CurrentFP + ")");
                return;
            }

            if (pc.IsBusy || pc.CurrentHP <= 0)
            {
                pc.SendMessage("You are too busy to activate that ability.");
                return;
            }

            // Check cooldown
            int?       cooldownCategoryID = perkAction.CooldownCategoryID(pc, perk.CooldownCategoryID, featID);
            PCCooldown pcCooldown         = DataService.GetAll <PCCooldown>().SingleOrDefault(x => x.PlayerID == pc.GlobalID &&
                                                                                              x.CooldownCategoryID == cooldownCategoryID);

            if (pcCooldown == null)
            {
                pcCooldown = new PCCooldown
                {
                    CooldownCategoryID = Convert.ToInt32(cooldownCategoryID),
                    DateUnlocked       = DateTime.UtcNow.AddSeconds(-1),
                    PlayerID           = pc.GlobalID
                };

                DataService.SubmitDataChange(pcCooldown, DatabaseActionType.Insert);
            }

            DateTime unlockDateTime = pcCooldown.DateUnlocked;
            DateTime now            = DateTime.UtcNow;

            if (unlockDateTime > now)
            {
                string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false);
                pc.SendMessage("That ability can be used in " + timeToWait + ".");
                return;
            }

            // Force Abilities (aka Spells)
            if (perk.ExecutionTypeID == (int)PerkExecutionType.ForceAbility)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_FORCE);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.ForceAbility, featID);
            }
            // Combat Abilities
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.CombatAbility)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_PHYSICAL);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.CombatAbility, featID);
            }
            // Queued Weapon Skills
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.QueuedWeaponSkill)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_PHYSICAL);
                HandleQueueWeaponSkill(pc, perk, perkAction, featID);
            }
            // Stances
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.Stance)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_COMBATABILITY);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.Stance, featID);
            }
        }
Beispiel #11
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);
        }