private static PawnKindDef determinePawnKind(Map map, Predicate <PawnKindDef> isAnimal, float inBiomeWeightNormalized, float outBiomeWeightNormalized, int rndInt, int pawnHandlingLevel, List <string> factionFarmAnimalRestrictions, List <string> factionWildAnimalRestrictions)
        {
            PawnKindDef pawnKindDef = null;



            if (factionWildAnimalRestrictions.NullOrEmpty() && rndInt <= inBiomeWeightNormalized)
            {
                (from a in map.Biome.AllWildAnimals
                 where map.mapTemperature.SeasonAcceptableFor(a.race) &&
                 IsMountableUtility.isAllowedInModOptions(a.defName)
                 select a).TryRandomElementByWeight((PawnKindDef def) => calculateCommonality(def, map, pawnHandlingLevel), out pawnKindDef);
            }
            else if (rndInt <= inBiomeWeightNormalized + outBiomeWeightNormalized)
            {
                (from a in DefDatabase <PawnKindDef> .AllDefs
                 where isAnimal(a) &&
                 a.wildSpawn_spawnWild &&
                 map.mapTemperature.SeasonAcceptableFor(a.race) &&
                 IsMountableUtility.isAllowedInModOptions(a.defName) &&
                 (factionWildAnimalRestrictions.NullOrEmpty() || factionWildAnimalRestrictions.Contains(a.defName))
                 select a).TryRandomElementByWeight((PawnKindDef def) => calculateCommonality(def, map, pawnHandlingLevel), out pawnKindDef);
            }
            else
            {
                (from a in DefDatabase <PawnKindDef> .AllDefs
                 where isAnimal(a) &&
                 !a.wildSpawn_spawnWild &&
                 map.mapTemperature.SeasonAcceptableFor(a.race) &&
                 IsMountableUtility.isAllowedInModOptions(a.defName) &&
                 (factionFarmAnimalRestrictions.NullOrEmpty() || factionFarmAnimalRestrictions.Contains(a.defName))
                 select a).TryRandomElementByWeight((PawnKindDef def) => 1 - def.RaceProps.wildness, out pawnKindDef);
            }

            return(pawnKindDef);
        }
        public static void AddMountingOptions(Pawn target, Pawn pawn, List <FloatMenuOption> opts)
        {
            var pawnData = Base.Instance.GetExtendedDataStorage().GetExtendedDataFor(pawn);

            if (target.Faction != null && target.Faction != Faction.OfPlayer)
            {
                return;
            }

            if (pawnData.mount == null)
            {
                bool canMount = false;
                if (Base.GiddyUpMechanoidsLoaded && target.RaceProps.IsMechanoid)
                {
                    canMount = true; //additional checking takes place in Giddy-up! Battle Mechs.
                }
                if (target.RaceProps.Animal)
                {
                    canMount = IsMountableUtility.isMountable(target, out IsMountableUtility.Reason reason);

                    if (!canMount && reason == IsMountableUtility.Reason.NotInModOptions)
                    {
                        opts.Add(new FloatMenuOption("GUC_NotInModOptions".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (target.CurJob != null && (target.InMentalState ||
                                                  target.IsBurning() ||
                                                  target.CurJob.def == JobDefOf.LayEgg ||
                                                  target.CurJob.def == JobDefOf.Nuzzle ||
                                                  target.CurJob.def == JobDefOf.Lovin ||
                                                  target.CurJob.def == JobDefOf.Wait_Downed ||
                                                  target.CurJob.def == GUC_JobDefOf.Mounted
                                                  ))
                    {
                        opts.Add(new FloatMenuOption("GUC_AnimalBusy".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (!canMount && reason == IsMountableUtility.Reason.NotFullyGrown)
                    {
                        opts.Add(new FloatMenuOption("GUC_NotFullyGrown".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (!canMount && reason == IsMountableUtility.Reason.NeedsTraining)
                    {
                        opts.Add(new FloatMenuOption("GUC_NeedsObedience".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (!canMount && reason == IsMountableUtility.Reason.IsRoped)
                    {
                        opts.Add(new FloatMenuOption("GUC_IsRoped".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                }

                if (canMount)
                {
                    Action action = delegate
                    {
                        if (Base.GiddyUpMechanoidsLoaded && target.RaceProps.IsMechanoid)
                        {
                            if (!pawn.Drafted)
                            {
                                //pawn.drafter.Drafted = true; moving to external method to sync across multiplayer clients
                                UpdatePawnDrafted(pawn, true);
                            }
                            if (target.drafter != null && target.Drafted)
                            {
                                //target.drafter.Drafted = false; moving to external method to sync across multiplayer clients
                                UpdatePawnDrafted(target, false);
                            }
                        }
                        Job jobRider = new Job(GUC_JobDefOf.Mount, target);
                        jobRider.count = 1;
                        pawn.jobs.TryTakeOrderedJob(jobRider);
                    };
                    opts.Add(new FloatMenuOption("GUC_Mount".Translate() + " " + target.Name, action, MenuOptionPriority.Low));
                }
            }
            else if (target == pawnData.mount)
            {
                //if (opts.Count > 0) opts.RemoveAt(0);//Remove option to attack your own mount

                Action action = delegate
                {
                    //pawnData.reset(); moving to external method to sync across multiplayer clients
                    ResetPawnData(pawnData);
                };
                opts.Add(new FloatMenuOption("GUC_Dismount".Translate(), action, MenuOptionPriority.High));
            }
        }
        private static PawnKindDef determinePawnKind(Map map, Predicate <PawnKindDef> isAnimal, float inBiomeWeightNormalized, float outBiomeWeightNormalized, int rndInt, int pawnHandlingLevel, List <string> factionFarmAnimalRestrictions, List <string> factionWildAnimalRestrictions, IncidentParms parms)
        {
            PawnKindDef             pawnKindDef        = null;
            float                   averageCommonality = AverageAnimalCommonality(map);
            Predicate <PawnKindDef> canUseAnimal       = (PawnKindDef a) => map.mapTemperature.SeasonAcceptableFor(a.race) && IsMountableUtility.isAllowedInModOptions(a.defName) && parms.points > a.combatPower * 2f;

            if (factionWildAnimalRestrictions.NullOrEmpty() && rndInt <= inBiomeWeightNormalized)
            {
                (from a in map.Biome.AllWildAnimals
                 where canUseAnimal(a)
                 select a).TryRandomElementByWeight((PawnKindDef def) => calculateCommonality(def, map, pawnHandlingLevel), out pawnKindDef);
            }
            else if (rndInt <= inBiomeWeightNormalized + outBiomeWeightNormalized)
            {
                (from a in Base.animalsWithBiome
                 where isAnimal(a) &&
                 canUseAnimal(a) &&
                 (factionWildAnimalRestrictions.NullOrEmpty() || factionWildAnimalRestrictions.Contains(a.defName))
                 select a).TryRandomElementByWeight((PawnKindDef def) => calculateCommonality(def, map, pawnHandlingLevel, averageCommonality), out pawnKindDef);
            }
            else
            {
                (from a in Base.animalsWithoutBiome
                 where isAnimal(a) &&
                 canUseAnimal(a) &&
                 (factionFarmAnimalRestrictions.NullOrEmpty() || factionFarmAnimalRestrictions.Contains(a.defName))
                 select a).TryRandomElementByWeight((PawnKindDef def) => calculateCommonality(def, map, pawnHandlingLevel, averageCommonality), out pawnKindDef);
            }
            return(pawnKindDef);
        }
        public static void AddMountingOptions(Vector3 clickPos, Pawn pawn, List <FloatMenuOption> opts)
        {
            foreach (LocalTargetInfo current in GenUI.TargetsAt(clickPos, TargetingParameters.ForAttackHostile(), true))
            {
                if (!(current.Thing is Pawn) || !((Pawn)current.Thing).RaceProps.Animal)
                {
                    return;
                }

                var  pawnData = Base.Instance.GetExtendedDataStorage().GetExtendedDataFor(pawn);
                Pawn animal   = (Pawn)current.Thing;

                if (animal.Faction != null && animal.Faction != Faction.OfPlayer)
                {
                    return;
                }

                if (pawnData.mount == null)
                {
                    bool canMount = IsMountableUtility.isMountable(animal, out IsMountableUtility.Reason reason);

                    if (!canMount && reason == IsMountableUtility.Reason.NotInModOptions)
                    {
                        opts.Add(new FloatMenuOption("GUC_NotInModOptions".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (animal.InMentalState ||
                        animal.IsBurning() ||
                        animal.CurJob.def == JobDefOf.LayEgg ||
                        animal.CurJob.def == JobDefOf.Nuzzle ||
                        animal.CurJob.def == JobDefOf.Lovin ||
                        animal.CurJob.def == JobDefOf.WaitDowned ||
                        animal.CurJob.def == GUC_JobDefOf.Mounted
                        )
                    {
                        opts.Add(new FloatMenuOption("GUC_AnimalBusy".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (!canMount && reason == IsMountableUtility.Reason.NotFullyGrown)
                    {
                        opts.Add(new FloatMenuOption("GUC_NotFullyGrown".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }
                    if (!canMount && reason == IsMountableUtility.Reason.NeedsObedience)
                    {
                        opts.Add(new FloatMenuOption("GUC_NeedsObedience".Translate(), null, MenuOptionPriority.Low));
                        return;
                    }


                    Action action = delegate
                    {
                        Job jobRider = new Job(GUC_JobDefOf.Mount, animal);
                        jobRider.count = 1;
                        pawn.jobs.TryTakeOrderedJob(jobRider);
                    };
                    opts.Add(new FloatMenuOption("GUC_Mount".Translate() + " " + animal.Name, action, MenuOptionPriority.Low));
                }
                else if (animal == pawnData.mount)
                {
                    if (opts.Count > 0)
                    {
                        opts.RemoveAt(0);                //Remove option to attack your own mount
                    }
                    Action action = delegate
                    {
                        pawnData.reset();
                    };
                    opts.Add(new FloatMenuOption("GUC_Dismount".Translate(), action, MenuOptionPriority.Default));
                }
            }
        }