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}