Skip to content

Commit

Permalink
Add better workarounds for multiple resource pools (#62)
Browse files Browse the repository at this point in the history
* More methods on Abilitylike

* Add docs on handling null / multiple resource pools
  • Loading branch information
alice-i-cecile authored Sep 4, 2024
1 parent c119b1a commit a83bb0a
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 11 deletions.
25 changes: 14 additions & 11 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,32 @@
- removed `ToggleActions`: this functionality no longer makes sense with changes to how LWIM disables actions. Use run conditions directly on the new `AbilitySystem::TickCooldowns` system set
- the associated type `Pool::Quantity` no longer needs to be able to be multiplied and divided by f32s to ease working with integer-based resource pools
- in exchange, the `RegeneratingPool::regenerate` method no longer has a default implementation
- to better support working with multiple resource pools for a single `Abilitylike`:
- `ready_no_cost` and `trigger_no_cost` have been added to `Abilitylike`
- when working with multiple resource pools, you should pass in `NullPool` as the type argument for `AbilityState`

## Version 0.8

- now supports Bevy 0.14

## Version 0.7

### Dependencies
### Dependencies (0.7)

- now supports Bevy 0.13

## Version 0.6

### Dependencies
### Dependencies (0.6)

- now supports Bevy 0.12

### Documentation
### Documentation (0.6)

- fixed several typos (`@striezel`)
- improved the documentation for `Pool::replenish`

### Usability
### Usability (0.6)

- removed the required `new` method from the `Pool` trait: this method was overly restrictive, and prevented the construction of more complex pools with custom initialization parameters
- `LifePool::new` and `ManaPool::new` methods have been added to the premade pools: do similarly for your own `Pool` types
Expand All @@ -48,30 +51,30 @@

## Version 0.5

### Dependencies
### Dependencies (0.5)

- now supports Bevy 0.11

## Version 0.4

### Dependencies
### Dependencies (0.4)

- now supports Bevy 0.10

### Usability
### Usability (0.4)

- the premade `LifePool` and `ManaPool` types now implement the `Resource` trait.
- the premade `Life` and `Mana` types now implement `Mul<T> for f32`, allowing you to have commutative multiplication

## Version 0.3

### Dependencies
### Dependencies (0.3)

- now supports Bevy 0.9

## Version 0.2

### Enhancements
### Enhancements (0.2)

- You can now store and check resource pools (like life, mana or energy) with the `Pool` trait!
- All of the corresponding ability methods and `AbilityState` have been changed to account for this.
Expand All @@ -80,14 +83,14 @@
- For example, you can add `PoolBundle<Mana>` to your entity to track both the `ManaPool` and the `AbilityCosts<A, ManaPool>`.
- We've included a `LifePool` and `ManaPool` type to get you started; feel free to copy-and-paste to adapt them to your needs.

### Usability
### Usability (0.2)

- All methods and functions that returned a bool now return a `Result<(), CannotUseAbility>` which explains why an action failed.
- the `trigger_action` and `action_ready` functions were renamed to `trigger_ability` and `ability_ready`

## Version 0.1

### Enhancements
### Enhancements (0.1)

- You can now store `Cooldowns` and `ActionCharges` on a per-action basis.
- These new components are now included in the `InputManagerBundle`.
Expand Down
18 changes: 18 additions & 0 deletions src/ability_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ use leafwing_input_manager::action_state::ActionState;
/// Once you have a [`AbilityStateItem`] by calling `.iter_mut()` or `.single_mut` on your query
/// (or a [`AbilityStateReadOnlyItem`] by calling `.iter()` or `.single`),
/// you can use the methods defined there to perform common tasks quickly and reliably.
///
/// ## No resource pool
///
/// When working with abilities that don't require a resource pool, simply pass in [`NullPool`] as the pool type.
/// The absence of a pool will be handled gracefully by the methods in [`Abilitylike`].
///
/// ## Multiple resource pools
///
/// When working with abilities that require multiple resource pools, there are two options:
///
/// 1. Create a new [`Pool`] type that contains all of the possible resource pools.
/// 2. Pass in [`NullPool`] and handle the resource costs manually in your ability implementations.
///
/// The first solution is reliable and type-safe, but limits you to a fixed collection of resource pools
/// and can be wasteful and confusing, as the majority of abilities or characters will only use a single resource pool.
///
/// The second solution is more flexible, but requires you to handle the resource costs manually.
/// Make sure to check if the resource cost can be paid before calling [`Abilitylike::trigger`]!
#[derive(QueryData)]
#[query_data(mutable)]
pub struct AbilityState<A: Abilitylike, P: Pool + Component = NullPool> {
Expand Down
33 changes: 33 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,39 @@ pub trait Abilitylike: Actionlike {
.copied(),
)
}

/// Triggers this ability, depleting a charge if available.
///
/// Returns `true` if the ability could be used, and `false` if it could not be.
/// Abilities can only be used if they are ready.
///
/// Calls [`Abilitylike::trigger`], passing in [`None`] for both the pools or costs.
/// This is useful when you don't have any pools or costs to check,
/// or when multiple distinct pools may be needed.
fn trigger_no_costs(
&self,
charges: &mut ChargeState<Self>,
cooldowns: &mut CooldownState<Self>,
) -> Result<(), CannotUseAbility> {
self.trigger::<NullPool>(charges, cooldowns, None, None)
}

/// Is this ability ready?
///
/// If this ability has charges, at least one charge must be available.
/// If this ability has a cooldown but no charges, the cooldown must be ready.
/// Otherwise, returns [`Ok(())`].
///
/// Calls [`Abilitylike::ready`], passing in [`None`] for both the pools or costs.
/// This is useful when you don't have any pools or costs to check,
/// or when multiple distinct pools may be needed.
fn ready_no_costs(
&self,
charges: &ChargeState<Self>,
cooldowns: &CooldownState<Self>,
) -> Result<(), CannotUseAbility> {
self.ready::<NullPool>(charges, cooldowns, None, None)
}
}

/// An [`Error`](std::error::Error) type that explains why an ability could not be used.
Expand Down

0 comments on commit a83bb0a

Please sign in to comment.