public override IEnumerable <Gizmo> CompGetGizmosExtra()
        {
            var gizmos = new List <Gizmo>();

            gizmos.Add(MakeDispenseNGizmo(1));
            gizmos.Add(MakeDispenseNGizmo(5));

            switchMode = new Command_Action();

            switchMode.icon = Resources.Cycle;

            switchMode.defaultLabel = (currentMode.ToString() + "Mode").Translate();
            switchMode.defaultDesc  = (currentMode.ToString() + "Mode_desc").Translate() + "\n" + "DispenserModeWarning".Translate();

            switchMode.action = delegate
            {
                var values = Enum.GetValues(typeof(DispenseMode));
                int n      = Array.IndexOf(values, currentMode);
                n++;
                if (n >= values.Length)
                {
                    n = 0;
                }
                currentMode = (DispenseMode)values.GetValue(n);
            };

            gizmos.Add(switchMode);

            return(gizmos);
        }
        bool ForceDispense(int count, DispenseMode mode)
        {
            if (!Utils.DrawPowerFromNetwork((Verse.Building) this.parent, ForceDispensePowerCost * count, true))
            {
                Messages.Message("NPDNoEnergy".Translate(), MessageTypeDefOf.RejectInput);
                return(false);
            }

            for (int i = 0; i < count; i++)
            {
                Thing meal = ((Building_NutrientPasteDispenser)this.parent).TryDispenseFood(mode, true);
                if (meal == null)
                {
                    return(false);
                }

                // TODO: refund (very unlikely)
                if (!GenPlace.TryPlaceThing(meal, this.parent.InteractionCell, this.parent.Map, ThingPlaceMode.Near))
                {
                    return(false);
                }
            }

            Utils.DrawPowerFromNetwork((Verse.Building) this.parent, ForceDispensePowerCost * count);

            return(true);
        }
        static int rankForPawn(DispenseMode mode, ThingDef def)
        {
            FoodCategory pref = def.DetermineFoodCategory();

            FoodCategory[] rank;

            if (mode == DispenseMode.Cannibal || mode == DispenseMode.CannibalClean)
            {
                rank = ranksForCannibals;
            }
            else
            {
                rank = ranksForOthers;
            }

            int num = Array.IndexOf(rank, pref);

            if (num == -1)
            {
                Log.Warning("Found unexpected food in hopper : " + def);
                num = rank.Count() - 1;
            }

            return(num);
        }
#pragma warning disable RECS0082 // Parameter has the same name as a member and hides it
        static int rankForPawn(DispenseMode mode, ThingDef def)
#pragma warning restore RECS0082 // Parameter has the same name as a member and hides it
        {
            FoodCategory pref = def.DetermineFoodCategory();

            FoodCategory[] rank;

            if (mode == DispenseMode.Cannibal || mode == DispenseMode.CannibalClean)
            {
                rank = ranksForCannibals;
            }
            else
            {
                rank = ranksForOthers;
            }

            int num = Array.IndexOf(rank, pref);

            if (num == -1)
            {
                Log.Warning("Found unexpected food in hopper : " + def);
                num = rank.Count() - 1;
            }

            return(num);
        }
        static List <Thing> IngredientsFor(Building_NutrientPasteDispenser self, DispenseMode mode)
        {
            var list = GetAllHoppersThings(self);

            int[] foodCountByRank = new int[4];

            for (int i = 0; i < 4; i++)
            {
                var current = foodCountByRank[i];
                foodCountByRank[i] = list.Where((arg) => rankForPawn(mode, arg.def) == i).Sum((arg) => arg.stackCount);
            }

            FoodCategory[] ranking;

            if (mode == DispenseMode.Cannibal || mode == DispenseMode.CannibalClean)
            {
                ranking = ranksForCannibals;
            }
            else if (mode == DispenseMode.Animal)
            {
                ranking = ranksForAnimals;
            }
            else
            {
                ranking = ranksForOthers;
            }

            var rawbadindex   = Array.IndexOf(ranking, FoodCategory.RawBad);
            var rawtastyindex = Array.IndexOf(ranking, FoodCategory.RawTasty);

            foodCountByRank[rawbadindex] = foodCountByRank[rawtastyindex] = foodCountByRank[rawbadindex] + foodCountByRank[rawtastyindex];

            var query = (from e in list
                         orderby foodCountByRank[rankForPawn(mode, e.def)] < 6, rankForPawn(mode, e.def), (e.TryGetComp <CompRottable>() != null ? e.TryGetComp <CompRottable>().TicksUntilRotAtCurrentTemp : -9999999)
                         select e).ToList();

            if (mode == DispenseMode.Clean)
            {
                query = query.Where((Thing arg) => !RimWorld.FoodUtility.IsHumanlikeMeat(arg.def) && arg.def.DetermineFoodCategory() != FoodCategory.RawInsect).ToList();
            }
            else if (mode == DispenseMode.CannibalClean)
            {
                query = query.Where((Thing arg) => arg.def.DetermineFoodCategory() != FoodCategory.RawInsect).ToList();
            }

            return(query);
        }
        //[DetourMethod(typeof(RimWorld.Building_NutrientPasteDispenser),"TryDispenseFood")]
        // RimWorld.Building_NutrientPasteDispenser
        public static Thing TryDispenseFood(this RimWorld.Building_NutrientPasteDispenser self, DispenseMode mode = DispenseMode.Standard, bool silent = false)
        {
            if (!self.CanDispenseNow)
            {
                return(null);
            }

            // ----- begin mod code ------

            List <Thing> ingredients;

            ingredients = IngredientsFor(self, mode);

            if (ingredients.Sum((arg) => arg.stackCount) < NutritionCostPerDispense)
            {
                if (!silent)
                {
                    Log.Error("Did not find enough food in hoppers while trying to dispense. (" + ingredients.Count + "/" + NutritionCostPerDispense + ")");
                }
                return(null);
            }
#if DEBUG
            //foreach (var e in query)
            //{
            //	Log.Message("dispenser has " + e.def + " rank: #" + rankForPawn(eater, e.def) + " total count: " + e.stackCount);
            //}
            //Log.Message("dispense");
#endif

            self.def.building.soundDispense.PlayOneShot(new TargetInfo(self.Position, self.Map, false));

            Thing           thing2          = ThingMaker.MakeThing(ThingDefOf.MealNutrientPaste, null);
            CompIngredients compIngredients = thing2.TryGetComp <CompIngredients>();

            float num = 0;

            for (int i = 0; num < NutritionCostPerDispense; i++)
            {
                var nutrition = ingredients[i].GetStatValue(StatDefOf.Nutrition);

                float num2 = Mathf.Min(ingredients[i].stackCount * nutrition, NutritionCostPerDispense);
                num += num2;
                ingredients[i].SplitOff(Convert.ToInt32(num2 / nutrition));
                compIngredients.RegisterIngredient(ingredients[i].def);
            }

            if (Config.SeparatedNutrientPaste && compIngredients.ingredients.Any((arg) => arg.DetermineFoodCategory() == FoodCategory.RawHuman))
            {
                thing2.def = ThingDef.Named("MealNutrientPasteCannibal");
            }

            // ----- end mod code ------

            return(thing2);
        }