public TradeGoodsList BuildTradeGoodsList(World origin, bool advancedMode, bool illegalGoods, int brokerScore, Dice random)
        {
            IReadOnlyList <TradeGood> goods;

            if (!illegalGoods)
            {
                goods = m_LegalTradeGoods;
            }
            else
            {
                goods = m_TradeGoods;
            }
            var result = new TradeGoodsList();

            List <TradeOffer> availableLots = new List <TradeOffer>();


            var randomGoods = new List <TradeGood>();

            /*
             * Goods with *: Always available
             * Good with no mark: Only 1 chance
             * Other goods: 5 chances plus 20 chances per matching remark
             */
            foreach (var good in goods)
            {
                if (good.Availability == "*")
                {
                    AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                }
                else if (good.Availability == "") //extremely rare
                {
                    randomGoods.Add(good);
                }
                else
                {
                    for (var i = 0; i < 1 + (5 * good.AvailabilityList.Count(a => origin.ContainsRemark(a))); i++)
                    {
                        randomGoods.Add(good);
                    }
                }
            }

            for (var i = 0; i < 6; i++)
            {
                var good = random.Choose(randomGoods);
                AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                randomGoods = randomGoods.Where(g => g != good).ToList();
            }

            List <TradeBid> requests = new List <TradeBid>();

            if (!advancedMode)
            {
                foreach (var good in goods)
                {
                    if (good.BasePrice == 0) //special case
                    {
                        foreach (var detail in good.Details)
                        {
                            foreach (var name in detail.NameList)
                            {
                                var bid = new TradeBid()
                                {
                                    Type      = good.Name,
                                    Subtype   = name,
                                    BasePrice = detail.Price * 1000,
                                    SaleDM    = SaleDM(origin, good),
                                };

                                //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                                int roll;
                                bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                                bid.Roll          = roll;

                                requests.Add(bid);
                            }
                        }
                    }
                    else
                    {
                        var bid = new TradeBid()
                        {
                            Type      = good.Name,
                            Subtype   = null,
                            BasePrice = good.BasePrice * 1000,
                            SaleDM    = SaleDM(origin, good),
                        };

                        //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                        int roll;
                        bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                        bid.Roll          = roll;

                        requests.Add(bid);
                    }
                }
            }
            else
            {
                foreach (var good in goods)
                {
                    foreach (var detail in good.Details)
                    {
                        foreach (var name in detail.NameList)
                        {
                            var bid = new TradeBid()
                            {
                                Type      = good.Name,
                                Subtype   = name,
                                BasePrice = detail.Price * 1000,
                                SaleDM    = SaleDM(origin, good),
                            };

                            //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                            int roll;
                            bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                            bid.Roll          = roll;

                            requests.Add(bid);
                        }
                    }
                }
            }

            result.Lots.AddRange(availableLots.OrderBy(r => r.Type).ThenBy(r => r.Subtype));
            result.Bids.AddRange(requests.OrderBy(r => r.Type).ThenBy(r => r.Subtype));

            return(result);
        }
        public TradeGoodsList BuildTradeGoodsList(World origin, bool advancedMode, bool illegalGoods, int brokerScore, Dice random)
        {
            IReadOnlyList<TradeGood> goods;
            if (!illegalGoods)
                goods = m_LegalTradeGoods;
            else
                goods = m_TradeGoods;
            var result = new TradeGoodsList();

            List<TradeOffer> availableLots = new List<TradeOffer>();


            var randomGoods = new List<TradeGood>();

            /*
             * Goods with *: Always available
             * Good with no mark: Only 1 chance
             * Other goods: 5 chances plus 20 chances per matching remark
             */
            foreach (var good in goods)
            {
                if (good.Availability == "*")
                {
                    AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                }
                else if (good.Availability == "") //extremely rare
                {
                    randomGoods.Add(good);
                }
                else
                {
                    for (var i = 0; i < 1 + (5 * good.AvailabilityList.Count(a => origin.ContainsRemark(a))); i++)
                        randomGoods.Add(good);
                }
            }

            for (var i = 0; i < 6; i++)
            {
                var good = random.Choose(randomGoods);
                AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                randomGoods = randomGoods.Where(g => g != good).ToList();
            }

            List<TradeBid> requests = new List<TradeBid>();
            if (!advancedMode)
                foreach (var good in goods)
                {
                    if (good.BasePrice == 0) //special case
                    {
                        foreach (var detail in good.Details)
                            foreach (var name in detail.NameList)
                            {
                                var bid = new TradeBid()
                                {
                                    Type = good.Name,
                                    Subtype = name,
                                    BasePrice = detail.Price * 1000,
                                    SaleDM = SaleDM(origin, good),
                                };

                                //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them 
                                int roll;
                                bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                                bid.Roll = roll;

                                requests.Add(bid);
                            }
                    }
                    else
                    {
                        var bid = new TradeBid()
                        {
                            Type = good.Name,
                            Subtype = null,
                            BasePrice = good.BasePrice * 1000,
                            SaleDM = SaleDM(origin, good),
                        };

                        //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them 
                        int roll;
                        bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                        bid.Roll = roll;

                        requests.Add(bid);
                    }
                }
            else
                foreach (var good in goods)
                    foreach (var detail in good.Details)
                        foreach (var name in detail.NameList)
                        {
                            var bid = new TradeBid()
                            {
                                Type = good.Name,
                                Subtype = name,
                                BasePrice = detail.Price * 1000,
                                SaleDM = SaleDM(origin, good),
                            };

                            //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them 
                            int roll;
                            bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                            bid.Roll = roll;

                            requests.Add(bid);
                        }

            result.Lots.AddRange(availableLots.OrderBy(r => r.Type).ThenBy(r => r.Subtype));
            result.Bids.AddRange(requests.OrderBy(r => r.Type).ThenBy(r => r.Subtype));

            return result;
        }
        public TradeGoodsList BuildTradeGoodsList(World origin, bool advancedMode, bool illegalGoods, int brokerScore, Dice random, bool raffleGoods)
        {
            if (origin == null)
            {
                throw new ArgumentNullException(nameof(origin), $"{nameof(origin)} is null.");
            }

            if (random == null)
            {
                throw new ArgumentNullException(nameof(random), $"{nameof(random)} is null.");
            }

            IReadOnlyList <TradeGood> goods;

            if (!illegalGoods)
            {
                goods = LegalTradeGoods;
            }
            else
            {
                goods = TradeGoods;
            }
            var result = new TradeGoodsList();

            List <TradeOffer> availableLots = new List <TradeOffer>();


            var randomGoods = new List <TradeGood>();

            if (raffleGoods)
            {
                /*
                 * Goods with *: Always available
                 * Good with no mark: Only 1 chance
                 * Other goods: 5 chances plus 20 chances per matching remark (trade code)
                 * 6 goods are selected by the raffle
                 */
                foreach (var good in goods)
                {
                    if (good.Availability == "*")
                    {
                        AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                    }
                    else if (good.Availability == "") //extremely rare
                    {
                        randomGoods.Add(good);
                    }
                    else
                    {
                        for (var i = 0; i < 5 + (20 * good.AvailabilityList.Count(a => origin.ContainsRemark(a))); i++)
                        {
                            randomGoods.Add(good);
                        }
                    }
                }

                for (var i = 0; i < origin.PopulationCode.Value; i++)
                {
                    var good = random.Choose(randomGoods);
                    AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                    randomGoods = randomGoods.Where(g => g != good).ToList();
                }
            }
            else
            {
                /*
                 * Goods with *: Always available
                 * Matching Trade remakrs: Always available
                 * Other goods: 1 chance. 1d6 Selected
                 */

                foreach (var good in goods)
                {
                    if (good.Availability == "*")
                    {
                        AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                    }
                    else if (good.AvailabilityList.Any(a => origin.ContainsRemark(a)))
                    {
                        AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                    }
                    else
                    {
                        randomGoods.Add(good);
                    }
                }

                var picks = random.D(6);
                for (var i = 0; i < picks; i++)
                {
                    var good = random.Pick(randomGoods);
                    AddTradeGood(origin, random, availableLots, good, advancedMode, brokerScore);
                }
            }

            List <TradeBid> requests = new List <TradeBid>();

            if (!advancedMode)
            {
                foreach (var good in goods)
                {
                    if (good.BasePrice == 0) //special case
                    {
                        foreach (var detail in good.Details)
                        {
                            foreach (var name in detail.NameList)
                            {
                                var bid = new TradeBid()
                                {
                                    Type      = good.Name,
                                    Subtype   = name,
                                    BasePrice = detail.Price * 1000,
                                    SaleDM    = SaleDM(origin, good),
                                };

                                //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                                int roll;
                                bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                                bid.Roll          = roll;

                                requests.Add(bid);
                            }
                        }
                    }
                    else
                    {
                        var bid = new TradeBid()
                        {
                            Type      = good.Name,
                            Subtype   = null,
                            BasePrice = good.BasePrice * 1000,
                            SaleDM    = SaleDM(origin, good),
                        };

                        //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                        int roll;
                        bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                        bid.Roll          = roll;

                        requests.Add(bid);
                    }
                }
            }
            else
            {
                foreach (var good in goods)
                {
                    foreach (var detail in good.Details)
                    {
                        foreach (var name in detail.NameList)
                        {
                            var bid = new TradeBid()
                            {
                                Type      = good.Name,
                                Subtype   = name,
                                BasePrice = detail.Price * 1000,
                                SaleDM    = SaleDM(origin, good),
                            };

                            //TODO: Auto-bump the price so that the merchant isn't buying from the PCs at a higher price than he would sell to them
                            int roll;
                            bid.PriceModifier = SalePriceModifier(random, bid.SaleDM, brokerScore, out roll);
                            bid.Roll          = roll;

                            requests.Add(bid);
                        }
                    }
                }
            }

            result.Lots.AddRange(availableLots.OrderBy(r => r.Type).ThenBy(r => r.Subtype));
            result.Bids.AddRange(requests.OrderBy(r => r.Type).ThenBy(r => r.Subtype));

            return(result);
        }