Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using VoidwalkerEngine.Framework.Collections;
- using VoidwalkerEngine.Framework.DataTypes;
- using VoidwalkerEngine.Framework.Game.Systems.GameItems;
- using VoidwalkerEngine.Framework.Game.Systems.GameItems.Data;
- using VoidwalkerEngine.Framework.Game.Systems.GameItems.Enchanting;
- using VoidwalkerEngine.Framework.Game.Systems.Loot;
- using VoidwalkerEngine.Framework.Logic;
- using VoidwalkerEngine.Framework.Maths;
- using VoidwalkerEngine.Framework.Utilities;
- namespace VoidwalkerEngine.Framework.Algorithms
- {
- public partial class LootGenerator
- {
- private VoidwalkerRandom _random;
- private List<UniqueEquipmentTemplate> _uniqueTemplates { get; set; }
- private List<Enchantment> _enchantments { get; set; }
- private GameDatabase _database;
- private Dictionary<Range, List<Affix>> _affixesByLevelBracket;
- static LootGenerator()
- {
- InitializeRareNameSuffixes();
- }
- public LootGenerator(GameDatabase database)
- {
- this._database = database;
- /**
- * Filter Affixes by level bracket
- */
- _affixesByLevelBracket = new Dictionary<Range, List<Affix>>();
- foreach (Affix affix in _database.AffixTemplates)
- {
- if (_affixesByLevelBracket.ContainsKey(affix.LevelBracket))
- {
- _affixesByLevelBracket[affix.LevelBracket].Add(affix);
- }
- else
- {
- _affixesByLevelBracket.Add(affix.LevelBracket, new List<Affix>());
- _affixesByLevelBracket[affix.LevelBracket].Add(affix);
- }
- }
- /**
- * Init
- */
- _enchantments = new List<Enchantment>();
- _random = new VoidwalkerRandom();
- if (_database.Enchantments != null)
- {
- foreach (Enchantment enchantment in _database.Enchantments)
- {
- if (enchantment.IsSpawnable)
- {
- this._enchantments.Add(enchantment);
- }
- }
- this._uniqueTemplates = _database.UniqueGameItemTemplates;
- }
- }
- #region Process LootTables
- public List<GameItemTemplate> Process(int level, List<LootTableDrop> items)
- {
- //if (items == null || items.Count == 0)
- //{
- // return null;
- //}
- //List<GameItem> results = new List<GameItem>();
- //foreach (LootTableDrop drop in items)
- //{
- // int quantity = _random.NextRange(drop.Quantity);
- // if (quantity > 0)
- // {
- // if (drop.Item.ItemType.IsGeneratable())
- // {
- // /**
- // * Roll Enchantments for each item in quantity.
- // * This allows for multiple items to have different
- // * enchantments, and qualities.
- // */
- // for (int i = 0; i < quantity; i++)
- // {
- // GameItem item = Generate(drop.Item, drop.LootArgs, level);
- // results.Add(item);
- // }
- // }
- // else
- // {
- // List<GameItem> existingStacks = new List<GameItem>();
- // foreach (GameItem item in results)
- // {
- // if (item.IsStackableWith(drop.Item))
- // {
- // existingStacks.Add(item);
- // }
- // }
- // if (existingStacks.Count == 0)
- // {
- // GameItem copy = new GameItem();
- // copy.Copy(drop.Item);
- // existingStacks.Add(copy);
- // }
- // int currentStackIndex = 0;
- // GameItem stackable = existingStacks[currentStackIndex];
- // for (int i = 1; i < quantity; i++)
- // {
- // int totalQuantity = stackable.Quantity + 1;
- // if (totalQuantity <= stackable.StackSize)
- // {
- // stackable.Quantity++;
- // }
- // else
- // {
- // currentStackIndex++;
- // GameItem copy = new GameItem();
- // copy.Copy(drop.Item);
- // existingStacks.Add(copy);
- // }
- // }
- // results.RemoveAll(p => p.Identifier.Equals(drop.Item.Identifier));
- // results.AddRange(existingStacks);
- // }
- // }
- //}
- //return results;
- return null;
- }
- #endregion
- public void RollAffixCounts(QualityType quality, bool isEthereal, out int prefixes, out int suffixes)
- {
- switch (quality)
- {
- case QualityType.Uncommon:
- if (isEthereal)
- {
- prefixes = 1;
- suffixes = 1;
- return;
- }
- if (_random.NextProbability(25))
- {
- prefixes = 1;
- suffixes = 0;
- return;
- }
- if (_random.NextProbability(50))
- {
- prefixes = 0;
- suffixes = 1;
- return;
- }
- // Default to both Prefix and Suffix
- prefixes = 1;
- suffixes = 1;
- return;
- case QualityType.Rare:
- prefixes = 0;
- suffixes = 0;
- if (isEthereal)
- {
- prefixes = 3;
- suffixes = 3;
- return;
- }
- int probability = 100;
- for (int i = 0; i < 6; i++)
- {
- switch (i)
- {
- case 0:
- case 1:
- case 2:
- probability = 100;
- break;
- case 3:
- case 4:
- probability = 75;
- break;
- case 5:
- probability = 40;
- break;
- default:
- break;
- }
- if (_random.NextProbability(probability))
- {
- int selection = _random.NextRange(0, 1);
- switch (selection)
- {
- case 0: // Prefix
- if (prefixes < 3)
- {
- prefixes++;
- }
- else
- {
- suffixes++;
- }
- break;
- case 1: // Suffix
- if (suffixes < 3)
- {
- suffixes++;
- }
- else
- {
- prefixes++;
- }
- break;
- }
- }
- }
- return;
- case QualityType.Epic:
- if (isEthereal)
- {
- prefixes = 3;
- suffixes = 3;
- return;
- }
- prefixes = 3;
- suffixes = 3;
- return;
- case QualityType.Unique:
- prefixes = 0;
- suffixes = 0;
- return;
- default:
- throw new Exception(); // Common
- }
- }
- /// <summary>
- /// Summary
- /// </summary>
- /// <param name="template"></param>
- /// <param name="lootParams"></param>
- /// <param name="level"></param>
- /// <returns></returns>
- public GameItem Generate(GameItemTemplate template, LootDropArgs lootParams, int level)
- {
- GameItem result = new GameItem();
- #region Copy template and roll base properties
- result.ItemType = template.ItemType;
- result.Identifier = template.Identifier;
- result.Template = template.Identifier;
- result.BaseName = template.BaseName;
- result.Icon = template.Icon;
- result.FlavorText = template.FlavorText;
- result.BaseSellPrice = template.BaseSellPrice;
- if (result.ItemType.IsWeapon())
- {
- result.BaseWeaponDamage = new Range(
- _random.NextRange(template.BaseMinimumWeaponDamage),
- _random.NextRange(template.BaseMaximumWeaponDamage));
- }
- if (result.ItemType.IsArmor())
- {
- result.BaseArmorRating = _random.NextRange(template.BaseMaximumWeaponDamage);
- }
- result.BaseDurability = _random.NextRange(template.BaseDurability);
- result.BaseBlockChance = _random.NextRange(template.BaseBlockChance);
- #endregion
- result.Quality = GenerateItemQuality(lootParams);
- bool isEthereal = GenerateEthereal();
- GameItemType itemConstraint = template.ItemType;
- List<Affix> affixes = new List<Affix>();
- RollAffixCounts(result.Quality, isEthereal, out int prefixes, out int suffixes);
- switch (result.Quality)
- {
- case QualityType.Uncommon:
- affixes = GenerateAffixes(itemConstraint, level, prefixes, suffixes);
- result.Header = GenerateUncommonName(affixes, template.BaseName);
- break;
- case QualityType.Rare:
- affixes = GenerateAffixes(itemConstraint, level, prefixes, suffixes);
- result.Header = GenerateRareName(itemConstraint);
- break;
- case QualityType.Epic:
- affixes = GenerateAffixes(itemConstraint, level, prefixes, suffixes);
- result.Header = GenerateEpicName();
- break;
- case QualityType.Unique:
- //if (this._legendaries != null)
- //{
- // List<LegendaryItemTemplate> candidates = new List<LegendaryItemTemplate>();
- // foreach (LegendaryItemTemplate candidate in this._legendaries)
- // {
- // if (candidate.Constraints.Contains(itemConstraint))
- // {
- // if (candidate.LevelBracket.Contains(level))
- // {
- // candidates.Add(candidate);
- // }
- // }
- // }
- // if (candidates.Count > 0)
- // {
- // LegendaryItemTemplate legendary = _random.Choose(candidates);
- // result.LegendaryTemplate = legendary;
- // result.Enchantments = GenerateEnchantments(itemConstraint, level, enchantmentCount);
- // result.Header = legendary.Header;
- // break;
- // }
- //}
- /**
- * The player rolled a legendary, however the routine failed. This may mean
- * that no legendary exists for their level bracket, or the item type has no
- * corresponding legendary. We will default to giving them a guaranteed epic.
- */
- result.Quality = QualityType.Epic;
- goto case QualityType.Epic;
- }
- /**
- * Finalize, Convert, and Apply all affixes
- */
- result.Properties = new List<GameItemProperty>();
- foreach (Affix affix in affixes)
- {
- GameItemProperty property = new GameItemProperty();
- if (isEthereal)
- {
- /**
- * Ethereal Items always gain maximum affix values
- */
- property.DynamicValue = affix.DynamicRange.Maximum;
- property.ProcChance = affix.ProcChance.Maximum;
- property.Property = affix.Property;
- property.StaticRange = affix.StaticRange;
- }
- else
- {
- property.DynamicValue = _random.NextRange(affix.DynamicRange);
- property.ProcChance = _random.NextRange(affix.ProcChance);
- property.Property = affix.Property;
- property.StaticRange = affix.StaticRange;
- }
- /**
- * Check for duplicate properties, and if they exist, combine them.
- */
- foreach (GameItemProperty existingProperty in result.Properties)
- {
- if (existingProperty.Property == property.Property)
- {
- // This may introduce edge cases.
- existingProperty.DynamicValue += property.DynamicValue;
- existingProperty.ProcChance += property.ProcChance;
- existingProperty.StaticRange = new Range(
- existingProperty.StaticRange.Minimum + property.StaticRange.Minimum,
- existingProperty.StaticRange.Maximum + property.StaticRange.Maximum);
- }
- }
- result.Properties.Add(property);
- }
- /**
- * Append Ethereal Property
- */
- if (isEthereal)
- {
- result.Properties.Add(
- new GameItemProperty()
- {
- Property = GameItemPropertyType.Ethereal,
- DynamicValue = 0,
- ProcChance = 0,
- StaticRange = Range.Empty
- });
- }
- //result.Repair();
- return result;
- }
- private string GenerateUncommonName(List<Affix> affixes, string baseName)
- {
- switch (affixes.Count)
- {
- case 1:
- Affix affix = affixes[0];
- switch (affix.AffixType)
- {
- case AffixType.Prefix:
- return affixes[0].Name + " " + baseName;
- case AffixType.Suffix:
- return baseName + " " + affixes[0].Name;
- default:
- throw new Exception();
- }
- case 2:
- return affixes[0].Name + " " + baseName + " " + affixes[1].Name;
- default:
- throw new Exception("Count: " + affixes.Count);
- }
- }
- public List<Affix> GenerateAffixes(GameItemType itemConstraint, int level, int prefixCount, int suffixCount)
- {
- List<Affix> results = new List<Affix>();
- if(prefixCount > 0)
- {
- results.AddRange(GenerateAffixes(itemConstraint, level, AffixType.Prefix, prefixCount));
- }
- if(suffixCount > 0)
- {
- results.AddRange(GenerateAffixes(itemConstraint, level, AffixType.Suffix, suffixCount));
- }
- return results;
- }
- public List<Affix> GenerateAffixes(GameItemType itemConstraint, int level, AffixType affixType, int count)
- {
- List<Affix> results = new List<Affix>();
- List<Affix> candidates = new List<Affix>();
- // Loop through all Keys, and collect lists that collide with level.
- foreach (KeyValuePair<Range, List<Affix>> pair in _affixesByLevelBracket)
- {
- if (pair.Key.Contains(level))
- {
- // Second collision is itemConstraint
- foreach (Affix affix in pair.Value)
- {
- if (affix.Constraints.Contains(itemConstraint) &&
- affix.AffixType == affixType)
- {
- candidates.Add(affix);
- }
- }
- }
- }
- bool isSearching = true;
- int maximumIterations = 32; // Infinite Loop Error Guard
- int iterations = 0;
- while (isSearching)
- {
- Affix candidate = _random.Choose(candidates);
- if (candidate != null)
- {
- if (_random.NextProbability(candidate.SpawnChance) &&
- !results.Exists(x => x.Property == candidate.Property) &&
- candidate.AffixType == affixType)
- {
- results.Add(candidate);
- }
- }
- iterations++;
- if (results.Count == count || iterations >= maximumIterations)
- {
- isSearching = false;
- }
- }
- return results;
- }
- /// <summary>
- /// sdfsdf
- /// </summary>
- /// <param name="dropArgs"></param>
- /// <returns></returns>
- public QualityType GenerateItemQuality(LootDropArgs dropArgs)
- {
- /**
- * This needs to handle probabilities as doubles instead.
- */
- if (_random.NextProbability(dropArgs.LegendaryChance))
- {
- return QualityType.Unique;
- }
- if (_random.NextProbability(dropArgs.EpicChance))
- {
- return QualityType.Epic;
- }
- if (_random.NextProbability(dropArgs.RareChance))
- {
- return QualityType.Rare;
- }
- if (_random.NextProbability(dropArgs.UncommonChance))
- {
- return QualityType.Uncommon;
- }
- return QualityType.Common;
- }
- /// <summary>
- /// Attempts to generate the flag for an item being Ethereal
- /// The current odds of rolling an Ethereal item is 1 in 1024 (0.0009765625%)
- /// </summary>
- public bool GenerateEthereal()
- {
- return _random.NextProbability(new Probability(1, 1024));
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement