/// <summary> /// Generates the loot within all specified parameters, depending on level & difficulty. /// </summary> /// <returns>The loot.</returns> /// <param name="map">Map to get the levelNumber and difficulty from. If unspecified uses set values. </param> public GameItem[] GenerateLoot(Map map = null) { if (map != null) { SetLevelAndDifficulty(map); } //Set loot parameters depending on level & difficulty int maxDifficulty = Enum.GetValues(typeof(Settings.Difficulty)).Length - 1; int minItems_base = Mathf.RoundToInt(minItemsBase_hardest + minItemsBase_modifier * (maxDifficulty - difficulty)); int maxItems_base = Mathf.RoundToInt(maxItemsBase_hardest + maxItemsBase_modifier * (maxDifficulty - difficulty)); int levelsTillMinItemGain = Mathf.RoundToInt(levelsTillMinItemGain_easiest * Mathf.Pow(levelsTillMinItemGain_multiplier, difficulty)); int levelsTillMaxItemGain = Mathf.RoundToInt(levelsTillMaxItemGain_easiest * Mathf.Pow(levelsTillMaxItemGain_multiplier, difficulty)); int minItems_gain = (int)levelNumber / levelsTillMinItemGain; int maxItems_gain = (int)levelNumber / levelsTillMaxItemGain; int minItems = Mathf.Min(minItems_base + minItems_gain, minLootCap); int maxItems = Mathf.Min(maxItems_base + maxItems_gain, maxLootCap); if (minItems > maxItems) { minItems = maxItems; } //Rarity int minRarityBase = Mathf.RoundToInt((int)minRarityBase_hardest + minRarityBase_modifier * (maxDifficulty - difficulty)); int levelsTillMinRarityGain = Mathf.RoundToInt(levelsTillMinRarityGain_easiest * Mathf.Pow(levelsTillMinRarityGain_multiplier, difficulty)); int minRarity_gain = (int)levelNumber / levelsTillMinRarityGain; GameItem.ItemRarity minRarity = (GameItem.ItemRarity)Mathf.Min(minRarityBase + minRarity_gain, (int)minRarityCap); //Generate loot in secret room return(ItemSpawner.GenerateLootBag((int)Time.time, levelNumber, minItems, maxItems, minRarity, false, healthPotionChance)); }
/// <summary> /// Generates a health potion. /// </summary> /// <returns>The health potion.</returns> /// <param name="seed">Seed.</param> /// <param name="quality">Quality.</param> /// <param name="rarity">Rarity.</param> /// <param name="useSeed">If set to <c>true</c> use seed.</param> public static UsableItem GenerateHealthPotion(int seed, int quality, GameItem.ItemRarity rarity, bool useSeed = false) { //TODO: incorporate quality more by allowing custom healing amounts //Allow 1 more potential potion every 5 levels, up to the max stack of course. Random random = GetRandom(seed, useSeed); int potionMaxStack = 5; int maxAmount = UnityEngine.Mathf.Min((int)(quality / 5) + 1, potionMaxStack); int quantity = random.Next(1, maxAmount + 1); UsableItem healthPotion = new UsableItem(null, null, "Health Potion", "A health potion.", 1, rarity, quantity, potionMaxStack, 100, "HealthPotionAction"); SetItemSprites(seed, "Health Potion", healthPotion, useSeed); return(healthPotion); }
/// <summary> /// Generation function designed to build a weapon item of some sort. Can be a melee or ranged weapon. /// </summary> /// <param name="seed">Seed to use for generation, useful for testing. Set this to system time during playtime.</param> /// <param name="quality">Quality modifier for items. Essentially represents how deep in the dungeon the player is. Pass this from the map class ideally.</param> /// <param name="rarity">Minimum item rarity, defaults to common. Higher rarity items have better stats implicitly.</param> /// <returns>A weapon item, with name and description pre-set based on the item spec.</returns> public static WeaponItem GenerateWeapon(int seed, int quality, GameItem.ItemRarity rarity = GameItem.ItemRarity.COMMON, bool useSeed = true) { // Some constants to use for calculations: int meleeWeight = 1; // Weighted likelyhood to pick this over the other. int rangedWeight = 0; // Weighted likelyhood to pick this over the other. // Note we are using the system's random, and not Unity's in order to use a seed. Random random = GetRandom(seed, useSeed); // Choose what type of thing to generate, Ranged? Melee? int val = random.Next(1, meleeWeight + rangedWeight); // Generate basic stats, these apply to all weapons int rareVal = (int)rarity; double[] damageScale = { 1, 10, 25, 60, 135, 250 }; // Damage range dependent on rarity, For rarity i, minimum is damageScale[i] double[] rofMin = { 1, 2, 3, 4, 5 }; // TODO: PLEASE BALANCE THIS double[] rofMax = { 2, 4, 6, 8, 10 }; double rangeMin = 1; double rangeMax = 5; // Ranged weapon range is x10 this. // Get Damage Value; utilizes quality and rarity to help it scale. double damage = random.NextDouble() * (damageScale[rareVal + 1] - damageScale[rareVal]) + damageScale[rareVal]; damage = damage + damage * (quality / floorRarityBoostThreshold); // Get Range Value; depdenent on nothing. double range = random.NextDouble() * (rangeMax - rangeMin) + rangeMin; // Get Rate Of Fire; higher rarities increase this value. double rof = random.NextDouble() * (rofMax[rareVal] - rofMin[rareVal]) + rofMin[rareVal]; // Call other generation functions based on this. if (val >= rangedWeight) { return(GenerateMeleeWeapon(seed, quality, damage, range, rof, (int)rarity, useSeed)); } else { return(GenerateRangedWeapon(seed, quality, damage, range * 10, rof, (int)rarity, useSeed)); } }
/// <summary> /// Generation function designed to build an either a weapon or armor. /// </summary> /// <param name="seed">Seed to use for generation, useful for testing. Set this to system time during playtime.</param> /// <param name="quality">Quality modifier for items. Essentially represents how deep in the dungeon the player is. Pass this from the map class ideally.</param> /// <param name="rarity">Minimum item rarity, defaults to common. Higher rarity items have better stats implicitly.</param> /// <returns>An item, with name and description pre-set based on the item spec.</returns> public static GameItem GenerateItem(int seed, int quality, GameItem.ItemRarity rarity = GameItem.ItemRarity.COMMON, bool useSeed = true) { // Some constants to use for calculations: int armorWeight = 2; // Weighted likelyhood to pick this over the other. int weaponWeight = 1; // Weighted likelyhood to pick this over the other. // Note we are using the system's random, and not Unity's in order to use a seed. Random random = GetRandom(seed, useSeed); // Choose what type of thing to generate, armor, or a weapon? int val = random.Next(1, armorWeight + weaponWeight + 1); // Call other generation functions based on this. if (val >= weaponWeight) { return(GenerateWeapon(seed, quality, rarity, useSeed)); } else { return(GenerateArmor(seed, quality, rarity, useSeed)); } }
/// <summary> /// Generation function designed to build an armor item for spawning. Can fit any slot. /// </summary> /// <param name="seed">Seed to use for generation, useful for testing. Set this to system time during playtime.</param> /// <param name="rarity">Minimum item rarity, defaults to common. Higher rarity items have better stats implicitly.</param> /// <returns>A weapon item, with name and description pre-set based on the item spec.</returns> public static ArmorItem GenerateArmor(int seed, int quality, GameItem.ItemRarity rarity = GameItem.ItemRarity.COMMON, bool useSeed = true) { // Some constants to use for calculations: double[] minArmorRarityRatings = { 1, 2, 3, 4, 5 }; // Scaling factor for minimum based on rarity. Min * RarityRating = Absolute Minimum double[] minArmorRatings = { 5, 10, 15, 5, 1, 1 }; // Minimum rating per armor slot, in enum order. double[] maxArmorRatings = { 20, 50, 100, 10, 5, 5 }; // Maximum rating per armor slot, in enum order. double[] minSpeedRarityRatings = { 1, 1.25, 1.5, 1.75, 2 }; // Scaling factor for minimum based on rarity. double[] minSpeedRatings = { 0, 1, 0, 0, 1, 1 }; // Minimum rating per armor slot, in enum order. double[] maxSpeedRatings = { 2, 5, 2, 1, 5, 5 }; // Maximum rating per armor slot, in enum order. double[] minDamageRarityRatings = { 1, 1.25, 1.5, 1.75, 2 }; // Scaling factor for minimum based on rarity. double[] minDamageRatings = { 0, 0, 0, 1, 1, 1 }; // Minimum rating per armor slot, in enum order. double[] maxDamageRatings = { 2, 2, 2, 5, 5, 5 }; // Maximum rating per armor slot, in enum order. // For reference, ENUM Order: HEAD, LEGS, CHEST, GLOVES, RING, NECK. // Note we are using the system's random, and not Unity's in order to use a seed. Random random = GetRandom(seed, useSeed); // Select rarity first; this determines effectiveness. int totalWeight = 0; for (int i = 0; i < rarityWeights.Length; i++) { totalWeight += rarityWeights[i]; } int randRarity = random.Next(totalWeight); int trueRarity = -1; totalWeight = rarityWeights[0]; for (int i = 1; i < rarityWeights.Length && trueRarity == -1; i++) { if (randRarity < totalWeight) { trueRarity = i - 1; } totalWeight += rarityWeights[i]; } // Rarity is guaurnteed to increase for every X floors of depth. trueRarity += (quality / floorRarityBoostThreshold); if (trueRarity > 4) { trueRarity = 4; } // Determine slot for armor. int trueSlot = random.Next(Enum.GetNames(typeof(EquipmentManager.EquipSlot)).Length); // Determine sprite info (somehow). TODO (I'm not sure how to do this) // Calculate the armor's values. double weightedMinArmor = minArmorRatings[trueSlot] * minArmorRarityRatings[trueRarity]; if (weightedMinArmor > maxArmorRatings[trueSlot]) { weightedMinArmor = maxArmorRatings[trueSlot]; } double weightedMinSpeed = minSpeedRatings[trueSlot] * minSpeedRarityRatings[trueRarity]; if (weightedMinArmor > maxSpeedRatings[trueSlot]) { weightedMinArmor = maxSpeedRatings[trueSlot]; } double weightedMinDamage = minDamageRatings[trueSlot] * minDamageRarityRatings[trueRarity]; if (weightedMinArmor > maxDamageRatings[trueSlot]) { weightedMinArmor = maxDamageRatings[trueSlot]; } double armor = random.NextDouble() * (maxArmorRatings[trueSlot] - weightedMinArmor) + weightedMinArmor; double speed = random.NextDouble() * (maxSpeedRatings[trueSlot] - weightedMinSpeed) + weightedMinSpeed; double damage = random.NextDouble() * (maxDamageRatings[trueSlot] - weightedMinDamage) + weightedMinDamage; // Determine, based on rarity, if armor is allowed to have speed or damage. if (trueRarity < 1) { speed = 0; damage = 0; } else if (trueRarity < 2) { if (speed > damage) { damage = 0; } else { speed = 0; } } // Build the armor item. ArmorItem newItem = new ArmorItem((EquipmentManager.EquipSlot)trueSlot, armor, speed, damage) { Rarity = (GameItem.ItemRarity)trueRarity }; // Generate a name. newItem.Name = GenerateArmorName(seed, newItem, minArmorRatings, maxArmorRatings, minSpeedRatings, maxSpeedRatings, minDamageRatings, maxDamageRatings, useSeed); // Generate a description. newItem.Description = GenerateArmorDesc(seed, newItem, useSeed); // Pick a value rating. (Should probably be another utility method). newItem.Value = GenerateItemValue(newItem); // Generate a unique ID (this might require some internal memory somewhere to keep track of what IDs have already been assigned, probably another utility function). newItem.ItemID = GenerateItemID(); // Return the finished item. return(newItem); }
/// <summary> /// Generation function designed to build an array of game items, can be potions, equipment, or just misc stuff. /// Function is primarily used for spawning more than one thing in a treasure room. /// </summary> /// <param name="seed">Seed to use for generation, useful for testing. Set this to system time during playtime.</param> /// <param name="quality">Quality modifier for items. Essentially represents how deep in the dungeon the player is. Pass this from the map class ideally.</param> /// <param name="min">Minimum amount of items that are allowed to spawn, inclusive.</param> /// <param name="max">Maximum amount of items that are allowed to spawn, inclusive.</param> /// <param name="rarity">Minimum item rarity, defaults to common. Higher rarity items have better stats implicitly.</param> /// <param name="healthPotionChance"> % chance from [0, 1] inclusive that any item dropped will be a health potion.</param></param> /// <returns>An equippable item, with name and description pre-set based on the item spec.</returns> public static GameItem[] GenerateLootBag(int seed, int quality, int min = 1, int max = 5, GameItem.ItemRarity rarity = GameItem.ItemRarity.COMMON, bool useSeed = true, double healthPotionChance = 0.0) { // Random generation seed is set before doing anyhting else, neat. Random random = GetRandom(seed, useSeed); // Size up the situation. int size = random.Next(min, max + 1); GameItem[] lootBag = new GameItem[size]; // Generate and fill the bag. for (int i = 0; i < size; i++) { if (random.NextDouble() <= healthPotionChance) { lootBag[i] = GenerateHealthPotion(seed, quality, rarity, useSeed); } else { lootBag[i] = GenerateItem(seed, quality, rarity, useSeed); } } return(lootBag); }
public void ItemValue(GameItem.ItemRarity rarity, double value) { GameItem valueTestItem = new GameItem(null, null, "Generic Item", "I am an Item.", 10, rarity, 5, 10, 2); Assert.AreEqual(value, ItemSpawner.GenerateItemValue(valueTestItem)); }
public void TestArmorNameByRarity(EquipmentManager.EquipSlot slot, int armorRatingPosition, GameItem.ItemRarity rarity, string description) { ArmorItem armor = new ArmorItem(rarity, slot); double[] minArmor = new double[6]; double[] maxArmor = new double[6]; minArmor[armorRatingPosition] = 1; maxArmor[armorRatingPosition] = 5; double[] minSpeed = new double[6]; double[] maxSpeed = new double[6]; minSpeed[armorRatingPosition] = 1; maxSpeed[armorRatingPosition] = 5; double[] minDamage = new double[6]; double[] maxDamage = new double[6]; minDamage[armorRatingPosition] = 1; maxDamage[armorRatingPosition] = 5; string name = ItemSpawner.GenerateArmorName(5, armor, minArmor, maxArmor, minSpeed, maxSpeed, minDamage, maxDamage); string[] ssize = name.Split(null); Assert.AreEqual(ssize[0], description); }