use enumset::EnumSetType;
use Reaction::*;
#[repr(u8)]
#[derive(EnumSetType, Debug)]
pub enum Reaction {
BLOOM,
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
}
use crate::element::Element::{self, *};
use crate::element::ElementSet;
use crate::element::{elem_set, ElementalAura};
macro_rules! test {
($fst:expr, $snd:expr; $value:path, $($rest:path),* $(,)*) => {
if $value.test_reaction($fst, $snd) { return Some($value) };
$(if $rest.test_reaction($fst, $snd) { return Some($value) });*
}
}
macro_rules! test_detail {
($fst:expr, $snd:expr; $value:path, $($rest:path),* $(,)*) => {
if $value.test_reaction($fst, $snd) { return Some(ReactionDetail::new($value, $fst, $snd)) };
$(if $rest.test_reaction($fst, $snd) { return Some(ReactionDetail::new($value, $fst, $snd)) });*
}
}
impl Reaction {
pub const fn reaction_elems(self) -> (ElementSet, ElementSet) {
use elem_set as S;
match self {
BLOOM => (S!(DENDRO), S!(HYDRO)),
BURNING => (S!(DENDRO), S!(PYRO)),
CRYSTALLIZE => (S!(PYRO, HYDRO, CRYO, ELECTRO), S!(GEO)),
ELECTROCHARGED => (S!(HYDRO), S!(ELECTRO)),
FROZEN => (S!(HYDRO), S!(CRYO)),
MELT => (S!(PYRO), S!(CRYO)),
OVERLOADED => (S!(PYRO), S!(ELECTRO)),
QUICKEN => (S!(DENDRO), S!(ELECTRO)),
SUPERCONDUCT => (S!(CRYO), S!(ELECTRO)),
SWIRL => (S!(PYRO, HYDRO, CRYO, ELECTRO), S!(ANEMO)),
VAPORIZE => (S!(HYDRO), S!(PYRO)),
}
}
pub const fn damage_boost(self) -> usize {
match self {
BLOOM => 1,
BURNING => 1,
CRYSTALLIZE => 1,
ELECTROCHARGED => 1,
FROZEN => 1,
MELT => 2,
OVERLOADED => 2,
QUICKEN => 1,
SUPERCONDUCT => 1,
SWIRL => 0,
VAPORIZE => 2,
}
}
fn test_reaction(self, fst: Element, snd: Element) -> bool {
let (x, y) = self.reaction_elems();
x.contains(fst) && y.contains(snd) || y.contains(fst) && x.contains(snd)
}
pub fn consult_reaction(fst: Element, snd: Element) -> Option<Reaction> {
test!(fst, snd;
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
);
None
}
pub fn consult_reaction_detail(fst: Element, snd: Element) -> Option<ReactionDetail> {
test_detail!(fst, snd;
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
);
None
}
pub fn consult_reaction_with_aura(aura: ElementalAura, snd: Element) -> Option<ReactionDetail> {
aura.consult_reaction(snd)
}
}
pub struct ReactionDetail {
reaction: Reaction,
fst: Element,
snd: Element,
}
impl ReactionDetail {
pub const fn new(reaction: Reaction, fst: Element, snd: Element) -> Self {
Self { reaction, fst, snd }
}
pub fn elem_reaction(self, elem: Element) -> bool {
self.fst == elem || self.snd == elem
}
}