public static void Postfix(ref RecipeWorkerCounter __instance, ref int __result, ref Bill_Production bill)
        {
            var extendedBillData = Main.Instance.GetExtendedBillDataStorage().GetExtendedDataFor(bill);

            if (extendedBillData == null)
            {
                return;
            }

            if (extendedBillData.ProductAdditionalFilter != null)
            {
                __result += CountAdditionalProducts(__instance, bill, extendedBillData);
            }

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(bill))
            {
                return;
            }

            var productThingDef = bill.recipe.products.First().thingDef;

            // Count resource items not in stockpiles
            if (Main.Instance.ShouldCountOutsideStockpiles() &&
                productThingDef.CountAsResource &&
                !bill.includeEquipped &&
                (bill.includeTainted || !productThingDef.IsApparel || !productThingDef.apparel.careIfWornByCorpse) &&
                bill.includeFromZone == null &&
                bill.hpRange.min == 0f &&
                bill.hpRange.max == 1f &&
                bill.qualityRange.min == QualityCategory.Awful &&
                bill.qualityRange.max == QualityCategory.Legendary &&
                !bill.limitToAllowedStuff)
            {
                __result += GetMatchingItemCountOutsideStockpiles(bill, productThingDef);
            }

            if (!bill.includeEquipped)
            {
                return;
            }

            if (extendedBillData.CountAway)
            {
                __result += CountAway(bill.Map, __instance, bill, productThingDef);
            }
        }
        // Constructor for migrating old data storage format to new method.
        public ExtendedBillData(Bill_Production bill)
        {
            var billWithWorkerFilter = bill as IBillWithWorkerFilter;

            Worker = billWithWorkerFilter.GetWorker();

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(bill))
            {
                return;
            }

            var billWithThingFilter = bill as IBillWithThingFilter;

            if (billWithThingFilter == null)
            {
                return;
            }

            OutputFilter         = billWithThingFilter.GetOutputFilter();
            AllowDeadmansApparel = billWithThingFilter.GetAllowDeadmansApparel();
            UseInputFilter       = billWithThingFilter.GetUseInputFilter();
        }
Пример #3
0
        public static void DrawFilters(Dialog_BillConfig __instance, Rect inRect)
        {
            var billRaw = (Bill_Production)BillGetter.GetValue(__instance);

            if (billRaw == null)
            {
                return;
            }

            var extendedBillDataStorage = Main.Instance.GetExtendedBillDataStorage();

            extendedBillDataStorage.MirrorBillToLinkedBills(billRaw);

            var extendedBillData = extendedBillDataStorage.GetOrCreateExtendedDataFor(billRaw);

            if (extendedBillData == null)
            {
                return;
            }

            // Bill navigation buttons
            DrawWorkTableNavigation(__instance, billRaw, inRect);

            var nextConfigButtonX = inRect.xMin + 28f;

            // Copy bill button
            {
                var copyBillRect = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                if (Widgets.ButtonImage(copyBillRect, Resources.CopyButton))
                {
                    Main.Instance.BillCopyPasteHandler.DoCopy(billRaw);
                }
                TooltipHandler.TipRegion(copyBillRect, "IW.CopyJustBillsTip".Translate());
                nextConfigButtonX += 28f;
            }

            // Paste into bill button
            {
                var pasteRect        = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                var copyPasteHandler = Main.Instance.BillCopyPasteHandler;
                if (copyPasteHandler.CanPasteInto(billRaw))
                {
                    if (Widgets.ButtonImage(pasteRect, Resources.PasteButton))
                    {
                        copyPasteHandler.DoPasteInto(billRaw);
                    }
                    TooltipHandler.TipRegion(pasteRect, "IW.PasteBillSettings".Translate());

                    nextConfigButtonX += 28f;
                }
            }

            // Linked bill handling
            if (extendedBillDataStorage.IsLinkedBill(billRaw))
            {
                var unlinkRect = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                if (Widgets.ButtonImage(unlinkRect, Resources.BreakLink))
                {
                    extendedBillDataStorage.RemoveBillFromLinkSets(billRaw);
                }
                TooltipHandler.TipRegion(unlinkRect, "IW.BreakLinkToOtherBillsTip".Translate());
            }

            // Bill renaming
            {
                var renameRect = new Rect(inRect.xMax - 75f, inRect.yMin + 4f, 24f, 24f);
                if (Widgets.ButtonImage(renameRect, Resources.Rename))
                {
                    Find.WindowStack.Add(new Dialog_RenameBill(extendedBillData, billRaw.LabelCap));
                }
                TooltipHandler.TipRegion(renameRect, "IW.RenameBillTip".Translate());
            }

            const float columnWidth = 180f;

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(billRaw))
            {
                return;
            }

            if (billRaw.repeatMode != BillRepeatModeDefOf.TargetCount)
            {
                return;
            }

            const float buttonHeight = 26f;

            var y = inRect.height - 84f;

            // Helper method for checkboxes
            void SimpleCheckBoxWithToolTip(string label, ref bool setting, string tip)
            {
                var subRect = new Rect(0f, y, columnWidth, buttonHeight);

                Widgets.CheckboxLabeled(subRect, label.Translate(),
                                        ref setting);

                TooltipHandler.TipRegion(subRect, tip.Translate());
                y += 26;
            };

            // Checkbox helper method with consistent language tokens
            void SimpleCheckBox(string label, ref bool setting)
            {
                SimpleCheckBoxWithToolTip($"IW.{label}Label", ref setting, $"IW.{label}Desc");
            }

            // Inventory Filter
            if (billRaw.includeEquipped)
            {
                SimpleCheckBox("CountAway", ref extendedBillData.CountAway);
            }
        }
Пример #4
0
        public static void DrawFilters(Dialog_BillConfig __instance, Rect inRect)
        {
            var billRaw = (Bill_Production)BillGetter.GetValue(__instance);

            if (billRaw == null)
            {
                return;
            }

            Main.Instance.IsRootBillFilterBeingDrawn = false;

            var extendedBillDataStorage = Main.Instance.GetExtendedBillDataStorage();

            extendedBillDataStorage.MirrorBillToLinkedBills(billRaw);

            var extendedBillData = extendedBillDataStorage.GetExtendedDataFor(billRaw);

            if (extendedBillData == null)
            {
                return;
            }

            // Bill navigation buttons
            DrawWorkTableNavigation(__instance, billRaw, inRect);

            // Linked bill handling
            if (extendedBillDataStorage.IsLinkedBill(billRaw))
            {
                var unlinkRect = new Rect(inRect.xMin + 28f, inRect.yMin + 50f, 24f, 24f);
                if (Widgets.ButtonImage(unlinkRect, Resources.BreakLink))
                {
                    extendedBillDataStorage.RemoveBillFromLinkSets(billRaw);
                }
                TooltipHandler.TipRegion(unlinkRect, "IW.BreakLinkToOtherBillsTip".Translate());
            }

            // Bill renaming
            {
                var renameRect = new Rect(inRect.xMax - 75f, inRect.yMin + 4f, 24f, 24f);
                if (Widgets.ButtonImage(renameRect, Resources.Rename))
                {
                    Find.WindowStack.Add(new Dialog_RenameBill(extendedBillData, billRaw.LabelCap));
                }
                TooltipHandler.TipRegion(renameRect, "IW.RenameBillTip".Translate());
            }

            const float columnWidth  = 180f;
            const float middleColumn = columnWidth + 34f;

            // Allowed worker filter
            var potentialWorkers = GetAllowedWorkersWithSkillLevel(billRaw);

            if (potentialWorkers != null)
            {
                var anyoneText       = "IW.NoColRestrictionLabel".Translate();
                var workerButtonRect = new Rect(middleColumn + 3f, inRect.yMin + 18f,
                                                columnWidth, 30f);

                var currentWorkerLabel =
                    extendedBillData.Worker != null
                    ? "IW.RestrictToLabel".Translate() + " " + extendedBillData.Worker.NameStringShort.CapitalizeFirst()
                    : anyoneText;

                if (Widgets.ButtonText(workerButtonRect, currentWorkerLabel))
                {
                    var potentialWorkerList = new List <FloatMenuOption>
                    {
                        new FloatMenuOption(
                            anyoneText, delegate { extendedBillData.Worker = null; })
                    };

                    foreach (var allowedWorkerAndTheirSkill in potentialWorkers)
                    {
                        var allowedWorker = allowedWorkerAndTheirSkill.First;
                        var skillRecord   = allowedWorkerAndTheirSkill.Second;
                        var skillPrefix   = "";
                        if (skillRecord != null)
                        {
                            var    level = skillRecord.Level;
                            string passion;
                            switch (skillRecord.passion)
                            {
                            case Passion.Minor:
                                passion = "+";
                                break;

                            case Passion.Major:
                                passion = "++";
                                break;

                            default:
                                passion = "";
                                break;
                            }
                            skillPrefix = $"[{level}{passion}] ";
                        }
                        var nameWithSkill = $"{skillPrefix}" + "IW.RestrictToLabel".Translate() + " " + $"{allowedWorker}";

                        var workerMenuItem = new FloatMenuOption(nameWithSkill,
                                                                 delegate { extendedBillData.Worker = allowedWorker; });

                        potentialWorkerList.Add(workerMenuItem);
                    }

                    Find.WindowStack.Add(new FloatMenu(potentialWorkerList));
                }
                TooltipHandler.TipRegion(workerButtonRect, "IW.RestrictJobToSpecificColonistTip".Translate());
            }

            // Custom take to stockpile, overlay dummy button
            {
                var storeRect = new Rect(middleColumn + 3f, inRect.yMin + 114f,
                                         columnWidth, 30f);

                var label = extendedBillData.UsesTakeToStockpile()
                    ? extendedBillData.CurrentTakeToStockpileLabel()
                    : ("BillStoreMode_" + billRaw.storeMode).Translate();

                Widgets.ButtonText(storeRect, label);
                TooltipHandler.TipRegion(storeRect,
                                         "IW.CrafterWillToSpecificStockpileTip".Translate());
            }

            // Filter copy/paste buttons
            if (billRaw.ingredientFilter != null)
            {
                const float filterButtonWidth  = 96f;
                const float filterButtonHeight = 24f;
                var         oldFont            = Text.Font;
                Text.Font = GameFont.Tiny;

                var copyPasteHandler = Main.Instance.BillCopyPasteHandler;
                var copyButtonRect   = new Rect(inRect.xMax - filterButtonWidth * 2 + 4f, inRect.yMax - 35f,
                                                filterButtonWidth, filterButtonHeight);

                var parentFilter = billRaw.recipe?.fixedIngredientFilter;
                if (Widgets.ButtonText(copyButtonRect, "IW.CopyFilterButton".Translate()))
                {
                    copyPasteHandler.CopyFilter(billRaw.ingredientFilter, parentFilter);
                }
                TooltipHandler.TipRegion(copyButtonRect, "IW.CopyFilterTip".Translate());

                if (copyPasteHandler.IsMatchingFilterCopied(parentFilter))
                {
                    var pasteButtonRect = new Rect(copyButtonRect);
                    pasteButtonRect.xMin += filterButtonWidth + 4f;
                    pasteButtonRect.xMax += filterButtonWidth + 4f;
                    if (Widgets.ButtonText(pasteButtonRect, "IW.PasteFilterButton".Translate()))
                    {
                        copyPasteHandler.PasteCopiedFilterInto(billRaw.ingredientFilter);
                    }
                }

                Text.Font = oldFont;
            }

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(billRaw))
            {
                return;
            }

            if (billRaw.repeatMode != BillRepeatModeDefOf.TargetCount)
            {
                return;
            }

            {
                var keyboardRect = new Rect(middleColumn + 90f, inRect.yMin + 208f, 24f, 24f);
                void TargetCountSetter(int i)
                {
                    billRaw.targetCount = i;
                    if (billRaw.unpauseWhenYouHave >= billRaw.targetCount)
                    {
                        billRaw.unpauseWhenYouHave = billRaw.targetCount - 1;
                    }
                }

                if (Widgets.ButtonImage(keyboardRect, Resources.Rename))
                {
                    Find.WindowStack.Add(new Dialog_NumericEntry(
                                             billRaw.targetCount,
                                             i => i > 0,
                                             TargetCountSetter));
                }
                TooltipHandler.TipRegion(keyboardRect, "IW.RenameTip".Translate());
            }

            const float buttonHeight      = 26f;
            const float smallButtonHeight = 24f;
            var         y = inRect.height - 248f + Text.LineHeight;

            // "Unpause when" level adjustment buttons
            if (billRaw.pauseWhenSatisfied)
            {
                var buttonWidth  = 42f;
                var minusOneRect = new Rect(middleColumn, inRect.height - 70, buttonWidth, smallButtonHeight);
                if (Widgets.ButtonText(minusOneRect, "-1"))
                {
                    if (billRaw.unpauseWhenYouHave > 0)
                    {
                        billRaw.unpauseWhenYouHave--;
                    }
                }

                var plusOneRect = new Rect(minusOneRect);
                plusOneRect.xMin += buttonWidth + 2f;
                plusOneRect.xMax += buttonWidth + 2f;
                if (Widgets.ButtonText(plusOneRect, "+1"))
                {
                    if (billRaw.unpauseWhenYouHave < billRaw.targetCount - 1)
                    {
                        billRaw.unpauseWhenYouHave++;
                    }
                }

                var keyboardRect = new Rect(plusOneRect.xMax + 2f, plusOneRect.yMin, 24f, 24f);
                if (Widgets.ButtonImage(keyboardRect, Resources.Rename))
                {
                    Find.WindowStack.Add(new Dialog_NumericEntry(
                                             billRaw.unpauseWhenYouHave,
                                             i => i < billRaw.targetCount,
                                             i => billRaw.unpauseWhenYouHave = i));
                }
                TooltipHandler.TipRegion(keyboardRect, "IW.RenameTip".Translate());
            }

            // Restrict counting to specific stockpile
            {
                y += 33;
                var subRect          = new Rect(0f, y, columnWidth, buttonHeight);
                var anyStockpileText = "IW.CountOnStockpilesText".Translate();
                var currentCountingStockpileLabel = extendedBillData.UsesCountingStockpile()
                    ? "Count in " + extendedBillData.GetCountingStockpile().label
                    : anyStockpileText;

                var map           = Find.VisibleMap;
                var allStockpiles =
                    map.zoneManager.AllZones.OfType <Zone_Stockpile>().ToList();

                if (Widgets.ButtonText(subRect, currentCountingStockpileLabel))
                {
                    var potentialStockpileList = new List <FloatMenuOption>
                    {
                        new FloatMenuOption(
                            anyStockpileText, delegate { extendedBillData.RemoveCountingStockpile(); })
                    };

                    foreach (var stockpile in allStockpiles)
                    {
                        var stockpileName = "IW.CountInText".Translate() + " " + stockpile.label;
                        var menuOption    = new FloatMenuOption(
                            stockpileName,
                            delegate { extendedBillData.SetCountingStockpile(stockpile); });

                        potentialStockpileList.Add(menuOption);
                    }

                    Find.WindowStack.Add(new FloatMenu(potentialStockpileList));
                }
                TooltipHandler.TipRegion(subRect,
                                         "IW.WillCountTowardsTargetTip".Translate());
            }

            var thingDef = billRaw.recipe.products.First().thingDef;

            if (!thingDef.CountAsResource)
            {
                // Counted items filter
                y += 33;
                var countedLabelRect = new Rect(0f, y, columnWidth, buttonHeight);
                Widgets.Label(countedLabelRect, "IW.CountedItemsFilter".Translate());
                y += Text.LineHeight;

                var filter = extendedBillData.OutputFilter;
                if (filter.allowedHitPointsConfigurable)
                {
                    var allowedHitPointsPercents = filter.AllowedHitPointsPercents;
                    var rect1 = new Rect(0f, y, columnWidth, buttonHeight);
                    Widgets.FloatRange(rect1, 10, ref allowedHitPointsPercents, 0f, 1f,
                                       "HitPoints", ToStringStyle.PercentZero);

                    TooltipHandler.TipRegion(rect1,
                                             "IW.HitPointsTip".Translate());
                    filter.AllowedHitPointsPercents = allowedHitPointsPercents;
                }

                if (filter.allowedQualitiesConfigurable)
                {
                    y += 33;
                    var rect2 = new Rect(0f, y, columnWidth, buttonHeight);
                    var allowedQualityLevels = filter.AllowedQualityLevels;
                    Widgets.QualityRange(rect2, 11, ref allowedQualityLevels);
                    TooltipHandler.TipRegion(rect2,
                                             "IW.QualityTip".Translate());
                    filter.AllowedQualityLevels = allowedQualityLevels;
                }
            }

            // Use input ingredients for counted items filter
            if (billRaw.ingredientFilter != null && thingDef.MadeFromStuff)
            {
                y += 33;
                var subRect = new Rect(0f, y, columnWidth, buttonHeight);
                Widgets.CheckboxLabeled(subRect, "IW.MatchInputIngredientsText".Translate(),
                                        ref extendedBillData.UseInputFilter);

                TooltipHandler.TipRegion(subRect,
                                         "IW.IngredientsTip".Translate());
            }


            // Deadmans clothing count filter
            if (thingDef.IsApparel)
            {
                var nonDeadmansApparelFilter = new SpecialThingFilterWorker_NonDeadmansApparel();
                if (!nonDeadmansApparelFilter.CanEverMatch(thingDef))
                {
                    // Thing can't be worn.
                    return;
                }

                y += 26;
                var rect3 = new Rect(0f, y, columnWidth, buttonHeight);
                Widgets.CheckboxLabeled(rect3, "IW.CountCorpseClothesLabel".Translate(),
                                        ref extendedBillData.AllowDeadmansApparel);
                TooltipHandler.TipRegion(rect3,
                                         "IW.CountCorpseClothesDesc".Translate());

                y += 26;
                var rect4 = new Rect(0f, y, columnWidth, buttonHeight);
                Widgets.CheckboxLabeled(rect4, "IW.CountEquippedClothesLabel".Translate(),
                                        ref extendedBillData.CountWornApparel);
                TooltipHandler.TipRegion(rect4,
                                         "IW.CountEquippedClothesDesc".Translate());
            }
        }
        public static void DrawFilters(Dialog_BillConfig __instance, Rect inRect)
        {
            var billRaw = (Bill_Production)BillGetter.GetValue(__instance);

            if (billRaw == null)
            {
                return;
            }

            var extendedBillDataStorage = Main.Instance.GetExtendedBillDataStorage();

            extendedBillDataStorage.MirrorBillToLinkedBills(billRaw);

            var extendedBillData = extendedBillDataStorage.GetOrCreateExtendedDataFor(billRaw);

            if (extendedBillData == null)
            {
                return;
            }

            // Bill navigation buttons
            DrawWorkTableNavigation(__instance, billRaw, inRect);

            var nextConfigButtonX = inRect.xMin + 28f;

            // Copy bill button
            {
                var copyBillRect = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                if (Widgets.ButtonImage(copyBillRect, Resources.CopyButton))
                {
                    Main.Instance.BillCopyPasteHandler.DoCopy(billRaw);
                }
                TooltipHandler.TipRegion(copyBillRect, "IW.CopyJustBillsTip".Translate());
                nextConfigButtonX += 28f;
            }

            // Paste into bill button
            {
                var pasteRect        = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                var copyPasteHandler = Main.Instance.BillCopyPasteHandler;
                if (copyPasteHandler.CanPasteInto(billRaw))
                {
                    if (Widgets.ButtonImage(pasteRect, Resources.PasteButton))
                    {
                        copyPasteHandler.DoPasteInto(billRaw);
                    }
                    TooltipHandler.TipRegion(pasteRect, "IW.PasteBillSettings".Translate());

                    nextConfigButtonX += 28f;
                }
            }

            // Linked bill handling
            if (extendedBillDataStorage.IsLinkedBill(billRaw))
            {
                var unlinkRect = new Rect(nextConfigButtonX, inRect.yMin + 50f, 24f, 24f);
                if (Widgets.ButtonImage(unlinkRect, Resources.BreakLink))
                {
                    extendedBillDataStorage.RemoveBillFromLinkSets(billRaw);
                }
                TooltipHandler.TipRegion(unlinkRect, "IW.BreakLinkToOtherBillsTip".Translate());
            }

            // Bill renaming
            {
                var renameRect = new Rect(inRect.xMax - 75f, inRect.yMin + 4f, 24f, 24f);
                if (Widgets.ButtonImage(renameRect, Resources.Rename))
                {
                    Find.WindowStack.Add(new Dialog_RenameBill(extendedBillData, billRaw.LabelCap));
                }
                TooltipHandler.TipRegion(renameRect, "IW.RenameBillTip".Translate());
            }

            const float columnWidth = 180f;

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(billRaw))
            {
                return;
            }

            if (billRaw.repeatMode != BillRepeatModeDefOf.TargetCount)
            {
                return;
            }

            Listing_Standard optionsList   = new Listing_Standard();
            float            optionsHeight = 120;

            optionsList.Begin(new Rect(0, inRect.height - optionsHeight, columnWidth, optionsHeight));

            // Inventory Filter
            if (billRaw.includeEquipped)
            {
                optionsList.CheckboxLabeled("IW.CountAwayLabel".Translate(), ref extendedBillData.CountAway, "IW.CountAwayDesc".Translate());
            }
            else
            {
                optionsList.Gap(Text.LineHeight + optionsList.verticalSpacing);
            }

            // Output Filter
            if (optionsList.ButtonText("IW.OutputFilterLabel".Translate()))
            {
                Window temp = Find.WindowStack.currentlyDrawnWindow;
                temp.Close();
                Find.WindowStack.Add(new Dialog_ThingFilter(extendedBillData, temp));
            }

            optionsList.End();
        }
Пример #6
0
        public static void Postfix(ref RecipeWorkerCounter __instance, ref int __result, ref Bill_Production bill)
        {
            if (!bill.includeEquipped)
            {
                return;
            }

            if (!ExtendedBillDataStorage.CanOutputBeFiltered(bill))
            {
                return;
            }

            var billMap = bill.Map;

            var productThingDef = bill.recipe.products.First().thingDef;

            // Fix for vanilla not counting items being hauled by colonists or animals
            foreach (var pawn in billMap.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer))
            {
                // Ignore prisoners, include animals
                if (!(pawn.IsFreeColonist || !pawn.IsColonist))
                {
                    continue;
                }

                if (pawn.carryTracker != null)
                {
                    __result += CountMatchingThingsIn(
                        pawn.carryTracker.innerContainer, __instance, bill, productThingDef);
                }
            }

            var extendedBillData = Main.Instance.GetExtendedBillDataStorage().GetExtendedDataFor(bill);

            if (extendedBillData == null || !extendedBillData.CountAway)
            {
                return;
            }


            // Look for matching items in colonists and animals away from base
            foreach (var pawn in Find.WorldPawns.AllPawnsAlive)
            {
                if (pawn.GetOriginMap() != billMap)
                {
                    // OriginMap is only set on our pawns who are away from base
                    continue;
                }

                if (pawn.apparel != null)
                {
                    __result += CountMatchingThingsIn(pawn.apparel.WornApparel.Cast <Thing>(), __instance, bill, productThingDef);
                }

                if (pawn.equipment != null)
                {
                    __result += CountMatchingThingsIn(pawn.equipment.AllEquipmentListForReading.Cast <Thing>(), __instance, bill, productThingDef);
                }

                if (pawn.inventory != null)
                {
                    __result += CountMatchingThingsIn(pawn.inventory.innerContainer, __instance, bill, productThingDef);
                }

                if (pawn.carryTracker != null)
                {
                    __result += CountMatchingThingsIn(pawn.carryTracker.innerContainer, __instance, bill, productThingDef);
                }
            }
        }
Пример #7
0
        static bool Prefix(ref Bill_Production bill, ref int __result)
        {
            if (!ExtendedBillDataStorage.CanOutputBeFiltered(bill))
            {
                return(true);
            }

            var extendedBillData = Main.Instance.GetExtendedBillDataStorage().GetExtendedDataFor(bill);

            if (extendedBillData == null)
            {
                return(true);
            }

            var productThingDef  = bill.recipe.products.First().thingDef;
            var isThingAResource = productThingDef.CountAsResource;

            if (isThingAResource && !extendedBillData.UsesCountingStockpile())
            {
                return(true);
            }

            var statFilterWrapper = new StatFilterWrapper(extendedBillData);

            if (!statFilterWrapper.IsAnyFilteringNeeded(productThingDef))
            {
                return(true);
            }

            SpecialThingFilterWorker_NonDeadmansApparel nonDeadmansApparelFilter = null;

            if (!extendedBillData.AllowDeadmansApparel && productThingDef.IsApparel)
            {
                // We want to filter out corpse worn apparel
                nonDeadmansApparelFilter = new SpecialThingFilterWorker_NonDeadmansApparel();
                if (!nonDeadmansApparelFilter.CanEverMatch(productThingDef))
                {
                    // Not apparel, don't bother checking
                    nonDeadmansApparelFilter = null;
                }
            }


            __result = 0;
            if (productThingDef.Minifiable)
            {
                var minifiedThings = bill.Map.listerThings.ThingsInGroup(ThingRequestGroup.MinifiedThing);
                foreach (var thing in minifiedThings)
                {
                    var minifiedThing = (MinifiedThing)thing;
                    var innerThing    = minifiedThing.InnerThing;
                    if (innerThing.def == productThingDef &&
                        statFilterWrapper.DoesThingOnMapMatchFilter(bill.ingredientFilter, innerThing) &&
                        statFilterWrapper.DoesThingOnMapMatchFilter(bill.ingredientFilter, minifiedThing))
                    {
                        __result++;
                    }
                }

                return(false);
            }

            var thingList = bill.Map.listerThings.ThingsOfDef(productThingDef).ToList();

            foreach (var thing in thingList)
            {
                if (!statFilterWrapper.DoesThingOnMapMatchFilter(bill.ingredientFilter, thing))
                {
                    continue;
                }

                if (nonDeadmansApparelFilter != null && !nonDeadmansApparelFilter.Matches(thing))
                {
                    continue;
                }

                __result += thing.stackCount;
            }

            if (!statFilterWrapper.ShouldCheckWornClothes(productThingDef))
            {
                return(false);
            }

            foreach (var colonist in Find.VisibleMap.mapPawns.FreeColonists)
            {
                foreach (var apparel in colonist.apparel.WornApparel)
                {
                    if (apparel.def != productThingDef)
                    {
                        continue;
                    }

                    if (statFilterWrapper.DoesThingMatchFilter(bill.ingredientFilter, apparel))
                    {
                        __result++;
                    }
                }
            }

            return(false);
        }