Advertisement
Krythic

LootGenerator

Jul 31st, 2020
1,479
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.28 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using VoidwalkerEngine.Framework.Collections;
  5. using VoidwalkerEngine.Framework.DataTypes;
  6. using VoidwalkerEngine.Framework.Logic;
  7. using VoidwalkerEngine.Framework.Systems.Enchanting;
  8. using VoidwalkerEngine.Framework.Systems.Items.Base;
  9. using VoidwalkerEngine.Framework.Systems.Items.Templates;
  10. using VoidwalkerEngine.Framework.Systems.Loot;
  11. using VoidwalkerEngine.Framework.Utilities;
  12.  
  13. namespace VoidwalkerEngine.Framework.Algorithms
  14. {
  15.     public partial class LootGenerator
  16.     {
  17.         private VoidwalkerRandom _random;
  18.         private List<LegendaryTemplate> _legendaries { get; set; }
  19.         private List<Enchantment> _enchantments { get; set; }
  20.  
  21.         static LootGenerator()
  22.         {
  23.             InitializeRareNameSuffixes();
  24.         }
  25.  
  26.         public LootGenerator()
  27.         {
  28.             _enchantments = new List<Enchantment>();
  29.             _random = new VoidwalkerRandom();
  30.             if (GameDatabase.Enchantments != null)
  31.             {
  32.                 foreach (Enchantment enchantment in GameDatabase.Enchantments)
  33.                 {
  34.                     if (enchantment.IsSpawnable)
  35.                     {
  36.                         this._enchantments.Add(enchantment);
  37.                     }
  38.                 }
  39.                 this._legendaries = GameDatabase.Legendaries;
  40.             }
  41.         }
  42.  
  43.         public List<GameItem> Process(int level, List<LootTableDrop> items)
  44.         {
  45.             if (items == null || items.Count == 0)
  46.             {
  47.                 return null;
  48.             }
  49.             List<GameItem> results = new List<GameItem>();
  50.  
  51.             foreach (LootTableDrop drop in items)
  52.             {
  53.                 int quantity = _random.NextRange(drop.Quantity);
  54.                 if (quantity > 0)
  55.                 {
  56.                     if (drop.Item.IsEnchantable)
  57.                     {
  58.                         /**
  59.                          * Roll Enchantments for each item in quantity.
  60.                          * This allows for multiple items to have different
  61.                          * enchantments, and qualities.
  62.                          */
  63.                         for (int i = 0; i < quantity; i++)
  64.                         {
  65.                             GameItem item = Generate(drop.Item, drop.LootArgs, level);
  66.                             results.Add(item);
  67.                         }
  68.                     }
  69.                     else
  70.                     {
  71.  
  72.                         List<GameItem> existingStacks = new List<GameItem>();
  73.                         foreach (GameItem item in results)
  74.                         {
  75.                             if (item.IsStackableWith(drop.Item))
  76.                             {
  77.                                 existingStacks.Add(item);
  78.                             }
  79.                         }
  80.                         if (existingStacks.Count == 0)
  81.                         {
  82.                             existingStacks.Add(drop.Item.MakeCopy());
  83.                         }
  84.                         int currentStackIndex = 0;
  85.                         for (int i = 1; i < quantity; i++)
  86.                         {
  87.                             int totalQuantity = existingStacks[currentStackIndex].Quantity + 1;
  88.                             if (totalQuantity <= 20)
  89.                             {
  90.                                 existingStacks[currentStackIndex].Quantity++;
  91.                             }
  92.                             else
  93.                             {
  94.                                 currentStackIndex++;
  95.                                 existingStacks.Add(drop.Item.MakeCopy());
  96.                             }
  97.                         }
  98.                         results.RemoveAll(p => p.Identifier.Equals(drop.Item.Identifier));
  99.                         results.AddRange(existingStacks);
  100.                     }
  101.                 }
  102.             }
  103.             return results;
  104.         }
  105.  
  106.         /// <summary>
  107.         ///
  108.         /// </summary>
  109.         /// <param name="template"></param>
  110.         /// <param name="lootParams"></param>
  111.         /// <param name="level"></param>
  112.         /// <param name="totalMagicFind"></param>
  113.         /// <returns></returns>
  114.         public GameItem Generate(GameItem template, LootDropArgs lootParams, int level)
  115.         {
  116.             GameItem result = template.MakeCopy();
  117.             if (result.IsSpawnable)
  118.             {
  119.                 result.Quality = GenerateItemQuality(lootParams);
  120.                 result.IsEthereal = GenerateEthereal();
  121.                 ItemType itemConstraint = result.Category;
  122.                 result.Enchantments = new List<Enchantment>();
  123.  
  124.                 int maximumEnchantments = result.Quality.GetMaximumEnchantmentSlots();
  125.                 if (result.Quality == QualityType.Legendary)
  126.                 {
  127.                     maximumEnchantments -= 1;
  128.                 }
  129.                 int enchantmentCount =
  130.                     result.IsEthereal ?
  131.                     maximumEnchantments :
  132.                     GenerateEnchantmentCount(result.Quality);
  133.                 // Generate enchantments based upon quality
  134.                 switch (result.Quality)
  135.                 {
  136.                     case QualityType.Uncommon:
  137.                         result.Enchantments = GenerateEnchantments(itemConstraint, level, enchantmentCount);
  138.                         break;
  139.                     case QualityType.Rare:
  140.                         result.Enchantments = GenerateEnchantments(itemConstraint, level, enchantmentCount);
  141.                         result.Header = GenerateRareName(itemConstraint);
  142.                         break;
  143.                     case QualityType.Epic:
  144.                         result.Enchantments = GenerateEnchantments(itemConstraint, level, enchantmentCount);
  145.                         result.Header = GenerateEpicName();
  146.                         break;
  147.                     case QualityType.Legendary:
  148.                         if (this._legendaries != null)
  149.                         {
  150.                             List<LegendaryTemplate> candidates = new List<LegendaryTemplate>();
  151.                             foreach (LegendaryTemplate candidate in this._legendaries)
  152.                             {
  153.                                 if (candidate.Constraints.Contains(itemConstraint))
  154.                                 {
  155.                                     if (candidate.LevelBracket.Contains(level))
  156.                                     {
  157.                                         candidates.Add(candidate);
  158.                                     }
  159.                                 }
  160.                             }
  161.                             if (candidates.Count > 0)
  162.                             {
  163.                                 LegendaryTemplate legendary = _random.Choose(candidates);
  164.                                 Enchantment legendaryEnchantment = GameDatabase.GetEnchantment(legendary.Enchantment);
  165.                                 if (legendaryEnchantment != null)
  166.                                 {
  167.                                     result.Enchantments.Add(legendaryEnchantment);
  168.                                 }
  169.                                 // generate enchantments
  170.                                 result.Enchantments = GenerateEnchantments(itemConstraint, level, enchantmentCount);
  171.                                 result.Header = legendary.Header;
  172.                                 result.FlavorText = legendary.FlavorText;
  173.                                 break;
  174.                             }
  175.                         }
  176.                         /**
  177.                          * The player rolled a legendary, however the routine failed. This may mean
  178.                          * that no legendary exists for their level bracket, or the item type has no
  179.                          * corresponding legendary. We will default to giving them a guaranteed epic.
  180.                          */
  181.                         result.Quality = QualityType.Epic;
  182.                         goto case QualityType.Epic;
  183.                 }
  184.                 result.Repair();
  185.                 return result;
  186.             }
  187.             else
  188.             {
  189.                 return result;
  190.             }
  191.         }
  192.  
  193.         /// <summary>
  194.         ///
  195.         /// </summary>
  196.         /// <param name="dropArgs"></param>
  197.         /// <returns></returns>
  198.         public QualityType GenerateItemQuality(LootDropArgs dropArgs)
  199.         {
  200.             /**
  201.              * This needs to handle probabilities as doubles instead.
  202.              */
  203.             if (_random.NextProbability(dropArgs.LegendaryChance))
  204.             {
  205.                 return QualityType.Legendary;
  206.             }
  207.             if (_random.NextProbability(dropArgs.EpicChance))
  208.             {
  209.                 return QualityType.Epic;
  210.             }
  211.             if (_random.NextProbability(dropArgs.RareChance))
  212.             {
  213.                 return QualityType.Rare;
  214.             }
  215.             if (_random.NextProbability(dropArgs.UncommonChance))
  216.             {
  217.                 return QualityType.Uncommon;
  218.             }
  219.             return QualityType.Common;
  220.         }
  221.  
  222.         /// <summary>
  223.         /// Attempts to generate the flag for an item being Ethereal
  224.         /// The current odds of rolling an Ethereal item is 1 in 1024 (‭‭0.0009765625‬%)
  225.         /// </summary>
  226.         public bool GenerateEthereal()
  227.         {
  228.             return _random.NextOdds(1, 1024);
  229.         }
  230.  
  231.         /// <summary>
  232.         ///
  233.         /// </summary>
  234.         /// <param name="constraint"></param>
  235.         /// <param name="level"></param>
  236.         /// <returns></returns>
  237.         public Enchantment GenerateEnchantment(ItemType constraint, int level)
  238.         {
  239.             if (this._enchantments == null || this._enchantments.Count == 0)
  240.             {
  241.                 return null;
  242.             }
  243.             return GenerateEnchantments(constraint, level, 1)[0];
  244.         }
  245.  
  246.         /// <summary>
  247.         ///
  248.         /// </summary>
  249.         /// <param name="constraint"></param>
  250.         /// <param name="level"></param>
  251.         /// <param name="count"></param>
  252.         /// <param name="allowDuplicates"></param>
  253.         /// <returns></returns>
  254.         private List<Enchantment> GenerateEnchantments(ItemType constraint, int level, int count, bool allowDuplicates = false)
  255.         {
  256.             List<Enchantment> results = new List<Enchantment>();
  257.             if (count == 0)
  258.             {
  259.                 return results;
  260.             }
  261.             int totalFitness = 0;
  262.             List<Enchantment> filteredEnchantments = new List<Enchantment>();
  263.             foreach (Enchantment candidate in this._enchantments)
  264.             {
  265.                 if (candidate.Constraints.Contains(constraint))
  266.                 {
  267.                     if (candidate.LevelBracket.Contains(level))
  268.                     {
  269.                         filteredEnchantments.Add(candidate);
  270.                         totalFitness += candidate.Frequency;
  271.                     }
  272.                 }
  273.             }
  274.             if (filteredEnchantments.Count < count)
  275.             {
  276.                 count = filteredEnchantments.Count;
  277.                 if (count == 0)
  278.                 {
  279.                     return results;
  280.                 }
  281.             }
  282.             filteredEnchantments.OrderBy(enchantment => enchantment.Frequency).Reverse().ToList();
  283.             int enchantmentsGenerated = 0;
  284.             bool isSearching = true;
  285.             int attempts = 0;
  286.             const int maximumAttempts = 32; // Prevent Infinite Loops
  287.             while (isSearching)
  288.             {
  289.                 Enchantment selectedEnchantment = null;
  290.                 int randomSample = _random.NextInteger(totalFitness);
  291.                 foreach (Enchantment attempt in filteredEnchantments)
  292.                 {
  293.                     if (randomSample < attempt.Frequency)
  294.                     {
  295.                         selectedEnchantment = attempt;
  296.                         break;
  297.                     }
  298.                     randomSample -= attempt.Frequency;
  299.                 }
  300.                 if (allowDuplicates ||
  301.                     !results.Any(e => e == selectedEnchantment) &&
  302.                     !results.Any(e => e.Family.Equals(selectedEnchantment.Family)))
  303.                 {
  304.                     attempts = 0;
  305.                     results.Add(selectedEnchantment);
  306.                     enchantmentsGenerated++;
  307.                 }
  308.                 attempts++;
  309.                 if (enchantmentsGenerated == count || attempts >= maximumAttempts)
  310.                 {
  311.                     isSearching = false;
  312.                 }
  313.             }
  314.             return results;
  315.         }
  316.  
  317.         private int GenerateEnchantmentCount(QualityType quality)
  318.         {
  319.             int result = 0;
  320.             switch (quality)
  321.             {
  322.                 case QualityType.Uncommon:
  323.                     if (_random.NextProbability(75))
  324.                     {
  325.                         return 1;
  326.                     }
  327.                     break;
  328.                 case QualityType.Rare:
  329.                     if (_random.NextProbability(75))
  330.                     {
  331.                         result += 1;
  332.                     }
  333.                     if (_random.NextProbability(40))
  334.                     {
  335.                         result += 1;
  336.                     }
  337.                     break;
  338.                 case QualityType.Epic:
  339.                     if (_random.NextProbability(75))
  340.                     {
  341.                         result += 1;
  342.                     }
  343.                     for (int i = 0; i < 2; i++)
  344.                     {
  345.                         if (_random.NextProbability(40))
  346.                         {
  347.                             result += 1;
  348.                         }
  349.                     }
  350.                     break;
  351.                 case QualityType.Legendary:
  352.                     if (_random.NextProbability(75))
  353.                     {
  354.                         result += 1;
  355.                     }
  356.                     if (_random.NextProbability(75))
  357.                     {
  358.                         result += 1;
  359.                     }
  360.                     if (_random.NextProbability(40))
  361.                     {
  362.                         result += 1;
  363.                     }
  364.                     break;
  365.             }
  366.             return result;
  367.         }
  368.     }
  369. }
  370.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement