use crate::actor::{Action, ActorRules};
use crate::battle::{Battle, BattleRules};
use crate::entity::EntityId;
use crate::error::{WeaselError, WeaselResult};
use crate::event::{Event, EventKind, EventProcessor, EventQueue, EventRights, EventTrigger};
use crate::util::Id;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::any::Any;
pub type Ability<R> = <<R as BattleRules>::AR as ActorRules<R>>::Ability;
pub type AbilityId<R> = <Ability<R> as Id>::Id;
pub type AbilitiesSeed<R> = <<R as BattleRules>::AR as ActorRules<R>>::AbilitiesSeed;
pub type Activation<R> = <<R as BattleRules>::AR as ActorRules<R>>::Activation;
pub type AbilitiesAlteration<R> = <<R as BattleRules>::AR as ActorRules<R>>::AbilitiesAlteration;
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct ActivateAbility<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "EntityId<R>: Serialize",
deserialize = "EntityId<R>: Deserialize<'de>"
))
)]
entity_id: EntityId<R>,
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "AbilityId<R>: Serialize",
deserialize = "AbilityId<R>: Deserialize<'de>"
))
)]
ability_id: AbilityId<R>,
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "Option<Activation<R>>: Serialize",
deserialize = "Option<Activation<R>>: Deserialize<'de>"
))
)]
activation: Option<Activation<R>>,
}
impl<R: BattleRules> ActivateAbility<R> {
pub fn trigger<P: EventProcessor<R>>(
processor: &mut P,
entity_id: EntityId<R>,
ability_id: AbilityId<R>,
) -> ActivateAbilityTrigger<R, P> {
ActivateAbilityTrigger {
processor,
entity_id,
ability_id,
activation: None,
}
}
pub fn entity_id(&self) -> &EntityId<R> {
&self.entity_id
}
pub fn ability_id(&self) -> &AbilityId<R> {
&self.ability_id
}
pub fn activation(&self) -> &Option<Activation<R>> {
&self.activation
}
}
impl<R: BattleRules> std::fmt::Debug for ActivateAbility<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"ActivateAbility {{ entity_id: {:?}, ability_id: {:?}, activation: {:?} }}",
self.entity_id, self.ability_id, self.activation
)
}
}
impl<R: BattleRules> Clone for ActivateAbility<R> {
fn clone(&self) -> Self {
ActivateAbility {
entity_id: self.entity_id.clone(),
ability_id: self.ability_id.clone(),
activation: self.activation.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for ActivateAbility<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if !self.entity_id.is_actor() {
return Err(WeaselError::NotAnActor(self.entity_id.clone()));
}
if let Some(actor) = battle.entities().actor(&self.entity_id) {
if !battle.state.rounds.is_acting(&self.entity_id) {
return Err(WeaselError::ActorNotReady(self.entity_id.clone()));
}
if let Some(ability) = actor.ability(&self.ability_id) {
battle
.rules
.actor_rules()
.activable(&battle.state, Action::new(actor, ability, &self.activation))
.map_err(|err| {
WeaselError::AbilityNotActivable(
self.entity_id.clone(),
self.ability_id.clone(),
Box::new(err),
)
})
} else {
Err(WeaselError::AbilityNotKnown(
self.entity_id.clone(),
self.ability_id.clone(),
))
}
} else {
Err(WeaselError::EntityNotFound(self.entity_id.clone()))
}
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let actor = battle
.state
.entities
.actor(&self.entity_id)
.unwrap_or_else(|| {
panic!("constraint violated: entity {:?} not found", self.entity_id)
});
let ability = actor.ability(&self.ability_id).unwrap_or_else(|| {
panic!(
"constraint violated: ability {:?} not found in actor {:?}",
self.ability_id, self.entity_id
)
});
battle.rules.actor_rules().activate(
&battle.state,
Action::new(actor, ability, &self.activation),
event_queue,
&mut battle.entropy,
&mut battle.metrics.write_handle(),
);
}
fn kind(&self) -> EventKind {
EventKind::ActivateAbility
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
fn rights<'a>(&'a self, battle: &'a Battle<R>) -> EventRights<'a, R> {
let actor = battle
.state
.entities
.actor(&self.entity_id)
.unwrap_or_else(|| {
panic!("constraint violated: entity {:?} not found", self.entity_id)
});
EventRights::Team(actor.team_id())
}
}
pub struct ActivateAbilityTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
entity_id: EntityId<R>,
ability_id: AbilityId<R>,
activation: Option<Activation<R>>,
}
impl<'a, R, P> ActivateAbilityTrigger<'a, R, P>
where
R: BattleRules + 'static,
P: EventProcessor<R>,
{
pub fn activation(&'a mut self, activation: Activation<R>) -> &'a mut Self {
self.activation = Some(activation);
self
}
}
impl<'a, R, P> EventTrigger<'a, R, P> for ActivateAbilityTrigger<'a, R, P>
where
R: BattleRules + 'static,
P: EventProcessor<R>,
{
fn processor(&'a mut self) -> &'a mut P {
self.processor
}
fn event(&self) -> Box<dyn Event<R> + Send> {
Box::new(ActivateAbility {
entity_id: self.entity_id.clone(),
ability_id: self.ability_id.clone(),
activation: self.activation.clone(),
})
}
}