rustorio_engine/
recipe.rs

1//! Recipes define all item transformations in the game via input items, output items, and time.
2
3pub use rustorio_derive::{Recipe, RecipeEx, recipe_doc};
4
5use crate::{Sealed, tick::Tick};
6
7/// Basic recipe trait. A building's specific recipe trait can then be defined like
8/// ```rust
9/// trait AssemblerRecipe: rustorio_engine::recipe::Recipe + rustorio_engine::Sealed {}
10/// ```
11/// For example, one could define a recipe that takes three inputs and gives two outputs like:
12/// ```rust
13/// use rustorio_engine::{recipe::Recipe, resource_type};
14///
15/// resource_type!(Resource1);
16/// resource_type!(Resource2);
17/// resource_type!(Resource3);
18/// resource_type!(Resource4);
19/// resource_type!(Resource5);
20///
21/// #[derive(Recipe)]
22/// #[recipe_inputs(
23///     (10, Resource1),
24///     (5, Resource2),
25///     (1, Resource3),
26/// )]
27/// #[recipe_outputs(
28///     (1, Resource4),
29///     (100, Resource5),
30/// )]
31/// #[recipe_ticks(10)]
32/// pub struct ThreeToTwoRecipe;
33/// ```
34/// The recipe will then take 10 ticks per cycle, consuming 10 `Resource1`, 5 `Resource2`,
35/// and 1 `Resource3`, and produce 1 `Resource4` and 100 `Resource5`.
36pub trait Recipe {
37    /// Amount of ticks one cycle of the recipe takes to complete.
38    const TIME: u64;
39
40    /// Typically a tuple of multiple `RecipeTypes`, to define the inputs
41    /// for one cycle of the recipe.
42    type Inputs: std::fmt::Debug;
43
44    /// Typically a tuple of multiple `RecipeTypes`, to define the outputs
45    /// for one cycle of the recipe.
46    type Outputs: std::fmt::Debug;
47
48    /// Factory function to create a new `Self::Inputs` with zero resources.
49    fn new_inputs() -> Self::Inputs;
50
51    /// Factory function to create a new `Self::Outputs` with zero resources.
52    fn new_outputs() -> Self::Outputs;
53
54    /// The type for `Self::InputAmountsType`, which is used to allow users to
55    /// access the input amount for each of the input resource types, per recipe cycle.
56    type InputAmountsType: std::fmt::Debug;
57
58    /// Amount for each of the input resource types, per recipe cycle.
59    const INPUT_AMOUNTS: Self::InputAmountsType;
60
61    /// The type for `Self::OuptutAmountsType`, which is used to allow users to
62    /// access the output amount for each of the output resource types, per recipe cycle.
63    type OutputAmountsType: std::fmt::Debug;
64
65    /// Amount for each of the output resource types, per recipe cycle.
66    const OUTPUT_AMOUNTS: Self::OutputAmountsType;
67}
68
69#[doc(hidden)]
70pub trait RecipeEx: Recipe {
71    /// A type guaranteed to contain exactly the input resources for one recipe cycle.
72    /// Used in handcrafting.
73    type InputBundle: std::fmt::Debug;
74    /// A type guaranteed to contain exactly the output resources for one recipe cycle.
75    /// Used in handcrafting.
76    type OutputBundle: std::fmt::Debug;
77
78    /// Factory function to create a new `Self::InputBundle`.
79    fn new_output_bundle() -> Self::OutputBundle;
80
81    /// Iterator helper over `Self::Inputs`.
82    fn iter_inputs(items: &mut Self::Inputs)
83    -> impl Iterator<Item = (&'static str, u32, &mut u32)>;
84
85    /// Iterator helper over `Self::Outputs`.
86    fn iter_outputs(
87        items: &mut Self::Outputs,
88    ) -> impl Iterator<Item = (&'static str, u32, &mut u32)>;
89}
90
91/// A recipe that can be hand-crafted by the player.
92pub trait HandRecipe: std::fmt::Debug + Sealed + RecipeEx {
93    /// Crafts the recipe by consuming the input bundle and producing the output bundle.
94    /// Advances the provided `Tick` by the recipe's time.
95    fn craft(tick: &mut Tick, inputs: Self::InputBundle) -> Self::OutputBundle {
96        let _ = inputs;
97        tick.advance_by(Self::TIME);
98        Self::new_output_bundle()
99    }
100}