protected void SpawnPawns(IncidentParms parms, List <Pawn> spawned)
        {
            var map = (Map)parms.target;

            var selection = GetPawnsToSpawn(parms).Distinct();

            foreach (var pawn in selection)
            {
                try
                {
                    var visitor = SpawnGroupUtility.SpawnVisitor(spawned, pawn, map, parms.spawnCenter);
                    if (visitor.needs?.rest != null)
                    {
                        visitor.needs.rest.CurLevel = Rand.Range(0.1f, 0.7f);
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Hospitality: Failed to spawn pawn {pawn?.Label}:\n{e}");
                    if (pawn.Spawned)
                    {
                        pawn.DeSpawn();
                        pawn.DestroyOrPassToWorld();
                    }
                }
            }
        }
        private bool SpawnGroup(IncidentParms parms, Map map)
        {
            var visitors = new List <Pawn>();

            try
            {
                //Log.Message(string.Format("Spawning visitors from {0}, at {1}.", parms.faction, parms.spawnCenter));
                SpawnPawns(parms, visitors);

                SpawnGroupUtility.CheckVisitorsValid(visitors);

                if (visitors == null || visitors.Count == 0)
                {
                    return(false);
                }

                var area = visitors.First().GetGuestArea() ?? map.GetMapComponent().defaultAreaRestriction;
                var spot = GetSpot(map, area, visitors.First());

                if (!spot.IsValid)
                {
                    throw new Exception($"Visitors from {parms.faction.Name} failed to find a valid travel target from {visitors.First()?.Position} to guest area {area?.Label}.");
                }

                GiveItems(visitors);

                var stayDuration = (int)(Rand.Range(1f, 2.4f) * GenDate.TicksPerDay);
                CreateLord(parms.faction, spot, visitors, map, true, true, stayDuration);
            }
            catch (Exception e)
            {
                var faction     = parms.faction?.Name;
                var factionType = parms.faction?.def.label;
                Log.Error($"Hospitality: Something failed when setting up visitors from faction {faction} ({factionType}):\n{e}");
                foreach (var visitor in visitors)
                {
                    if (visitor?.Spawned == true)
                    {
                        visitor.DeSpawn();
                        visitor.DestroyOrPassToWorld();
                    }
                }
                GenericUtility.PlanNewVisit(map, Rand.Range(1f, 3f), parms.faction);
            }
            return(true); // be gone, event
        }
        protected IEnumerable <Pawn> GetPawnsToSpawn(IncidentParms parms)
        {
            var totalAmount     = GetGroupSize();
            int knownPawnAmount = Mathf.RoundToInt(totalAmount * ChanceToKnowEachPawn);

            var options = SpawnGroupUtility.GetKnownPawns(parms).RandomlyUsingTitleAsChance().InRandomOrder().Take(knownPawnAmount).ToList();

            if (options.Count < totalAmount)
            {
                try
                {
                    // Create some new people
                    int missing  = totalAmount - options.Count;
                    var newPawns = GenerateNewPawns(parms, missing);
                    options.AddRange(newPawns);
                }
                catch (Exception e)
                {
                    Log.Error($"Failed to create new pawns for faction {parms.faction?.Name}.\n{e}");
                }
            }
            return(options);
        }
        private static void GiveItems(IEnumerable <Pawn> visitors)
        {
            foreach (var visitor in visitors)
            {
                PawnInventoryGenerator.GiveRandomFood(visitor);
                if (Rand.Value < 0.5f)
                {
                    visitor.TryGiveBackpack();
                }


                float totalValue = 0;

                // Money
                //Log.Message("Goodwill: "+visitor.Faction.ColonyGoodwill);
                var wealthBase = visitor.Faction.PlayerGoodwill;
                var title      = visitor.royalty?.MostSeniorTitle;
                if (title != null)
                {
                    wealthBase += title.def.seniority / 2;
                }
                var amountS = Mathf.Max(0, Mathf.RoundToInt(Rand.Gaussian(wealthBase, wealthBase) * 2)) + Rand.Range(0, 40);
                if (amountS >= Rand.Range(10, 25))
                {
                    var money = SpawnGroupUtility.CreateRandomItem(visitor, ThingDefOf.Silver);
                    money.stackCount = amountS;

                    var spaceFor = visitor.GetInventorySpaceFor(money);
                    if (spaceFor > 0)
                    {
                        money.stackCount = Mathf.Min(spaceFor, amountS);
                        var success = visitor.inventory.innerContainer.TryAdd(money);
                        if (success)
                        {
                            totalValue += money.MarketValue * money.stackCount;
                        }
                        else if (!money.Destroyed)
                        {
                            money.Destroy();
                        }
                    }
                }

                // Items
                float maxValue = (wealthBase + 25) * Rand.Range(5, 8);
                if (maxValue - totalValue <= 100)
                {
                    maxValue = totalValue + Rand.Range(25, 60);                               // At least bring some junk
                }
                float value    = maxValue - totalValue;
                int   curCount = 0;
                while (value > 100 && curCount < 200)
                {
                    //Log.Message("Total is now " + totalValue + ", space left is " + space);
                    curCount++;

                    bool     apparel = Rand.Value < 0.5f;
                    ThingDef thingDef;
                    do
                    {
                        thingDef = SpawnGroupUtility.GetRandomItem(visitor.Faction.def.techLevel, ref _items);
                    }while (thingDef != null && apparel && thingDef.IsApparel);
                    if (thingDef == null)
                    {
                        break;
                    }

                    //var amount = Mathf.Min(Mathf.RoundToInt(Mathf.Abs(Rand.Gaussian(1, thingDef.stackLimit/2f))),
                    //    thingDef.stackLimit);
                    //if (amount <= 0) continue;

                    var item = SpawnGroupUtility.CreateRandomItem(visitor, thingDef);

                    //Log.Message(item.Label + " has this value: " + item.MarketValue);
                    if (item.Destroyed)
                    {
                        continue;
                    }

                    if (item.MarketValue >= value)
                    {
                        item.Destroy();
                        continue;
                    }

                    if (item.MarketValue < 1)
                    {
                        item.Destroy();
                        continue;
                    }
                    var uniquesAmount = item.TryGetComp <CompQuality>() != null ? 1 : item.def.stackLimit;
                    var maxItems      = Mathf.Min(Mathf.FloorToInt(value / item.MarketValue), item.def.stackLimit, uniquesAmount);
                    var minItems      = Mathf.Max(1, Mathf.CeilToInt(Rand.Range(50, 100) / item.MarketValue));

                    if (maxItems < 1 || minItems > maxItems)
                    {
                        item.Destroy();
                        continue;
                    }

                    //Log.Message("Can fit " + maxItems+" of "+item.Label);
                    item.stackCount = Rand.RangeInclusive(minItems, maxItems);
                    //Log.Message("Added " + item.stackCount + " with a value of " + (item.MarketValue * item.stackCount));

                    var spaceFor = visitor.GetInventorySpaceFor(item);
                    if (spaceFor > 0)
                    {
                        item.stackCount = Mathf.Min(spaceFor, item.stackCount);
                        var success = visitor.inventory.innerContainer.TryAdd(item);
                        if (success)
                        {
                            totalValue += item.MarketValue * item.stackCount;
                        }
                        else if (!item.Destroyed)
                        {
                            item.Destroy();
                        }
                    }
                    value = maxValue - totalValue;
                }
            }
        }