use crate::ability::{AbilitiesAlteration, AbilitiesSeed, Ability, AbilityId, Activation};
use crate::battle::{Battle, BattleRules, BattleState};
use crate::character::Character;
use crate::entity::{Entities, EntityId};
use crate::entropy::Entropy;
use crate::error::{WeaselError, WeaselResult};
use crate::event::{Event, EventKind, EventProcessor, EventQueue, EventTrigger};
use crate::metric::WriteMetrics;
use crate::team::TeamId;
use crate::util::Id;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Debug, Formatter, Result};
pub trait Actor<R: BattleRules>: Character<R> {
fn abilities<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Ability<R>> + 'a>;
fn abilities_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Ability<R>> + 'a>;
fn ability(&self, id: &AbilityId<R>) -> Option<&Ability<R>>;
fn ability_mut(&mut self, id: &AbilityId<R>) -> Option<&mut Ability<R>>;
fn add_ability(&mut self, ability: Ability<R>) -> Option<Ability<R>>;
fn remove_ability(&mut self, id: &AbilityId<R>) -> Option<Ability<R>>;
fn team_id(&self) -> &TeamId<R>;
}
pub trait ActorRules<R: BattleRules> {
type Ability: Id + 'static;
#[cfg(not(feature = "serialization"))]
type AbilitiesSeed: Clone + Debug + Send;
#[cfg(feature = "serialization")]
type AbilitiesSeed: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
#[cfg(not(feature = "serialization"))]
type Activation: Clone + Debug + Send;
#[cfg(feature = "serialization")]
type Activation: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
#[cfg(not(feature = "serialization"))]
type AbilitiesAlteration: Clone + Debug + Send;
#[cfg(feature = "serialization")]
type AbilitiesAlteration: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
fn generate_abilities(
&self,
_seed: &Option<Self::AbilitiesSeed>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) -> Box<dyn Iterator<Item = Self::Ability>> {
Box::new(std::iter::empty())
}
fn activable(&self, _state: &BattleState<R>, _action: Action<R>) -> WeaselResult<(), R> {
Ok(())
}
fn activate(
&self,
_state: &BattleState<R>,
_action: Action<R>,
_event_queue: &mut Option<EventQueue<R>>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn alter_abilities(
&self,
_actor: &mut dyn Actor<R>,
_alteration: &Self::AbilitiesAlteration,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn on_turn_start(
&self,
_state: &BattleState<R>,
_actor: &dyn Actor<R>,
_event_queue: &mut Option<EventQueue<R>>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn on_turn_end(
&self,
_state: &BattleState<R>,
_actor: &dyn Actor<R>,
_event_queue: &mut Option<EventQueue<R>>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
}
pub struct Action<'a, R: BattleRules> {
pub actor: &'a dyn Actor<R>,
pub ability: &'a Ability<R>,
pub activation: &'a Option<Activation<R>>,
}
impl<'a, R: BattleRules> Action<'a, R> {
pub fn new(
actor: &'a dyn Actor<R>,
ability: &'a Ability<R>,
activation: &'a Option<Activation<R>>,
) -> Self {
Self {
actor,
ability,
activation,
}
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct AlterAbilities<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "EntityId<R>: Serialize",
deserialize = "EntityId<R>: Deserialize<'de>"
))
)]
id: EntityId<R>,
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "AbilitiesAlteration<R>: Serialize",
deserialize = "AbilitiesAlteration<R>: Deserialize<'de>"
))
)]
alteration: AbilitiesAlteration<R>,
}
impl<R: BattleRules> AlterAbilities<R> {
pub fn trigger<'a, P: EventProcessor<R>>(
processor: &'a mut P,
id: EntityId<R>,
alteration: AbilitiesAlteration<R>,
) -> AlterAbilitiesTrigger<'a, R, P> {
AlterAbilitiesTrigger {
processor,
id,
alteration,
}
}
pub fn id(&self) -> &EntityId<R> {
&self.id
}
pub fn alteration(&self) -> &AbilitiesAlteration<R> {
&self.alteration
}
}
impl<R: BattleRules> Debug for AlterAbilities<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"AlterAbilities {{ id: {:?}, alteration: {:?} }}",
self.id, self.alteration
)
}
}
impl<R: BattleRules> Clone for AlterAbilities<R> {
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
alteration: self.alteration.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for AlterAbilities<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
verify_is_actor(battle.entities(), &self.id)
}
fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
let actor = battle
.state
.entities
.actor_mut(&self.id)
.unwrap_or_else(|| panic!("constraint violated: actor {:?} not found", self.id));
battle.rules.actor_rules().alter_abilities(
actor,
&self.alteration,
&mut battle.entropy,
&mut battle.metrics.write_handle(),
);
}
fn kind(&self) -> EventKind {
EventKind::AlterAbilities
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct AlterAbilitiesTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
id: EntityId<R>,
alteration: AbilitiesAlteration<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for AlterAbilitiesTrigger<'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(AlterAbilities {
id: self.id.clone(),
alteration: self.alteration.clone(),
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct RegenerateAbilities<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "EntityId<R>: Serialize",
deserialize = "EntityId<R>: Deserialize<'de>"
))
)]
id: EntityId<R>,
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "Option<AbilitiesSeed<R>>: Serialize",
deserialize = "Option<AbilitiesSeed<R>>: Deserialize<'de>"
))
)]
seed: Option<AbilitiesSeed<R>>,
}
impl<R: BattleRules> RegenerateAbilities<R> {
pub fn trigger<P: EventProcessor<R>>(
processor: &'_ mut P,
id: EntityId<R>,
) -> RegenerateAbilitiesTrigger<'_, R, P> {
RegenerateAbilitiesTrigger {
processor,
id,
seed: None,
}
}
pub fn id(&self) -> &EntityId<R> {
&self.id
}
pub fn seed(&self) -> &Option<AbilitiesSeed<R>> {
&self.seed
}
}
impl<R: BattleRules> Debug for RegenerateAbilities<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"RegenerateAbilities {{ id: {:?}, seed: {:?} }}",
self.id, self.seed
)
}
}
impl<R: BattleRules> Clone for RegenerateAbilities<R> {
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
seed: self.seed.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for RegenerateAbilities<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
verify_is_actor(battle.entities(), &self.id)
}
fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
let actor = battle
.state
.entities
.actor_mut(&self.id)
.unwrap_or_else(|| panic!("constraint violated: actor {:?} not found", self.id));
let abilities: Vec<_> = battle
.rules
.actor_rules()
.generate_abilities(
&self.seed,
&mut battle.entropy,
&mut battle.metrics.write_handle(),
)
.collect();
let mut to_remove = Vec::new();
for ability in actor.abilities() {
if abilities.iter().find(|e| e.id() == ability.id()).is_none() {
to_remove.push(ability.id().clone());
}
}
for ability_id in to_remove {
actor.remove_ability(&ability_id);
}
for ability in abilities {
if actor.ability(ability.id()).is_none() {
actor.add_ability(ability);
}
}
}
fn kind(&self) -> EventKind {
EventKind::RegenerateAbilities
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct RegenerateAbilitiesTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
id: EntityId<R>,
seed: Option<AbilitiesSeed<R>>,
}
impl<'a, R, P> RegenerateAbilitiesTrigger<'a, R, P>
where
R: BattleRules + 'static,
P: EventProcessor<R>,
{
pub fn seed(&'a mut self, seed: AbilitiesSeed<R>) -> &'a mut Self {
self.seed = Some(seed);
self
}
}
impl<'a, R, P> EventTrigger<'a, R, P> for RegenerateAbilitiesTrigger<'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(RegenerateAbilities {
id: self.id.clone(),
seed: self.seed.clone(),
})
}
}
fn verify_is_actor<R>(entities: &Entities<R>, id: &EntityId<R>) -> WeaselResult<(), R>
where
R: BattleRules,
{
if !id.is_actor() {
return Err(WeaselError::NotAnActor(id.clone()));
}
entities
.entity(id)
.ok_or_else(|| WeaselError::EntityNotFound(id.clone()))?;
Ok(())
}