use alloc::{
borrow::ToOwned,
vec::Vec,
};
use anyhow::Result;
use battler_data::Id;
use hashbrown::HashMap;
use crate::{
battle::{
Context,
EffectContext,
},
effect::{
AppliedEffectHandle,
AppliedEffectLocation,
EffectHandle,
},
error::WrapOptionError,
};
pub struct LinkedEffectsManager {
effects: HashMap<u32, AppliedEffectHandle>,
}
impl LinkedEffectsManager {
pub fn new() -> Self {
Self {
effects: HashMap::default(),
}
}
fn get_linked_id(context: &mut Context, effect: &AppliedEffectHandle) -> Result<Option<u32>> {
let connector = match effect.effect_state_connector() {
Some(connector) => connector,
None => return Ok(None),
};
if !connector.exists(context)? {
return Ok(None);
}
if let Some(id) = connector.get_mut(context)?.linked_id() {
return Ok(Some(id));
}
let id = context.battle_mut().next_effect_linked_id();
connector.get_mut(context)?.set_linked_id(id);
context
.battle_mut()
.linked_effects_manager
.effects
.insert(id, effect.to_owned());
Ok(Some(id))
}
pub fn link(
context: &mut Context,
from: &AppliedEffectHandle,
to: &AppliedEffectHandle,
) -> Result<bool> {
let from_uuid = match Self::get_linked_id(context, from)? {
Some(uuid) => uuid,
None => return Ok(false),
};
let to_uuid = match Self::get_linked_id(context, to)? {
Some(uuid) => uuid,
None => return Ok(false),
};
from.effect_state_connector()
.wrap_expectation("expected applied effect to have effect state after getting link id")?
.get_mut(context)?
.add_link(to_uuid);
to.effect_state_connector()
.wrap_expectation("expected applied effect to have effect state after getting link id")?
.get_mut(context)?
.add_link(from_uuid);
Ok(true)
}
pub fn remove_by_id(
context: &mut EffectContext,
id: &Id,
location: AppliedEffectLocation,
) -> Result<()> {
let effect_handle = context.battle_mut().get_effect_handle_by_id(id)?.clone();
Self::remove(context, effect_handle, location)
}
pub fn remove(
context: &mut EffectContext,
effect: EffectHandle,
location: AppliedEffectLocation,
) -> Result<()> {
let effect = AppliedEffectHandle::new(effect, location);
let connector = match effect.effect_state_connector() {
Some(connector) => connector,
None => return Ok(()),
};
if !connector.exists(context.as_battle_context_mut())? {
return Ok(());
}
let linked_id = match connector
.get_mut(context.as_battle_context_mut())?
.linked_id()
{
Some(linked_id) => linked_id,
None => return Ok(()),
};
context
.battle_mut()
.linked_effects_manager
.effects
.remove(&linked_id);
let mut context = context.forward_effect_context(effect.effect_handle.clone())?;
for link in connector
.get_mut(context.as_battle_context_mut())?
.linked_to()
.cloned()
.collect::<Vec<_>>()
{
Self::remove_link(&mut context, link, linked_id)?;
}
Ok(())
}
fn remove_link(context: &mut EffectContext, link: u32, remove: u32) -> Result<()> {
let linked_effect = match context.battle().linked_effects_manager.effects.get(&link) {
Some(effect) => effect.clone(),
None => return Ok(()),
};
let connector = match linked_effect.effect_state_connector() {
Some(connector) => connector,
None => return Ok(()),
};
if !connector.exists(context.as_battle_context_mut())? {
return Ok(());
}
let effect_state = connector.get_mut(context.as_battle_context_mut())?;
effect_state.remove_link(remove);
linked_effect.end(context)?;
Ok(())
}
}