#pragma once #include #include #include #include "BuildingType.h" // One entry in [[recipe]].inputs — amount units of a named item consumed per // production cycle (REQ-MAT-CYCLE). struct RecipeIngredient { std::string item; int amount; }; // One entry in [[recipe]].outputs. For reprocessing_plant recipes, probability // is populated and outputs are rolled with weighted pick at cycle start // (REQ-BLD-REPROCESSING, REQ-MAT-CYCLE). For other buildings, probability is // std::nullopt and all outputs are produced on every cycle. struct RecipeOutput { std::string item; int amount; std::optional probability; }; struct RecipeDef { std::string id; // Unique recipe id; used by UI for selection. BuildingType building; // Which BuildingType can run this recipe. std::vector inputs; std::vector outputs; double durationSeconds; // Optional id of the item whose icon represents this recipe in the recipe- // selection dialog (REQ-UI-RECIPE-ICON). When unset, the first output item is // used. A missing icon file for that item is not an error (REQ-UI-ITEM-ICON). std::optional icon; // Assembler only. When true, this recipe is available from game start // regardless of the implicit item graph — used for base recipes that no // schematic's materials reach (e.g. building blocks). See REQ-LOCK-IMPLICIT. // Otherwise an assembler recipe is either explicitly gated (granted by an // unlock group, REQ-LOCK-EXPLICIT) or implicitly gated via the item graph. bool unlockedAtStart = false; }; struct RecipesConfig { std::vector recipes; // Returns the definition for the given recipe id, or nullptr if the id has // no entry in recipes.toml. const RecipeDef* findRecipeDef(const std::string& id) const { for (const RecipeDef& recipe : recipes) { if (recipe.id == id) { return &recipe; } } return nullptr; } // Same, but additionally requires the recipe to belong to the given building // type — recipe ids are only unique per building type. const RecipeDef* findRecipeDef(const std::string& id, BuildingType building) const { for (const RecipeDef& recipe : recipes) { if (recipe.id == id && recipe.building == building) { return &recipe; } } return nullptr; } };