MCPcopy Index your code
hub / github.com/Leafwing-Studios/leafwing_abilities

github.com/Leafwing-Studios/leafwing_abilities @v0.12

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.12 ↗ · + Follow
183 symbols 352 edges 13 files 26 documented · 14%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

About

A fully-featured set of tools for managing abilities in Bevy. This crate is meant to be used with Leafwing Input Manager, which converts inputs into actions.

Some of those actions will be abilities! Abilities are intended for gameplay use, and follow complex but relatively standardized logic about how they might be used.

use bevy::prelude::*;
use bevy::reflect::Reflect;
use leafwing_abilities::prelude::*;
use leafwing_abilities::premade_pools::mana::{ManaPool, Mana};
use leafwing_abilities::premade_pools::life::{LifePool, Life};
use leafwing_input_manager::prelude::*;

// We're modelling https://leagueoflegends.fandom.com/wiki/Zyra/LoL
// to show off this crate's features!
#[derive(Actionlike, Abilitylike, Debug, Clone, Copy, Hash, PartialEq, Eq, Reflect)]
pub enum ZyraAbility {
    GardenOfThorns,
    DeadlySpines,
    RampantGrowth,
    GraspingRoots,
    Stranglethorns,
}

impl ZyraAbility {
    /// You could use the `strum` crate to derive this automatically!
    fn variants() -> Vec<ZyraAbility> {
        use ZyraAbility::*;
        vec![GardenOfThorns, DeadlySpines, RampantGrowth, GraspingRoots, Stranglethorns]
    }

    fn input_map() -> InputMap<ZyraAbility> {
        use ZyraAbility::*;

        // We can use this `new` idiom, which accepts an iterator of pairs
        InputMap::new([
            (DeadlySpines, KeyCode::KeyQ),
            (RampantGrowth, KeyCode::KeyW),
            (GraspingRoots, KeyCode::KeyE),
            (Stranglethorns, KeyCode::KeyR),
        ])
    }

    // This match pattern is super useful to be sure you've defined an attribute for every variant
    fn cooldown(&self) -> Cooldown {
        use ZyraAbility::*;

        let seconds: f32 = match *self {
            GardenOfThorns => 13.0,
            DeadlySpines => 7.0,
            RampantGrowth => 18.0,
            GraspingRoots => 12.0,
            Stranglethorns => 110.0,
        };

        Cooldown::from_secs(seconds)
    }

    fn cooldowns() -> CooldownState<ZyraAbility> {
        let mut cooldowns = CooldownState::default();

        // Now, we can loop over all the variants to populate our struct
        for ability in ZyraAbility::variants() {
            cooldowns.set(ability, ability.cooldown());
        }

        cooldowns
    }

    fn charges() -> ChargeState<ZyraAbility> {
        // The builder API can be very convenient when you only need to set a couple of values
        ChargeState::default()
            .set(ZyraAbility::RampantGrowth, Charges::replenish_one(2))
            .build()
    }

    fn mana_costs() -> AbilityCosts<ZyraAbility, ManaPool> {
        use ZyraAbility::*;
        AbilityCosts::new([
            (DeadlySpines, Mana(70.)),
            (GraspingRoots, Mana(70.)),
            (Stranglethorns, Mana(100.)),
        ])
    }
}

/// Marker component for this champion
#[derive(Component)]
struct Zyra;

#[derive(Bundle)]
struct ZyraBundle {
    champion: Zyra,
    life_pool: LifePool,
    input_manager_bundle: InputManagerBundle<ZyraAbility>,
    abilities_bundle: AbilitiesBundle<ZyraAbility>,
    mana_bundle: PoolBundle<ZyraAbility, ManaPool>,
}

impl Default for ZyraBundle {
    fn default() -> Self {
        ZyraBundle {
            champion: Zyra,
            // Max life, then regen
            life_pool: LifePool::new(Life(574.), Life(574.), (Life(5.5))),
            input_manager_bundle: InputManagerBundle::<ZyraAbility> {
                input_map: ZyraAbility::input_map(),
                ..default()
            },
            abilities_bundle: AbilitiesBundle::<ZyraAbility> {
                cooldowns: ZyraAbility::cooldowns(),
                charges: ZyraAbility::charges(),
            },
            mana_bundle: PoolBundle::<ZyraAbility, ManaPool> {
                pool: ManaPool::new(Mana(418.), Mana(418.), Mana(13.0)),
                ability_costs: ZyraAbility::mana_costs(),
            }
        }
    }
}

Features

  • track and automatically tick cooldowns
  • store multiple charges of abilities
  • Leafwing Studio's trademark #[deny(missing_docs)]

Planned:

  • resource management (health, mana, energy etc)
  • damage
  • cast times
  • range checking

Extension points exported contracts — how you extend this code

Pool (Interface)
A reservoir of a resource that can be used to pay for abilities, or keep track of character state. Each type that imple [3 …
src/pool.rs
Abilitylike (Interface)
Allows a type to be used as a gameplay action in an input-agnostic fashion Actions are modelled as "virtual buttons", c
src/lib.rs
RegeneratingPool (Interface)
A resource pool that regenerates (or decays) over time. Set the regeneration rate to a positive value to regenerate, or [2 …
src/pool.rs

Core symbols most depended-on inside this repo

set_current
called by 12
src/premade_pools.rs
trigger
called by 11
src/cooldown.rs
expend
called by 9
src/charges.rs
get
called by 7
src/pool.rs
replenish
called by 7
src/charges.rs
clone
called by 6
src/pool.rs
current
called by 5
src/ability_state.rs
tick
called by 5
src/cooldown.rs

Shape

Method 98
Function 55
Class 19
Enum 8
Interface 3

Languages

Rust100%

Modules by API surface

src/cooldown.rs30 symbols
src/charges.rs30 symbols
src/pool.rs27 symbols
src/lib.rs20 symbols
examples/cooldown.rs20 symbols
src/premade_pools.rs19 symbols
src/ability_state.rs16 symbols
tests/cooldowns.rs12 symbols
src/plugin.rs4 symbols
src/systems.rs2 symbols
tools/ci/src/main.rs1 symbols
macros/src/lib.rs1 symbols

For agents

$ claude mcp add leafwing_abilities \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact