use weasel::rules::{statistic::SimpleStatistic, status::SimpleStatus}; use weasel::status::{Application, AppliedStatus, Potency, Status, StatusDuration, StatusId}; use weasel::{ battle_rules, rules::empty::*, AlterStatistics, BattleRules, BattleState, Character, CharacterRules, Entropy, EventQueue, EventTrigger, FightRules, Id, LinkedQueue, Transmutation, WriteMetrics, }; pub(crate) const HEALTH: u8 = 0; /// Id of the status that increases HEALTH. pub(crate) const VIGOR: u8 = 0; /// Id of the status that deals damage over time. pub(crate) const DOT: u8 = 1; // Declare the battle rules with the help of a macro. battle_rules! { EmptyTeamRules, // Use our own character rules to define how statuses are created. CustomCharacterRules, EmptyActorRules, // Use our own fight rules to specify the status' side effects. CustomFightRules, EmptyUserRules, EmptySpaceRules, EmptyRoundsRules, EmptyEntropyRules } // Define our custom character rules. #[derive(Default)] pub struct CustomCharacterRules {} impl CharacterRules for CustomCharacterRules { // Just use an integer as creature id. type CreatureId = u8; // Same for objects. type ObjectId = u8; // Use statistics with integers as both id and value. type Statistic = SimpleStatistic; // The seed will contain the value of HEALTH. type StatisticsSeed = i8; // We alter the HEALTH statistic in this example. // This represents the quantity to add to the current value. type StatisticsAlteration = i8; // Simple statuses with integers as both id and value. type Status = SimpleStatus; // We don't alter statuses in this example. type StatusesAlteration = (); fn generate_statistics( &self, seed: &Option, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) -> Box> { // Generate a single statistic: HEALTH. let min = 0; let max = 100; let value = seed.unwrap(); let v = vec![SimpleStatistic::with_value(HEALTH, min, max, value)]; Box::new(v.into_iter()) } fn alter_statistics( &self, character: &mut dyn Character, alteration: &Self::StatisticsAlteration, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) -> Option { // Apply the change to the character's health. let current = character.statistic(&HEALTH).unwrap().value(); character .statistic_mut(&HEALTH) .unwrap() .set_value(current + alteration); None } fn generate_status( &self, _character: &dyn Character, status_id: &StatusId, potency: &Option>, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) -> Option> { // We expect to always have a valid potency. let potency = potency.unwrap(); let effect = potency.0; let duration = potency.1; // Return a new status in any case. If it already exists on the character, // the old one is replaced (anyway it doesn't happen in this example). Some(SimpleStatus::new(*status_id, effect, duration)) } } // Define our custom fight rules. #[derive(Default)] pub struct CustomFightRules {} impl FightRules for CustomFightRules { // We don't use impacts. type Impact = (); // Potency will tell how strong a status is and how long will it lasts. type Potency = (i8, Option); fn apply_status( &self, _state: &BattleState, character: &dyn Character, application: Application, event_queue: &mut Option>, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) { // Treat all applications in the same way. We won't have replacements in this example. // So we only need to get the new status definition. let status = match application { Application::New(new) => new, Application::Replacement(_, new) => new, }; // If the status is VIGOR buff the character's HEALTH. if *status.id() == VIGOR { AlterStatistics::trigger(event_queue, *character.entity_id(), status.effect()).fire(); } } fn update_status( &self, _state: &BattleState, character: &dyn Character, status: &AppliedStatus, linked_queue: &mut Option>, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) -> bool { // If the status is DOT deal some damage to the character. if *status.id() == DOT { AlterStatistics::trigger(linked_queue, *character.entity_id(), -status.effect()).fire(); } // Terminate the status if its duration expired. if let Some(max_duration) = status.max_duration() { status.duration() == max_duration } else { false } } fn delete_status( &self, _state: &BattleState, character: &dyn Character, status: &AppliedStatus, event_queue: &mut Option>, _entropy: &mut Entropy, _metrics: &mut WriteMetrics, ) { // If the status is VIGOR remove the buff. if *status.id() == VIGOR { AlterStatistics::trigger(event_queue, *character.entity_id(), -status.effect()).fire(); } } }