예제 #1
0
        public static ItemVO PickRandomItemFromLootTable(int lootTableID)
        {
            if (lootTableID <= 0)
            {
                return(null);
            }
            var lootTableItems = DataService.LootTableItem.GetAllByLootTableID(lootTableID).ToList();

            if (lootTableItems.Count <= 0)
            {
                return(null);
            }
            int[] weights = new int[lootTableItems.Count];
            for (int x = 0; x < lootTableItems.Count; x++)
            {
                weights[x] = lootTableItems.ElementAt(x).Weight;
            }

            int           randomIndex = RandomService.GetRandomWeightedIndex(weights);
            LootTableItem itemEntity  = lootTableItems.ElementAt(randomIndex);
            int           quantity    = RandomService.Random(itemEntity.MaxQuantity) + 1;
            ItemVO        result      = new ItemVO
            {
                Quantity  = quantity,
                Resref    = itemEntity.Resref,
                SpawnRule = itemEntity.SpawnRule
            };

            return(result);
        }
예제 #2
0
        /// <summary>
        /// Cycle out the available guild tasks if the previous set has been available for 24 hours.
        /// </summary>
        private static void OnModuleLoad()
        {
            var config = DataService.Get <ServerConfiguration>(1);
            var now    = DateTime.UtcNow;

            // 24 hours haven't passed since the last cycle. Bail out now.
            if (now < config.LastGuildTaskUpdate.AddHours(24))
            {
                return;
            }

            // Start by marking the existing tasks as not currently offered.
            foreach (var task in DataService.Where <GuildTask>(x => x.IsCurrentlyOffered))
            {
                task.IsCurrentlyOffered = false;
                DataService.SubmitDataChange(task, DatabaseActionType.Update);
            }

            int maxRank = RankProgression.Keys.Max();

            // Active available tasks are grouped by GuildID and RequiredRank.
            // 10 of each are randomly selected and marked as currently offered.
            // This makes them appear in the dialog menu for players.
            // If there are 10 or less available tasks, all of them will be enabled and no randomization will occur.
            foreach (var guild in DataService.GetAll <Guild>())
            {
                for (int rank = 0; rank <= maxRank; rank++)
                {
                    var rank1          = rank; // VS recommends copying the variable. Unsure why.
                    var potentialTasks = DataService.Where <GuildTask>(x => x.GuildID == guild.ID &&
                                                                       x.RequiredRank == rank1);
                    IEnumerable <GuildTask> tasks;

                    // Need at least 11 tasks to randomize. We have ten or less. Simply enable all of these.
                    if (potentialTasks.Count <= 10)
                    {
                        tasks = potentialTasks;
                    }
                    // Pick 10 tasks randomly out of the potential list.
                    else
                    {
                        tasks = potentialTasks.OrderBy(o => RandomService.Random()).Take(10);
                    }

                    // We've got our set of tasks. Mark them as currently offered and submit the data change.
                    foreach (var task in tasks)
                    {
                        task.IsCurrentlyOffered = true;
                        DataService.SubmitDataChange(task, DatabaseActionType.Update);
                    }
                }
            }

            // Update the server config and mark the timestamp.
            config.LastGuildTaskUpdate = now;
            DataService.SubmitDataChange(config, DatabaseActionType.Update);
        }
예제 #3
0
        public static Location GetRandomSpawnPoint(NWArea area)
        {
            var walkmeshes = AreaService.GetAreaWalkmeshes(area);
            int count      = walkmeshes.Count;
            var index      = count <= 0 ? 0 : RandomService.Random(count);

            var spawnPoint = walkmeshes[index];

            return(Location(area.Object,
                            Vector((float)spawnPoint.LocationX, (float)spawnPoint.LocationY, (float)spawnPoint.LocationZ),
                            RandomService.RandomFloat(0, 360)));
        }
예제 #4
0
        public static Location GetRandomSpawnPoint(NWArea area)
        {
            Area dbArea     = DataService.Area.GetByResref(area.Resref);
            var  walkmeshes = DataService.AreaWalkmesh.GetAllByAreaID(dbArea.ID).ToList();
            int  count      = walkmeshes.Count;
            var  index      = count <= 0 ? 0 : RandomService.Random(count);

            var spawnPoint = walkmeshes[index];

            return(Location(area.Object,
                            Vector((float)spawnPoint.LocationX, (float)spawnPoint.LocationY, (float)spawnPoint.LocationZ),
                            RandomService.RandomFloat(0, 360)));
        }
예제 #5
0
        private static void RunLootAttempt(NWCreature target, int lootTableID, int chance, int attempts)
        {
            if (chance <= 0)
            {
                chance = 75;
            }
            else if (chance > 100)
            {
                chance = 100;
            }

            if (attempts <= 0)
            {
                attempts = 1;
            }

            for (int a = 1; a <= attempts; a++)
            {
                if (RandomService.Random(100) + 1 <= chance)
                {
                    ItemVO model = PickRandomItemFromLootTable(lootTableID);
                    if (model == null)
                    {
                        continue;
                    }

                    int spawnQuantity = model.Quantity > 1 ? RandomService.Random(1, model.Quantity) : 1;

                    for (int x = 1; x <= spawnQuantity; x++)
                    {
                        var item = CreateItemOnObject(model.Resref, target);
                        if (!string.IsNullOrWhiteSpace(model.SpawnRule))
                        {
                            var rule = SpawnService.GetSpawnRule(model.SpawnRule);
                            rule.Run(item);
                        }
                    }
                }
            }
        }
예제 #6
0
        private static void SaveChestInventory(NWPlayer oPC, NWPlaceable oChest, bool resetTimeLock)
        {
            int          chestID = oChest.GetLocalInt(SearchSiteIDVariableName);
            PCSearchSite entity  = DataService.SingleOrDefault <PCSearchSite>(x => x.PlayerID == oPC.GlobalID && x.SearchSiteID == chestID);

            int      lockHours = RandomService.Random(2, 5);
            DateTime lockTime  = DateTime.UtcNow.AddHours(lockHours);

            if (entity != null)
            {
                if (resetTimeLock)
                {
                    lockTime = entity.UnlockDateTime;
                }
                DataService.SubmitDataChange(entity, DatabaseActionType.Delete);
            }

            entity = new PCSearchSite
            {
                PlayerID       = oPC.GlobalID,
                SearchSiteID   = chestID,
                UnlockDateTime = lockTime
            };

            foreach (NWItem item in oChest.InventoryItems)
            {
                if (item.GetLocalInt("QUEST_ID") <= 0)
                {
                    PCSearchSiteItem itemEntity = new PCSearchSiteItem
                    {
                        SearchItem   = SerializationService.Serialize(item),
                        SearchSiteID = entity.SearchSiteID
                    };

                    DataService.SubmitDataChange(itemEntity, DatabaseActionType.Insert);
                }
            }
        }
예제 #7
0
        private static ItemVO PickResultItem(int lootTableID)
        {
            var lootTableItems = DataService.Where <LootTableItem>(x => x.LootTableID == lootTableID).ToList();

            int[] weights = new int[lootTableItems.Count];

            for (int x = 0; x < lootTableItems.Count; x++)
            {
                weights[x] = lootTableItems.ElementAt(x).Weight;
            }
            int randomIndex = RandomService.GetRandomWeightedIndex(weights);

            LootTableItem itemEntity = lootTableItems.ElementAt(randomIndex);
            int           quantity   = RandomService.Random(itemEntity.MaxQuantity) + 1;

            ItemVO result = new ItemVO
            {
                Quantity = quantity,
                Resref   = itemEntity.Resref
            };

            return(result);
        }
예제 #8
0
        private static void RunSearchCycle(NWPlayer oPC, NWPlaceable oChest, int iDC)
        {
            int lootTable = oChest.GetLocalInt(SearchSiteLootTableVariableName);
            int skill     = _.GetSkillRank(_.SKILL_SEARCH, oPC.Object);

            if (skill > 10)
            {
                skill = 10;
            }
            else if (skill < 0)
            {
                skill = 0;
            }

            int roll         = RandomService.Random(20) + 1;
            int combinedRoll = roll + skill;

            if (roll + skill >= iDC)
            {
                oPC.FloatingText(ColorTokenService.SkillCheck("Search: *success*: (" + roll + " + " + skill + " = " + combinedRoll + " vs. DC: " + iDC + ")"));
                ItemVO spawnItem = PickResultItem(lootTable);

                if (!string.IsNullOrWhiteSpace(spawnItem.Resref) && spawnItem.Quantity > 0)
                {
                    NWItem foundItem     = (_.CreateItemOnObject(spawnItem.Resref, oChest.Object, spawnItem.Quantity, ""));
                    float  maxDurability = DurabilityService.GetMaxDurability(foundItem);
                    if (maxDurability > -1)
                    {
                        DurabilityService.SetDurability(foundItem, RandomService.RandomFloat() * maxDurability + 1);
                    }
                }
            }
            else
            {
                oPC.FloatingText(ColorTokenService.SkillCheck("Search: *failure*: (" + roll + " + " + skill + " = " + combinedRoll + " vs. DC: " + iDC + ")"));
            }
        }
예제 #9
0
        private static void InitializeAreaSpawns(NWArea area)
        {
            var areaSpawn = new AreaSpawn();

            // Check for manually placed spawns
            NWObject obj = GetFirstObjectInArea(area.Object);

            while (obj.IsValid)
            {
                bool isSpawn = obj.ObjectType == OBJECT_TYPE_WAYPOINT && obj.GetLocalInt("IS_SPAWN") == TRUE;

                if (isSpawn)
                {
                    int    spawnType       = obj.GetLocalInt("SPAWN_TYPE");
                    int    objectType      = spawnType == 0 || spawnType == OBJECT_TYPE_CREATURE ? OBJECT_TYPE_CREATURE : spawnType;
                    int    spawnTableID    = obj.GetLocalInt("SPAWN_TABLE_ID");
                    int    npcGroupID      = obj.GetLocalInt("SPAWN_NPC_GROUP_ID");
                    string behaviourScript = obj.GetLocalString("SPAWN_BEHAVIOUR_SCRIPT");
                    if (string.IsNullOrWhiteSpace(behaviourScript))
                    {
                        behaviourScript = obj.GetLocalString("SPAWN_BEHAVIOUR");
                    }

                    string  spawnResref = obj.GetLocalString("SPAWN_RESREF");
                    float   respawnTime = obj.GetLocalFloat("SPAWN_RESPAWN_SECONDS");
                    string  spawnRule   = obj.GetLocalString("SPAWN_RULE");
                    int     deathVFXID  = obj.GetLocalInt("SPAWN_DEATH_VFX");
                    AIFlags aiFlags     = (AIFlags)obj.GetLocalInt("SPAWN_AI_FLAGS");
                    bool    useResref   = true;

                    // No resref specified but a table was, look in the database for a random record.
                    if (string.IsNullOrWhiteSpace(spawnResref) && spawnTableID > 0)
                    {
                        // Pick a random record.
                        var spawnObjects = DataService.SpawnObject.GetAllBySpawnTableID(spawnTableID).ToList();
                        int count        = spawnObjects.Count;
                        int index        = count <= 0 ? 0 : RandomService.Random(count);
                        var dbSpawn      = spawnObjects[index];

                        if (dbSpawn != null)
                        {
                            spawnResref = dbSpawn.Resref;
                            useResref   = false;

                            if (dbSpawn.NPCGroupID != null && dbSpawn.NPCGroupID > 0)
                            {
                                npcGroupID = Convert.ToInt32(dbSpawn.NPCGroupID);
                            }

                            if (!string.IsNullOrWhiteSpace(dbSpawn.BehaviourScript))
                            {
                                behaviourScript = dbSpawn.BehaviourScript;
                            }

                            if (!string.IsNullOrWhiteSpace(dbSpawn.SpawnRule))
                            {
                                spawnRule = dbSpawn.SpawnRule;
                            }

                            if (deathVFXID <= 0)
                            {
                                deathVFXID = dbSpawn.DeathVFXID;
                            }

                            if (aiFlags == AIFlags.None)
                            {
                                aiFlags = dbSpawn.AIFlags;
                            }
                        }
                    }

                    // If we found a resref, spawn the object and add it to the cache.
                    if (!string.IsNullOrWhiteSpace(spawnResref))
                    {
                        // Delay the creation so that the iteration through the area doesn't get thrown off by new entries.
                        Location location   = obj.Location;
                        bool     isInstance = area.IsInstance;

                        ObjectSpawn newSpawn;
                        if (useResref)
                        {
                            newSpawn = new ObjectSpawn(location, true, spawnResref, respawnTime);
                        }
                        else
                        {
                            newSpawn = new ObjectSpawn(location, true, spawnTableID, respawnTime);
                        }

                        if (npcGroupID > 0)
                        {
                            newSpawn.NPCGroupID = npcGroupID;
                        }

                        if (deathVFXID > 0)
                        {
                            newSpawn.DeathVFXID = deathVFXID;
                        }

                        if (!string.IsNullOrWhiteSpace(behaviourScript))
                        {
                            newSpawn.BehaviourScript = behaviourScript;
                        }

                        if (!string.IsNullOrWhiteSpace(spawnRule))
                        {
                            newSpawn.SpawnRule = spawnRule;
                        }

                        if (aiFlags == AIFlags.None)
                        {
                            newSpawn.AIFlags = aiFlags;
                        }

                        // Instance spawns are one-shot.
                        if (isInstance)
                        {
                            newSpawn.Respawns = false;
                        }

                        if (objectType == OBJECT_TYPE_CREATURE)
                        {
                            areaSpawn.Creatures.Add(newSpawn);
                        }
                        else if (objectType == OBJECT_TYPE_PLACEABLE)
                        {
                            areaSpawn.Placeables.Add(newSpawn);
                        }
                    }
                }

                obj = GetNextObjectInArea(area.Object);
            }

            AreaSpawns.Add(area, areaSpawn);

            DelayCommand(1.0f, () =>
            {
                SpawnResources(area, areaSpawn);
            });
        }
예제 #10
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);
        }
예제 #11
0
        public static Tuple <ItemProperty, int> GetRandomComponentBonusIP(ResourceQuality quality)
        {
            string[] normalIP =
            {
                "compbon_arm1",         // Armorsmith 1
                "compbon_cspd1",        // Cooldown Recovery 1
                "compbon_charges1",     // Charges 1
                //"compbon_cooking1",     // Cooking 1
                "compbon_dmg1",         // Damage 1
                "compbon_eng1",         // Engineering 1
                "compbon_enmdown1",     // Enmity Down 1
                "compbon_harv1",        // Harvesting 1
                "compbon_wpn1",         // Weaponsmith 1
                "compbon_hp2",          // Hit Points 2
                "compbon_fp2",          // Force Points 2
                "compbon_enmup1",       // Enmity Up 1
                "compbon_med1",         // Meditate 1
                "compbon_faid1",        // Medicine 1
                "compbon_fab1",         // Fabrication 1
                "compbon_scanup1",      // Scanning 1
                "compbon_rest1",        // Rest 1
                "compbon_ab1"           // Attack Bonus 1
            };

            string[] highIP =
            {
                "compbon_arm2",         // Armorsmith 2
                "compbon_cspd2",        // Cooldown Recovery 2
                "compbon_charges2",     // Charges 2
                //"compbon_cooking2",     // Cooking 2
                "compbon_dmg2",         // Damage 2
                "compbon_eng2",         // Engineering 2
                "compbon_enmdown2",     // Enmity Down 2
                "compbon_harv2",        // Harvesting 2
                "compbon_wpn2",         // Weaponsmith 2
                "compbon_hp4",          // Hit Points 4
                "compbon_fp4",          // Force Points 4
                "compbon_enmup2",       // Enmity Up 2
                "compbon_luck1",        // Luck 1
                "compbon_med2",         // Meditate 2
                "compbon_faid2",        // Medicine 2
                "compbon_hpregen1",     // HP Regen 1
                "compbon_fpregen1",     // FP Regen 1
                "compbon_snkatk1",      // Sneak Attack 1
                "compbon_fab2",         // Fabrication 2
                "compbon_scanup2",      // Scanning 2
                "compbon_rest2",        // Rest 2
                "compbon_str1",         // Strength 1
                "compbon_dex1",         // Dexterity 1
                "compbon_con1",         // Constitution 1
                "compbon_wis1",         // Wisdom 1
                "compbon_int1",         // Intelligence 1
                "compbon_cha1",         // Charisma 1
                "compbon_ab2",          // Attack Bonus 2
                "compbon_scavup1"       // Scavenging 1
            };

            string[] veryHighIP =
            {
                "compbon_arm3",         // Armorsmith 3
                "compbon_cspd3",        // Cooldown Recovery 3
                //"compbon_cooking3",     // Cooking 3
                "compbon_charges3",     // Charges 3
                "compbon_dmg3",         // Damage 3
                "compbon_eng3",         // Engineering 3
                "compbon_enmdown3",     // Enmity Down 3
                "compbon_harv3",        // Harvesting 3
                "compbon_wpn3",         // Weaponsmith 3
                "compbon_hp6",          // Hit Points 6
                "compbon_fp6",          // Force Points 6
                "compbon_enmup3",       // Enmity Up 3
                "compbon_luck2",        // Luck 2
                "compbon_med3",         // Meditate 3
                "compbon_faid3",        // Medicine 3
                "compbon_hpregen2",     // HP Regen 2
                "compbon_fpregen2",     // FP Regen 2
                "compbon_snkatk2",      // Sneak Attack 2
                "compbon_fab3",         // Fabrication 3
                "compbon_scanup3",      // Scanning 3
                "compbon_rest3",        // Rest 3
                "compbon_str2",         // Strength 2
                "compbon_dex2",         // Dexterity 2
                "compbon_con2",         // Constitution 2
                "compbon_wis2",         // Wisdom 2
                "compbon_int2",         // Intelligence 2
                "compbon_cha2",         // Charisma 2
                "compbon_ab3",          // Attack Bonus 3
                "compbon_scavup2"       // Scavenging 2
            };

            string[] setToUse;

            switch (quality)
            {
            case ResourceQuality.Low:
            case ResourceQuality.Normal:
                setToUse = normalIP;
                break;

            case ResourceQuality.High:
                setToUse = highIP;
                break;

            case ResourceQuality.VeryHigh:
                setToUse = veryHighIP;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(quality), quality, null);
            }

            int    index   = RandomService.Random(0, setToUse.Length - 1);
            string itemTag = setToUse[index];

            return(new Tuple <ItemProperty, int>(ItemService.GetCustomItemPropertyByItemTag(itemTag), Colorize(itemTag)));
        }
예제 #12
0
        public static Tuple <ItemProperty, int> GetRandomComponentBonusIP(ResourceQuality quality)
        {
            string[] commonIP =
            {
                "compbon_ac1",
                "compbon_arm1",
                "compbon_cspd1",
                "compbon_charges1",
                "compbon_charges2",
                "compbon_cooking1",
                "compbon_dmg1",
                "compbon_dur1",
                "compbon_dur2",
                "compbon_eng1",
                "compbon_enmdown1",
                "compbon_epup1",
                "compbon_epdown1",
                "compbon_edup1",
                "compbon_eddown1",
                "compbon_dpdown1",
                "compbon_dpup1",
                "compbon_dddown1",
                "compbon_ddup1",
                "compbon_lpdown1",
                "compbon_lpup1",
                "compbon_lddown1",
                "compbon_ldup1",
                "compbon_mpdown1",
                "compbon_mpup1",
                "compbon_mddown1",
                "compbon_mdup1",
                "compbon_harv1",
                "compbon_wpn1",
                "compbon_hp2",
                "compbon_fp2",
                "compbon_enmup1",
                "compbon_med1",
                "compbon_faid1",
                "compbon_fab1",
                "compbon_scanup1",
                "compbon_rest1",
                "compbon_ab1"
            };

            string[] uncommonIP =
            {
                "compbon_ac2",
                "compbon_arm2",
                "compbon_cspd2",
                "compbon_charges3",
                "compbon_cooking2",
                "compbon_dmg2",
                "compbon_dur3",
                "compbon_eng2",
                "compbon_enmdown2",
                "compbon_epup2",
                "compbon_epdown2",
                "compbon_edup2",
                "compbon_eddown2",
                "compbon_dpdown2",
                "compbon_dpup2",
                "compbon_dddown2",
                "compbon_ddup2",
                "compbon_lpdown2",
                "compbon_lpup2",
                "compbon_lddown2",
                "compbon_ldup2",
                "compbon_mpdown2",
                "compbon_mpup2",
                "compbon_mddown2",
                "compbon_mdup2",
                "compbon_harv2",
                "compbon_wpn2",
                "compbon_hp4",
                "compbon_fp4",
                "compbon_enmup2",
                "compbon_luck1",
                "compbon_med2",
                "compbon_faid2",
                "compbon_hpregen1",
                "compbon_fpregen1",
                "compbon_snkatk1",
                "compbon_fab2",
                "compbon_scanup2",
                "compbon_rest2",
                "compbon_str1",
                "compbon_dex1",
                "compbon_con1",
                "compbon_wis1",
                "compbon_int1",
                "compbon_cha1",
                "compbon_ab2",
                "compbon_scavup1"
            };

            string[] rareIP =
            {
                "compbon_ac3",
                "compbon_arm3",
                "compbon_cspd3",
                "compbon_cooking3",
                "compbon_dmg3",
                "compbon_eng3",
                "compbon_enmdown3",
                "compbon_epup3",
                "compbon_epdown3",
                "compbon_edup3",
                "compbon_eddown3",
                "compbon_dpdown3",
                "compbon_dpup3",
                "compbon_dddown3",
                "compbon_ddup3",
                "compbon_lpdown3",
                "compbon_lpup3",
                "compbon_lddown3",
                "compbon_ldup3",
                "compbon_mpdown3",
                "compbon_mpup3",
                "compbon_mddown3",
                "compbon_mdup3",
                "compbon_harv3",
                "compbon_wpn3",
                "compbon_hp6",
                "compbon_fp6",
                "compbon_enmup3",
                "compbon_luck2",
                "compbon_med3",
                "compbon_faid3",
                "compbon_hpregen2",
                "compbon_fpregen2",
                "compbon_snkatk2",
                "compbon_fab3",
                "compbon_scanup3",
                "compbon_rest3",
                "compbon_str2",
                "compbon_dex2",
                "compbon_con2",
                "compbon_wis2",
                "compbon_int2",
                "compbon_cha2",
                "compbon_ab3",
                "compbon_scavup2"
            };

            string[] ultraRareIP =
            {
                "compbon_luck3",
                "compbon_hpregen3",
                "compbon_fpregen3",
                "compbon_snkatk3",
                "compbon_str3",
                "compbon_dex3",
                "compbon_con3",
                "compbon_wis3",
                "compbon_int3",
                "compbon_cha3",
                "compbon_fpup1",
                "compbon_faup1",
                "compbon_fdup1",
                "compbon_scavup3"
            };

            // Order: Common, Uncommon, Rare, Ultra Rare
            int[] chance;

            switch (quality)
            {
            case ResourceQuality.Low:
                chance = new[] { 100, 0, 0, 0 };
                break;

            case ResourceQuality.Normal:
                chance = new[] { 80, 20, 0, 0 };
                break;

            case ResourceQuality.High:
                chance = new[] { 20, 40, 40, 0 };
                break;

            case ResourceQuality.VeryHigh:
                chance = new[] { 0, 0, 70, 30 };
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(quality));
            }

            string[] setToUse = null;

            int index = RandomService.GetRandomWeightedIndex(chance);

            switch (index)
            {
            case 0: setToUse = commonIP; break;

            case 1: setToUse = uncommonIP; break;

            case 2: setToUse = rareIP; break;

            case 3: setToUse = ultraRareIP; break;
            }

            if (setToUse == null)
            {
                throw new NullReferenceException(nameof(setToUse));
            }

            index = RandomService.Random(0, setToUse.Length - 1);

            string itemTag = setToUse[index];

            return(new Tuple <ItemProperty, int>(ItemService.GetCustomItemPropertyByItemTag(itemTag), index));
        }
예제 #13
0
        private static bool ApplySkillDecay(NWPlayer oPC, PCSkill levelingSkill, int xp)
        {
            int totalSkillRanks = GetPCTotalSkillCount(oPC);

            if (totalSkillRanks < SkillCap)
            {
                return(true);
            }

            // Find out if we have enough XP to remove. If we don't, make no changes and return false signifying no XP could be removed.
            var pcSkills = DataService.Where <PCSkill>(x => x.PlayerID == oPC.GlobalID && x.SkillID != levelingSkill.SkillID);
            var totalXPs = pcSkills.Select(s =>
            {
                var reqXP   = DataService.Where <SkillXPRequirement>(x => x.SkillID == s.SkillID && (x.Rank < s.Rank || x.Rank == 0 && s.XP > 0));
                var totalXP = reqXP.Sum(x => x.XP);
                return(new { s.SkillID, TotalSkillXP = totalXP });
            }).ToList();

            int aggregateXP = 0;

            foreach (var p in totalXPs)
            {
                aggregateXP += p.TotalSkillXP;
            }
            if (aggregateXP < xp)
            {
                return(false);
            }

            // We have enough XP to remove. Reduce XP, picking random skills each time we reduce.
            var skillsPossibleToDecay = GetAllPCSkills(oPC)
                                        .Where(x =>
            {
                var skill = DataService.Get <Skill>(x.SkillID);
                return(!x.IsLocked &&
                       skill.ContributesToSkillCap &&
                       x.SkillID != levelingSkill.SkillID &&
                       (x.XP > 0 || x.Rank > 0));
            }).ToList();

            // There's an edge case where players can be at the cap, but we're unable to find a skill to decay.
            // In this scenario we can't go any further. Return false which will cause the GiveSkillXP method to
            // bail out with no changes to XP or decayed skills.
            if (skillsPossibleToDecay.Count <= 0)
            {
                return(false);
            }

            while (xp > 0)
            {
                int     skillIndex        = RandomService.Random(skillsPossibleToDecay.Count);
                PCSkill decaySkill        = skillsPossibleToDecay[skillIndex];
                int     totalDecaySkillXP = totalXPs.Find(x => x.SkillID == decaySkill.SkillID).TotalSkillXP;
                int     oldRank           = decaySkill.Rank;

                if (totalDecaySkillXP >= xp)
                {
                    totalDecaySkillXP = totalDecaySkillXP - xp;
                    xp = 0;
                }
                else if (totalDecaySkillXP < xp)
                {
                    totalDecaySkillXP = 0;
                    xp = xp - totalDecaySkillXP;
                }

                // If skill drops to 0 total XP, remove it from the possible list of skills
                if (totalDecaySkillXP <= 0)
                {
                    skillsPossibleToDecay.Remove(decaySkill);
                    decaySkill.XP   = 0;
                    decaySkill.Rank = 0;
                }
                // Otherwise calculate what rank and XP value the skill should now be.
                else
                {
                    // Get the XP amounts required per level, in ascending order, so we can see how many levels we're now meant to have.
                    List <SkillXPRequirement> reqs = DataService.Where <SkillXPRequirement>(x => x.SkillID == decaySkill.SkillID && x.Rank <= decaySkill.Rank).OrderBy(o => o.Rank).ToList();


                    // The first entry in the database is for rank 0, and if passed, will raise us to 1.  So start our count at 0.
                    int newDecaySkillRank = 0;
                    foreach (SkillXPRequirement req in reqs)
                    {
                        if (totalDecaySkillXP >= req.XP)
                        {
                            totalDecaySkillXP = totalDecaySkillXP - req.XP;
                            newDecaySkillRank++;
                        }
                        else if (totalDecaySkillXP < req.XP)
                        {
                            break;
                        }
                    }

                    decaySkill.Rank = newDecaySkillRank;
                    decaySkill.XP   = totalDecaySkillXP;
                }

                PCSkill dbDecaySkill = new PCSkill
                {
                    SkillID  = decaySkill.SkillID,
                    IsLocked = decaySkill.IsLocked,
                    ID       = decaySkill.ID,
                    PlayerID = decaySkill.PlayerID,
                    Rank     = decaySkill.Rank,
                    XP       = decaySkill.XP
                };
                DataService.SubmitDataChange(dbDecaySkill, DatabaseActionType.Update);
                MessageHub.Instance.Publish(new SkillDecayedMessage(oPC, decaySkill.SkillID, oldRank, decaySkill.Rank));
            }

            PlayerStatService.ApplyStatChanges(oPC, null);
            return(true);
        }
예제 #14
0
        private static void HandleBattlemagePerk()
        {
            DamageEventData data = NWNXDamage.GetDamageEventData();

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

            NWObject target = Object.OBJECT_SELF;

            if (!data.Damager.IsPlayer || !target.IsNPC)
            {
                return;
            }
            if (_.GetHasFeat((int)CustomFeatType.Battlemage, data.Damager.Object) == FALSE)
            {
                return;
            }

            NWPlayer player = data.Damager.Object;
            NWItem   weapon = _.GetLastWeaponUsed(player.Object);

            if (weapon.CustomItemType != CustomItemType.Baton)
            {
                return;
            }
            if (player.Chest.CustomItemType != CustomItemType.ForceArmor)
            {
                return;
            }

            int perkRank = PerkService.GetPCPerkLevel(player, PerkType.Battlemage);

            int  restoreAmount = 0;
            bool metRoll       = RandomService.Random(100) + 1 <= 50;

            switch (perkRank)
            {
            case 1 when metRoll:
                restoreAmount = 1;
                break;

            case 2:
                restoreAmount = 1;
                break;

            case 3:
                restoreAmount = 1;
                if (metRoll)
                {
                    restoreAmount++;
                }
                break;

            case 4:
                restoreAmount = 2;
                break;

            case 5:
                restoreAmount = 2;
                if (metRoll)
                {
                    restoreAmount++;
                }
                break;

            case 6:
                restoreAmount = 3;
                break;
            }

            if (restoreAmount > 0)
            {
                AbilityService.RestoreFP(player, restoreAmount);
            }
        }
예제 #15
0
        public static void OnChestOpen(NWPlaceable oChest)
        {
            NWPlayer oPC = (_.GetLastOpenedBy());

            if (!oPC.IsPlayer)
            {
                return;
            }

            if (_.GetActionMode(oPC.Object, _.ACTION_MODE_STEALTH) == _.TRUE)
            {
                _.SetActionMode(oPC.Object, _.ACTION_MODE_STEALTH, _.FALSE);
            }

            string       resref           = oChest.Resref;
            int          chestID          = oChest.GetLocalInt(SearchSiteIDVariableName);
            int          skillRank        = _.GetSkillRank(_.SKILL_SEARCH, oPC.Object);
            int          numberOfSearches = (skillRank / ExtraSearchPerNumberLevels) + 1;
            PCSearchSite searchEntity     = DataService.SingleOrDefault <PCSearchSite>(x => x.PlayerID == oPC.GlobalID && x.SearchSiteID == chestID);
            DateTime     timeLock         = DateTime.UtcNow;

            if (numberOfSearches <= 0)
            {
                numberOfSearches = 1;
            }

            if (searchEntity != null)
            {
                timeLock = searchEntity.UnlockDateTime;
            }

            if (resref == SearchSiteCopyResref)
            {
                oChest.IsUseable = false;
            }

            QuestService.SpawnQuestItems(oChest, oPC);

            if (timeLock < DateTime.UtcNow || searchEntity == null)
            {
                int dc = oChest.GetLocalInt(SearchSiteDCVariableName);

                for (int search = 1; search <= numberOfSearches; search++)
                {
                    RunSearchCycle(oPC, oChest, dc);
                    dc += RandomService.Random(3) + 1;
                }

                SaveChestInventory(oPC, oChest, false);
            }
            else
            {
                var searchItems = DataService.Where <PCSearchSiteItem>(x => x.PlayerID == oPC.GlobalID && x.SearchSiteID == searchEntity.SearchSiteID).ToList();
                foreach (PCSearchSiteItem item in searchItems)
                {
                    NWItem oItem = SerializationService.DeserializeItem(item.SearchItem, oChest);

                    // Prevent item duplication in containers
                    if (oItem.HasInventory)
                    {
                        foreach (NWItem containerItem in oItem.InventoryItems)
                        {
                            containerItem.Destroy();
                        }
                    }
                }
            }
        }