1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! Game stats that reset every frame, inspired by immediate mode GUI.
//!
//! This makes it easy to implement temporary buffs/debuffs, and effects that change over time.
//! Using a [derive macro](macro@StatContainer), stat resets are propagated to any stat fields,
//! making it easy to compose stats into more complex objects.
//!
//! ```rust no_run
//! # use immediate_stats::*;
//! #[derive(StatContainer)]
//! struct Speed(Stat);
//!
//! fn main() {
//! let mut speed = Speed(Stat::new(10)); // Set base speed to 10.
//!
//! loop {
//! speed.0 *= 2.0; // Applies a multiplier to the final result.
//! speed.0 += 5; // Adds a bonus to the final result.
//! // The order does not matter, bonuses are always applied before multipliers.
//! assert_eq!(speed.0.total(), 30); // (10 + 5) * 2 = 30
//!
//! speed.reset_modifiers(); // Reset speed back to 10.
//! }
//! }
//! ```
//!
//! ## Bevy
//!
//! There is build-in integration with the [Bevy Engine](https://bevyengine.org)
//! via the `bevy` feature flag.
//! This adds systems for resetting [`StatContainer`] components and resources.
//!
//! # use bevy_app::prelude::*;
//! # use bevy_ecs::prelude::*;
//! # use immediate_stats::*;
//! #[derive(StatContainer, Component, Resource, Default)]
//! struct Speed(Stat);
//!
//! fn main() {
//! App::new()
//! .add_plugins((
//! ImmediateStatsPlugin,
//! ResetComponentPlugin::<Speed>::new(),
//! ResetResourcePlugin::<Speed>::new(),
//! ))
//! .run();
//! }
//! ```
//!
//! ### Bevy Auto Plugin
//!
//! If you use [Bevy Auto Plugin](https://github.com/strikeforcezero/bevy_auto_plugin/), you can also use the `bevy_auto_plugin` feature flag.
//! This adds build hooks that automatically add the reset plugin.
//!
//! # use bevy_app::prelude::*;
//! # use bevy_ecs::prelude::*;
//! # use immediate_stats::*;
//! # use bevy_auto_plugin::prelude::{AutoPlugin, auto_plugin_build_hook, auto_resource};
//!
//! fn main() {
//! App::new().add_plugins((ImmediateStatsPlugin, MyPlugin)).run();
//! }
//!
//! #[derive(AutoPlugin)]
//! #[auto_plugin(impl_plugin_trait)]
//! struct MyPlugin;
//!
//! #[derive(StatContainer, Component)]
//! // Use hook to add the `ResetComponentPlugin` to `MyPlugin` automatically.
//! #[auto_plugin_build_hook(plugin = MyPlugin, hook = ResetComponentHook)]
//! struct Speed(Stat);
//! ```
//!
//! ### Version Compatibility
//! | Bevy | Immediate Stats |
//! |--------|-----------------|
//! | `0.18` | `0.4` |
//! | `0.17` | `0.3` |
//! | `0.16` | `0.1` - `0.2` |
/// Implements [`reset_modifiers`](StatContainer::reset_modifiers)
/// by propagating the call down to any stat fields.
/// ```rust
/// # use immediate_stats::*;
/// #[derive(StatContainer, Default, Debug, PartialEq)]
/// struct Health {
/// max: Stat, // `Health::reset_modifiers` calls will be passed onto `max`.
/// current: i32,
/// }
///
/// fn main() {
/// let mut health = Health {
/// max: Stat::new(10),
/// current: 10
/// };
///
/// health.max += 5;
/// health.reset_modifiers();
/// assert_eq!(health.max, Stat::new(10));
/// }
/// ```
/// # Configuration
/// By default, the macro will consider any field whose type contains the word "Stat"
/// to be a sub-stat.
/// You can use `#[stat]` to add other sub-stats and `#[stat_ignore]` to ignore one.
/// ```rust
/// # use immediate_stats::*;
/// # #[derive(StatContainer, Default, Debug, PartialEq)]
/// # struct Health {
/// # max: Stat,
/// # current: i32,
/// # }
/// #[derive(StatContainer)]
/// struct PartialReset {
/// #[stat]
/// custom: Health, // Will get reset.
/// #[stat_ignore]
/// ignored: Stat, // Will not get reset.
/// }
///
/// fn main () {
/// let mut partial = PartialReset {
/// custom: Health::default(),
/// ignored: Stat::default(),
/// };
///
/// partial.custom.max += 10;
/// partial.ignored += 10;
///
/// partial.reset_modifiers();
///
/// assert_eq!(partial.custom, Health::default());
/// assert_eq!(partial.ignored, Stat::default().with_bonus(10));
/// }
/// ```
pub use StatContainer;
pub use *;
pub use *;
pub use *;
// Used by derive macro.
pub use PreUpdate as __PreUpdate;
/// Types that contain stats that need to be reset.
///
/// Consider using the [derive macro](macro@StatContainer) before implementing manually.