use crate::battle::{Battle, BattleRules};
use crate::entity::{Entities, Entity, EntityId};
use crate::error::{WeaselError, WeaselResult};
use crate::event::{Event, EventKind, EventProcessor, EventQueue, EventTrigger};
use crate::metric::WriteMetrics;
use crate::round::Rounds;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Debug, Formatter, Result};
pub struct Space<R: BattleRules> {
model: SpaceModel<R>,
rules: R::SR,
}
impl<R: BattleRules> Space<R> {
pub(crate) fn new(seed: Option<SpaceSeed<R>>, rules: R::SR) -> Self {
Self {
model: rules.generate_model(&seed),
rules,
}
}
pub(crate) fn check_move(
&self,
claim: PositionClaim<R>,
position: &Position<R>,
) -> WeaselResult<(), R> {
self.rules.check_move(&self.model, claim, position)
}
pub(crate) fn move_entity(
&mut self,
claim: PositionClaim<R>,
position: Option<&Position<R>>,
metrics: &mut WriteMetrics<R>,
) {
self.rules
.move_entity(&mut self.model, claim, position, metrics);
}
pub fn model(&self) -> &SpaceModel<R> {
&self.model
}
pub fn model_mut(&mut self) -> &mut SpaceModel<R> {
&mut self.model
}
pub fn rules(&self) -> &R::SR {
&self.rules
}
pub fn rules_mut(&mut self) -> &mut R::SR {
&mut self.rules
}
}
pub trait SpaceRules<R: BattleRules> {
#[cfg(not(feature = "serialization"))]
type Position: Eq + Clone + Debug + Send;
#[cfg(feature = "serialization")]
type Position: Eq + Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
#[cfg(not(feature = "serialization"))]
type SpaceSeed: Clone + Debug + Send;
#[cfg(feature = "serialization")]
type SpaceSeed: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
#[cfg(not(feature = "serialization"))]
type SpaceAlteration: Clone + Debug + Send;
#[cfg(feature = "serialization")]
type SpaceAlteration: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
type SpaceModel;
fn generate_model(&self, seed: &Option<Self::SpaceSeed>) -> Self::SpaceModel;
fn check_move(
&self,
_model: &Self::SpaceModel,
_claim: PositionClaim<R>,
_position: &Self::Position,
) -> WeaselResult<(), R> {
Ok(())
}
fn move_entity(
&self,
_model: &mut Self::SpaceModel,
_claim: PositionClaim<R>,
_position: Option<&Self::Position>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn translate_entity(
&self,
_model: &Self::SpaceModel,
_new_model: &mut Self::SpaceModel,
_entity: &mut dyn Entity<R>,
_event_queue: &mut Option<EventQueue<R>>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn alter_space(
&self,
_entities: &Entities<R>,
_rounds: &Rounds<R>,
_model: &mut Self::SpaceModel,
_alteration: &Self::SpaceAlteration,
_event_queue: &mut Option<EventQueue<R>>,
_metrics: &mut WriteMetrics<R>,
) {
}
}
pub type Position<R> = <<R as BattleRules>::SR as SpaceRules<R>>::Position;
pub type SpaceSeed<R> = <<R as BattleRules>::SR as SpaceRules<R>>::SpaceSeed;
pub type SpaceModel<R> = <<R as BattleRules>::SR as SpaceRules<R>>::SpaceModel;
pub type SpaceAlteration<R> = <<R as BattleRules>::SR as SpaceRules<R>>::SpaceAlteration;
pub enum PositionClaim<'a, R: BattleRules> {
Spawn(&'a EntityId<R>),
Movement(&'a dyn Entity<R>),
}
impl<R: BattleRules> PositionClaim<'_, R> {
pub fn entity_id(&self) -> &EntityId<R> {
match self {
Self::Spawn(id) => id,
Self::Movement(entity) => entity.entity_id(),
}
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct MoveEntity<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 = "Position<R>: Serialize",
deserialize = "Position<R>: Deserialize<'de>"
))
)]
position: Position<R>,
}
impl<R: BattleRules> MoveEntity<R> {
pub fn trigger<'a, P: EventProcessor<R>>(
processor: &'a mut P,
id: EntityId<R>,
position: Position<R>,
) -> MoveEntityTrigger<'a, R, P> {
MoveEntityTrigger {
processor,
id,
position,
}
}
pub fn id(&self) -> &EntityId<R> {
&self.id
}
pub fn position(&self) -> &Position<R> {
&self.position
}
}
impl<R: BattleRules> Debug for MoveEntity<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"MoveEntity {{ creature_id: {:?}, position: {:?} }}",
self.id, self.position
)
}
}
impl<R: BattleRules> Clone for MoveEntity<R> {
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
position: self.position.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for MoveEntity<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
let entity = battle
.entities()
.entity(&self.id)
.ok_or_else(|| WeaselError::EntityNotFound(self.id.clone()))?;
battle
.space()
.check_move(PositionClaim::Movement(entity), &self.position)
.map_err(|err| {
WeaselError::PositionError(
Some(entity.position().clone()),
self.position.clone(),
Box::new(err),
)
})
}
fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
let entity = battle
.state
.entities
.entity_mut(&self.id)
.unwrap_or_else(|| panic!("constraint violated: entity {:?} not found", self.id));
battle.state.space.move_entity(
PositionClaim::Movement(entity),
Some(&self.position),
&mut battle.metrics.write_handle(),
);
entity.set_position(self.position.clone());
}
fn kind(&self) -> EventKind {
EventKind::MoveEntity
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct MoveEntityTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
id: EntityId<R>,
position: Position<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for MoveEntityTrigger<'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(MoveEntity {
id: self.id.clone(),
position: self.position.clone(),
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct ResetSpace<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "Option<SpaceSeed<R>>: Serialize",
deserialize = "Option<SpaceSeed<R>>: Deserialize<'de>"
))
)]
seed: Option<SpaceSeed<R>>,
}
impl<R: BattleRules> ResetSpace<R> {
pub fn trigger<P: EventProcessor<R>>(processor: &mut P) -> ResetSpaceTrigger<R, P> {
ResetSpaceTrigger {
processor,
seed: None,
}
}
pub fn seed(&self) -> &Option<SpaceSeed<R>> {
&self.seed
}
}
impl<R: BattleRules> Debug for ResetSpace<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "ResetSpace {{ seed: {:?} }}", self.seed)
}
}
impl<R: BattleRules> Clone for ResetSpace<R> {
fn clone(&self) -> Self {
Self {
seed: self.seed.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for ResetSpace<R> {
fn verify(&self, _battle: &Battle<R>) -> WeaselResult<(), R> {
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let rules = &battle.state.space.rules;
let mut new_model = rules.generate_model(&self.seed);
for entity in battle.state.entities.entities_mut() {
rules.translate_entity(
&battle.state.space.model,
&mut new_model,
entity,
event_queue,
&mut battle.metrics.write_handle(),
);
}
battle.state.space.model = new_model;
}
fn kind(&self) -> EventKind {
EventKind::ResetSpace
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct ResetSpaceTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
seed: Option<SpaceSeed<R>>,
}
impl<'a, R, P> ResetSpaceTrigger<'a, R, P>
where
R: BattleRules + 'static,
P: EventProcessor<R>,
{
pub fn seed(&'a mut self, seed: SpaceSeed<R>) -> &'a mut Self {
self.seed = Some(seed);
self
}
}
impl<'a, R, P> EventTrigger<'a, R, P> for ResetSpaceTrigger<'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(ResetSpace {
seed: self.seed.clone(),
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct AlterSpace<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = " SpaceAlteration<R>: Serialize",
deserialize = " SpaceAlteration<R>: Deserialize<'de>"
))
)]
alteration: SpaceAlteration<R>,
}
impl<R: BattleRules> AlterSpace<R> {
pub fn trigger<P: EventProcessor<R>>(
processor: &mut P,
alteration: SpaceAlteration<R>,
) -> AlterSpaceTrigger<R, P> {
AlterSpaceTrigger {
processor,
alteration,
}
}
pub fn alteration(&self) -> &SpaceAlteration<R> {
&self.alteration
}
}
impl<R: BattleRules> Debug for AlterSpace<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "AlterSpace {{ alteration: {:?} }}", self.alteration)
}
}
impl<R: BattleRules> Clone for AlterSpace<R> {
fn clone(&self) -> Self {
Self {
alteration: self.alteration.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for AlterSpace<R> {
fn verify(&self, _battle: &Battle<R>) -> WeaselResult<(), R> {
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let rules = &battle.state.space.rules;
rules.alter_space(
&battle.state.entities,
&battle.state.rounds,
&mut battle.state.space.model,
&self.alteration,
event_queue,
&mut battle.metrics.write_handle(),
);
}
fn kind(&self) -> EventKind {
EventKind::AlterSpace
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct AlterSpaceTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
alteration: SpaceAlteration<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for AlterSpaceTrigger<'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(AlterSpace {
alteration: self.alteration.clone(),
})
}
}