Exemple #1
0
        public static int CalculateReassemblyChance(NWPlayer player, int penalty)
        {
            const int BaseChance  = 70;
            int       harvesting  = SkillService.GetPCSkillRank(player, SkillType.Harvesting);
            var       itemBonuses = PlayerStatService.GetPlayerItemEffectiveStats(player);
            int       perkLevel   = PerkService.GetCreaturePerkLevel(player, PerkType.MolecularReassemblyProficiency);

            // Calculate the base chance after factoring in skills, perks, and items.
            int categoryChance = (int)(BaseChance + (harvesting / 2.5f) + perkLevel * 10 + itemBonuses.Harvesting / 3f);

            // Reduce the chance by the penalty. This penalty is generally determined by how many properties were already
            // applied during this batch.
            categoryChance -= penalty;

            // Keep bounds between 0 and 100
            if (categoryChance < 0)
            {
                return(0);
            }
            else if (categoryChance > 100)
            {
                return(100);
            }
            else
            {
                return(categoryChance);
            }
        }
Exemple #2
0
        public static int CalculateChanceForComponentBonus(NWPlayer player, int tier, ResourceQuality quality, bool scavenging = false)
        {
            int rank       = (scavenging ? SkillService.GetPCSkillRank(player, SkillType.Scavenging) : SkillService.GetPCSkillRank(player, SkillType.Harvesting));
            int difficulty = (tier - 1) * 10 + GetDifficultyAdjustment(quality);
            int delta      = difficulty - rank;

            if (delta >= 7)
            {
                return(0);
            }
            if (delta <= -7)
            {
                return(45);
            }

            int chance = 0;

            switch (delta)
            {
            case 6: chance = 1; break;

            case 5: chance = 2; break;

            case 4: chance = 3; break;

            case 3: chance = 6; break;

            case 2: chance = 9; break;

            case 1: chance = 12; break;

            case 0: chance = 15; break;

            case -1: chance = 18; break;

            case -2: chance = 20; break;

            case -3: chance = 21; break;

            case -4: chance = 23; break;

            case -5: chance = 25; break;

            case -6: chance = 27; break;
            }

            var effectiveStats = PlayerStatService.GetPlayerItemEffectiveStats(player);
            int itemBonus      = (scavenging ? effectiveStats.Scavenging : effectiveStats.Harvesting) / 2;

            if (itemBonus > 30)
            {
                itemBonus = 30;
            }
            chance += itemBonus;

            return(chance);
        }
        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);
        }
Exemple #4
0
        private static void OnModuleApplyDamage()
        {
            var data = NWNXDamage.GetDamageEventData();

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

            NWObject damager = data.Damager;

            if (!damager.IsPlayer)
            {
                return;
            }
            NWCreature target = NWGameObject.OBJECT_SELF;

            // Check that this was a normal attack, and not (say) a damage over time effect.
            if (target.GetLocalInt(AbilityService.LAST_ATTACK + damager.GlobalID) != AbilityService.ATTACK_PHYSICAL)
            {
                return;
            }

            NWItem weapon      = (_.GetLastWeaponUsed(damager.Object));
            int    damageBonus = weapon.DamageBonus;

            NWPlayer  player    = (damager.Object);
            int       itemLevel = weapon.RecommendedLevel;
            SkillType skill     = ItemService.GetSkillTypeForItem(weapon);

            if (skill == SkillType.Unknown)
            {
                return;
            }

            int rank  = SkillService.GetPCSkillRank(player, skill);
            int delta = itemLevel - rank;

            if (delta >= 1)
            {
                damageBonus--;
            }
            damageBonus = damageBonus - delta / 5;

            if (damageBonus <= 0)
            {
                damageBonus = 0;
            }

            data.Base += damageBonus;
            NWNXDamage.SetDamageEventData(data);
        }
Exemple #5
0
        public static bool OnModuleExamine(NWPlayer examiner, NWObject target)
        {
            string backupDescription = target.GetLocalString("BACKUP_DESCRIPTION");

            if (!string.IsNullOrWhiteSpace(backupDescription))
            {
                target.UnidentifiedDescription = backupDescription;
            }
            if (!examiner.IsDM || !target.IsPlayer || target.IsDM)
            {
                return(false);
            }

            backupDescription = target.IdentifiedDescription;
            target.SetLocalString("BACKUP_DESCRIPTION", backupDescription);
            Player playerEntity    = DataService.Player.GetByID(target.GlobalID);
            NWArea area            = NWModule.Get().Areas.Single(x => x.Resref == playerEntity.RespawnAreaResref);
            string respawnAreaName = area.Name;

            StringBuilder description =
                new StringBuilder(
                    ColorTokenService.Green("ID: ") + target.GlobalID + "\n" +
                    ColorTokenService.Green("Character Name: ") + target.Name + "\n" +
                    ColorTokenService.Green("Respawn Area: ") + respawnAreaName + "\n" +
                    ColorTokenService.Green("Skill Points: ") + playerEntity.TotalSPAcquired + " (Unallocated: " + playerEntity.UnallocatedSP + ")" + "\n" +
                    ColorTokenService.Green("FP: ") + playerEntity.CurrentFP + " / " + playerEntity.MaxFP + "\n" +
                    ColorTokenService.Green("Skill Levels: ") + "\n\n");

            List <PCSkill> pcSkills = SkillService.GetAllPCSkills(target.Object);

            foreach (PCSkill pcSkill in pcSkills)
            {
                Skill skill = SkillService.GetSkill(pcSkill.SkillID);
                description.Append(skill.Name).Append(" rank ").Append(pcSkill.Rank).AppendLine();
            }

            description.Append("\n\n").Append(ColorTokenService.Green("Perks: ")).Append("\n\n");

            var pcPerks = DataService.PCPerk.GetAllByPlayerID(target.GlobalID);

            foreach (PCPerk pcPerk in pcPerks)
            {
                var perk = DataService.Perk.GetByID(pcPerk.PerkID);
                description.Append(perk.Name).Append(" Lvl. ").Append(pcPerk.PerkLevel).AppendLine();
            }

            description.Append("\n\n").Append(ColorTokenService.Green("Description: \n\n")).Append(backupDescription).AppendLine();
            target.UnidentifiedDescription = description.ToString();
            _.DelayCommand(0.1f, () => { _.SetDescription(target, backupDescription, false); });
            return(true);
        }
Exemple #6
0
        public static string TranslateSnippetForListener(NWObject speaker, NWObject listener, SkillType language, string snippet)
        {
            Dictionary <SkillType, Type> map = new Dictionary <SkillType, Type>
            {
                { SkillType.Bothese, typeof(TranslatorBothese) },
                { SkillType.Catharese, typeof(TranslatorCatharese) },
                { SkillType.Cheunh, typeof(TranslatorCheunh) },
                { SkillType.Dosh, typeof(TranslatorDosh) },
                { SkillType.Droidspeak, typeof(TranslatorDroidspeak) },
                { SkillType.Huttese, typeof(TranslatorHuttese) },
                { SkillType.Mandoa, typeof(TranslatorMandoa) },
                { SkillType.Shyriiwook, typeof(TranslatorShyriiwook) },
                { SkillType.Twileki, typeof(TranslatorTwileki) },
                { SkillType.Zabraki, typeof(TranslatorZabraki) },
                { SkillType.Mirialan, typeof(TranslatorMirialan) },
                { SkillType.MonCalamarian, typeof(TranslatorMonCalamarian) },
                { SkillType.Ugnaught, typeof(TranslatorUgnaught) }
            };

            Type type = typeof(TranslatorGeneric);

            map.TryGetValue(language, out type);
            ITranslator translator = (ITranslator)Activator.CreateInstance(type);

            if (speaker.IsPC && !speaker.IsDM)
            {
                // Get the rank and max rank for the speaker, and garble their English text based on it.
                NWPlayer speakerAsPlayer     = speaker.Object;
                int      speakerSkillRank    = SkillService.GetPCSkillRank(speakerAsPlayer, language);
                int      speakerSkillMaxRank = SkillService.GetSkill(language).MaxRank;

                if (speakerSkillRank != speakerSkillMaxRank)
                {
                    int garbledChance = 100 - (int)(((float)speakerSkillRank / (float)speakerSkillMaxRank) * 100);

                    string[] split = snippet.Split(' ');
                    for (int i = 0; i < split.Length; ++i)
                    {
                        if (RandomService.Random(100) <= garbledChance)
                        {
                            split[i] = new string(split[i].ToCharArray().OrderBy(s => (RandomService.Random(2) % 2) == 0).ToArray());
                        }
                    }

                    snippet = split.Aggregate((a, b) => a + " " + b);
                }
            }

            if (!listener.IsPC || listener.IsDM)
            {
                // Short circuit for a DM or NPC - they will always understand the text.
                return(snippet);
            }

            // Let's grab the max rank for the listener skill, and then we roll for a successful translate based on that.
            NWPlayer listenerAsPlayer = listener.Object;
            int      rank             = SkillService.GetPCSkillRank(listenerAsPlayer, language);
            int      maxRank          = SkillService.GetSkill(language).MaxRank;

            // Check for the Comprehend Speech concentration ability.
            Player dbPlayer     = DataService.Player.GetByID(listenerAsPlayer.GlobalID);
            bool   grantSenseXP = false;

            if (dbPlayer.ActiveConcentrationPerkID == (int)PerkType.ComprehendSpeech)
            {
                int bonus = 5 * dbPlayer.ActiveConcentrationTier;
                rank        += bonus;
                grantSenseXP = true;
            }

            // Ensure we don't go over the maximum.
            if (rank > maxRank)
            {
                rank = maxRank;
            }

            if (rank == maxRank || speaker == listener)
            {
                // Guaranteed success - return original.
                return(snippet);
            }

            string textAsForeignLanguage = translator.Translate(snippet);

            if (rank != 0)
            {
                int englishChance = (int)(((float)rank / (float)maxRank) * 100);

                string[] originalSplit = snippet.Split(' ');
                string[] foreignSplit  = textAsForeignLanguage.Split(' ');

                StringBuilder endResult = new StringBuilder();

                // WARNING: We're making the assumption that originalSplit.Length == foreignSplit.Length.
                // If this assumption changes, the below logic needs to change too.
                for (int i = 0; i < originalSplit.Length; ++i)
                {
                    if (RandomService.Random(100) <= englishChance)
                    {
                        endResult.Append(originalSplit[i]);
                    }
                    else
                    {
                        endResult.Append(foreignSplit[i]);
                    }

                    endResult.Append(" ");
                }

                textAsForeignLanguage = endResult.ToString();
            }

            long now             = DateTime.Now.Ticks;
            int  lastSkillUpLow  = listenerAsPlayer.GetLocalInt("LAST_LANGUAGE_SKILL_INCREASE_LOW");
            int  lastSkillUpHigh = listenerAsPlayer.GetLocalInt("LAST_LANGUAGE_SKILL_INCREASE_HIGH");
            long lastSkillUp     = lastSkillUpHigh;

            lastSkillUp = (lastSkillUp << 32) | (uint)lastSkillUpLow;
            long differenceInSeconds = (now - lastSkillUp) / 10000000;

            if (differenceInSeconds / 60 >= 2)
            {
                int amount = Math.Max(10, Math.Min(150, snippet.Length) / 3);
                // Reward exp towards the language - we scale this with character count, maxing at 50 exp for 150 characters.
                SkillService.GiveSkillXP(listenerAsPlayer, language, amount);

                // Grant Sense XP if player is concentrating Comprehend Speech.
                if (grantSenseXP)
                {
                    SkillService.GiveSkillXP(listenerAsPlayer, SkillType.ForceSense, amount * 10);
                }

                listenerAsPlayer.SetLocalInt("LAST_LANGUAGE_SKILL_INCREASE_LOW", (int)(now & 0xFFFFFFFF));
                listenerAsPlayer.SetLocalInt("LAST_LANGUAGE_SKILL_INCREASE_HIGH", (int)((now >> 32) & 0xFFFFFFFF));
            }

            return(textAsForeignLanguage);
        }
Exemple #7
0
        public static void CalculateEffectiveStats(NWPlayer player, NWItem item)
        {
            if (item == null || !item.IsValid || !player.IsPlayer || player.IsDMPossessed || player.IsDM || !player.IsInitializedAsPlayer)
            {
                return;
            }

            // Calculating effective stats can be expensive, so we cache it on the item.
            SkillType skill;

            if (item.BaseItemType == BaseItem.Amulet || item.BaseItemType == BaseItem.Ring)
            {
                var forceArmor = SkillService.GetPCSkill(player, (int)SkillType.ForceArmor);
                var lightArmor = SkillService.GetPCSkill(player, (int)SkillType.LightArmor);
                var heavyArmor = SkillService.GetPCSkill(player, (int)SkillType.HeavyArmor);
                var highest    = forceArmor.Rank;
                skill = SkillType.ForceArmor;

                if (lightArmor.Rank > highest)
                {
                    highest = lightArmor.Rank;
                    skill   = SkillType.LightArmor;
                }
                if (heavyArmor.Rank > highest)
                {
                    skill = SkillType.HeavyArmor;
                }
            }
            else
            {
                skill = ItemService.GetSkillTypeForItem(item);
            }

            var rank = DataService.PCSkill.GetByPlayerIDAndSkillID(player.GlobalID, (int)skill).Rank;

            using (new Profiler("PlayerStatService::ApplyStatChanges::GetPlayerItemEffectiveStats::ItemLoop::CalculateEffectiveStats"))
            {
                // Only scale cooldown recovery if it's a bonus. Penalties remain regardless of skill level difference.
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_COOLDOWN_RECOVERY", item.CooldownRecovery > 0
                    ? CalculateAdjustedValue(item.CooldownRecovery, item.RecommendedLevel, rank, 1)
                    : item.CooldownRecovery);

                item.SetLocalFloat("STAT_EFFECTIVE_LEVEL_ENMITY_RATE", CalculateAdjustedValue(0.01f * item.EnmityRate, item.RecommendedLevel, rank, 0.00f));

                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_LUCK_BONUS", CalculateAdjustedValue(item.LuckBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_MEDITATE_BONUS", CalculateAdjustedValue(item.MeditateBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_REST_BONUS", CalculateAdjustedValue(item.RestBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_MEDICINE_BONUS", CalculateAdjustedValue(item.MedicineBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HP_REGEN_BONUS", CalculateAdjustedValue(item.HPRegenBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FP_REGEN_BONUS", CalculateAdjustedValue(item.FPRegenBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_WEAPONSMITH_BONUS", CalculateAdjustedValue(item.CraftBonusWeaponsmith, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_COOKING_BONUS", CalculateAdjustedValue(item.CraftBonusCooking, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_ENGINEERING_BONUS", CalculateAdjustedValue(item.CraftBonusEngineering, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FABRICATION_BONUS", CalculateAdjustedValue(item.CraftBonusFabrication, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_ARMORSMITH_BONUS", CalculateAdjustedValue(item.CraftBonusArmorsmith, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HARVESTING_BONUS", CalculateAdjustedValue(item.HarvestingBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_PILOTING_BONUS", CalculateAdjustedValue(item.PilotingBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_SCAVENGING_BONUS", CalculateAdjustedValue(item.ScavengingBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_SNEAK_ATTACK_BONUS", CalculateAdjustedValue(item.SneakAttackBonus, item.RecommendedLevel, rank, 0));

                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_STRENGTH_BONUS", CalculateAdjustedValue(item.StrengthBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_DEXTERITY_BONUS", CalculateAdjustedValue(item.DexterityBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_CONSTITUTION_BONUS", CalculateAdjustedValue(item.ConstitutionBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_WISDOM_BONUS", CalculateAdjustedValue(item.WisdomBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_INTELLIGENCE_BONUS", CalculateAdjustedValue(item.IntelligenceBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_CHARISMA_BONUS", CalculateAdjustedValue(item.CharismaBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_HP_BONUS", CalculateAdjustedValue(item.HPBonus, item.RecommendedLevel, rank, 0));
                item.SetLocalInt("STAT_EFFECTIVE_LEVEL_FP_BONUS", CalculateAdjustedValue(item.FPBonus, item.RecommendedLevel, rank, 0));
            }
        }
Exemple #8
0
        private static void OnModuleApplyDamage()
        {
            var data = NWNXDamage.GetDamageEventData();

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

            NWObject damager = data.Damager;

            if (!damager.IsPlayer)
            {
                return;
            }
            NWCreature target = _.OBJECT_SELF;

            // Check that this was a normal attack, and not (say) a damage over time effect.
            if (target.GetLocalInt(AbilityService.LAST_ATTACK + damager.GlobalID) != AbilityService.ATTACK_PHYSICAL)
            {
                return;
            }

            NWItem weapon = (_.GetLastWeaponUsed(damager.Object));

            if (!weapon.IsValid)
            {
                // Double weapons don't show up correctly when their offhand makes an attack.
                // So check for that case here.
                if (_.GetObjectType(damager) == ObjectType.Creature)
                {
                    NWCreature attacker = data.Damager.Object;

                    if (attacker.RightHand.BaseItemType == BaseItem.Saberstaff ||
                        attacker.RightHand.BaseItemType == BaseItem.TwoBladedSword ||
                        attacker.RightHand.BaseItemType == BaseItem.DoubleAxe ||
                        attacker.RightHand.BaseItemType == BaseItem.DireMace)
                    {
                        weapon = attacker.RightHand;
                    }
                }
            }

            int damageBonus = weapon.DamageBonus;

            NWPlayer  player    = (damager.Object);
            int       itemLevel = weapon.RecommendedLevel;
            SkillType skill     = ItemService.GetSkillTypeForItem(weapon);

            if (skill == SkillType.Unknown)
            {
                return;
            }

            int rank  = SkillService.GetPCSkillRank(player, skill);
            int delta = itemLevel - rank;

            if (delta >= 1)
            {
                damageBonus--;
            }
            damageBonus = damageBonus - delta / 5;

            if (damageBonus <= 0)
            {
                damageBonus = 0;
            }

            data.Base += damageBonus;
            NWNXDamage.SetDamageEventData(data);
        }
Exemple #9
0
        /// <summary>
        /// Calculates ability resistance for an ability.
        /// The attacker and defender's skills, ability modifiers, and balance affinity will be
        /// used to make this determination.
        /// </summary>
        /// <param name="attacker">The creature using the ability.</param>
        /// <param name="defender">The creature being targeted by the ability.</param>
        /// <param name="skill">The skill used for this ability.</param>
        /// <param name="balanceType">The force balance type to use for this ability.</param>
        /// <param name="sendRollMessage">If true, the roll message will be sent. Otherwise it won't be.</param>
        /// <returns>Data regarding the ability resistance roll</returns>
        public static AbilityResistanceResult CalculateAbilityResistance(NWCreature attacker, NWCreature defender, SkillType skill, ForceBalanceType balanceType, bool sendRollMessage = true)
        {
            int abilityScoreType;

            switch (skill)
            {
            case SkillType.ForceAlter:
                abilityScoreType = ABILITY_INTELLIGENCE;
                break;

            case SkillType.ForceControl:
                abilityScoreType = ABILITY_WISDOM;
                break;

            case SkillType.ForceSense:
                abilityScoreType = ABILITY_CHARISMA;
                break;

            default:
                throw new ArgumentException("Invalid skill type called for " + nameof(CalculateAbilityResistance) + ", value '" + skill + "' not supported.");
            }


            AbilityResistanceResult result = new AbilityResistanceResult();

            int attackerSkill   = SkillService.GetPCSkillRank(attacker.Object, skill);
            int attackerAbility = _.GetAbilityModifier(abilityScoreType, attacker);

            int defenderSkill   = SkillService.GetPCSkillRank(defender.Object, skill);
            int defenderAbility = _.GetAbilityModifier(abilityScoreType, defender);

            // If the defender is equipped with a lightsaber, we check their lightsaber skill
            if (defender.RightHand.CustomItemType == CustomItemType.Lightsaber ||
                defender.LeftHand.CustomItemType == CustomItemType.Lightsaber)
            {
                int lightsaberSkill = SkillService.GetPCSkillRank(defender.Object, SkillType.Lightsaber);
                if (lightsaberSkill > defenderSkill)
                {
                    defenderSkill = lightsaberSkill;
                }
            }

            // If the defender's martial arts skill is greater than the current skill they're using, we'll use that instead.
            int defenderMASkill = SkillService.GetPCSkillRank(defender.Object, SkillType.MartialArts);

            if (defenderMASkill > defenderSkill)
            {
                defenderSkill = defenderMASkill;
            }

            int attackerAffinity = 0;
            int defenderAffinity = 0;

            // Only check affinity if ability has a force balance type.
            if (balanceType == ForceBalanceType.Dark || balanceType == ForceBalanceType.Light)
            {
                attackerAffinity = GetBalanceAffinity(attacker.Object, balanceType);
                defenderAffinity = GetBalanceAffinity(defender.Object, balanceType);
            }

            float attackerCR = attacker.IsPlayer ? 0f : attacker.ChallengeRating * 5f;
            float defenderCR = defender.IsPlayer ? 0f : defender.ChallengeRating * 5f;

            float attackerTotal = attackerSkill + attackerAbility + attackerAffinity + attackerCR;
            float defenderTotal = defenderSkill + defenderAbility + defenderAffinity + defenderCR;
            float divisor       = attackerTotal + defenderTotal + 1; // +1 to prevent division by zero.

            //Console.WriteLine("attackerCR = " + attackerCR);
            //Console.WriteLine("defenderCR = " + defenderCR);
            //Console.WriteLine("attackerSkill = " + attackerSkill);
            //Console.WriteLine("attackerAbility = " + attackerAbility);
            //Console.WriteLine("attackerAffinity = " + attackerAffinity);
            //Console.WriteLine("defenderSkill = " + defenderSkill);
            //Console.WriteLine("defenderAbility = " + defenderAbility);
            //Console.WriteLine("defenderAffinity = " + defenderAffinity);
            //Console.WriteLine("attackerTotal = " + attackerTotal);
            //Console.WriteLine("defenderTotal = " + defenderTotal);
            //Console.WriteLine("divisor = " + divisor);

            result.DC   = (int)(attackerTotal / divisor * 100);
            result.Roll = RandomService.D100(1);

            if (sendRollMessage)
            {
                string resisted = result.IsResisted ? ColorTokenService.Red(" [RESISTED " + Math.Abs(result.Delta) + "%]") : string.Empty;
                string message  = ColorTokenService.SavingThrow("Roll: " + result.Roll + " VS " + result.DC + " DC") + resisted;
                attacker.SendMessage(message);
                defender.SendMessage(message);
            }

            return(result);
        }
Exemple #10
0
        private static void HandleDamageImmunity()
        {
            DamageEventData data = NWNXDamage.GetDamageEventData();

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

            NWCreature target = NWGameObject.OBJECT_SELF;
            NWItem     shield = target.LeftHand;
            var        concentrationEffect = AbilityService.GetActiveConcentrationEffect(target);
            double     reduction           = 0.0f;

            // Shield damage reduction and absorb energy are calculated here. They don't stack, so the one
            // with the highest reduction will take precedence.

            // Calculate shield damage reduction.
            if (ItemService.ShieldBaseItemTypes.Contains(shield.BaseItemType))
            {
                // Apply damage scaling based on shield presence
                int   perkLevel = PerkService.GetCreaturePerkLevel(target.Object, PerkType.ShieldProficiency);
                float perkBonus = 0.02f * perkLevel;

                // DI = 10% + 1% / 3 AC bonuses on the shield + 2% per perk bonus.
                reduction = (0.1 + 0.01 * shield.AC / 3) + perkBonus;
            }
            // Calculate Absorb Energy concentration effect reduction.
            if (concentrationEffect.Type == PerkType.AbsorbEnergy)
            {
                double perkReduction = concentrationEffect.Tier * 0.1;
                if (perkReduction > reduction)
                {
                    reduction = perkReduction;
                    // Calculate and award force XP based on total damage reduced.
                    int xp = (int)(data.Total * reduction * 3);
                    if (xp < 5)
                    {
                        xp = 5;
                    }

                    SkillService.GiveSkillXP(target.Object, SkillType.ForceControl, xp);
                    // Play a visual effect signifying the ability was activated.
                    _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_BLUR), target, 0.5f);
                }
            }

            // No reduction found. Bail out early.
            if (reduction <= 0.0f)
            {
                return;
            }

            target.SendMessage("Damage reduced by " + (int)(reduction * 100) + "%");
            reduction = 1.0f - reduction;

            data.Bludgeoning = (int)(data.Bludgeoning * reduction);
            data.Pierce      = (int)(data.Pierce * reduction);
            data.Slash       = (int)(data.Slash * reduction);
            data.Magical     = (int)(data.Magical * reduction);
            data.Acid        = (int)(data.Acid * reduction);
            data.Cold        = (int)(data.Cold * reduction);
            data.Divine      = (int)(data.Divine * reduction);
            data.Electrical  = (int)(data.Electrical * reduction);
            data.Fire        = (int)(data.Fire * reduction);
            data.Negative    = (int)(data.Negative * reduction);
            data.Positive    = (int)(data.Positive * reduction);
            data.Sonic       = (int)(data.Sonic * reduction);
            data.Base        = (int)(data.Base * reduction);

            NWNXDamage.SetDamageEventData(data);
        }