use crate::actor::{Actor, ActorRules};
use crate::battle::{Battle, BattleRules, Checkpoint};
use crate::entity::{Entities, Entity, EntityId};
use crate::entropy::Entropy;
use crate::error::{WeaselError, WeaselResult};
use crate::event::{Event, EventKind, EventProcessor, EventQueue, EventRights, EventTrigger};
use crate::metric::WriteMetrics;
use crate::space::Space;
use crate::status::update_statuses;
use indexmap::IndexSet;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use std::marker::PhantomData;
pub type RoundsCount = u32;
pub type TurnsCount = u32;
pub struct Rounds<R: BattleRules> {
state: TurnStateType<R>,
model: RoundsModel<R>,
rules: R::RR,
rounds: RoundsCount,
turns: TurnsCount,
}
impl<R: BattleRules> Rounds<R> {
pub(crate) fn new(seed: Option<RoundsSeed<R>>, rules: R::RR) -> Self {
Self {
state: TurnState::Ready,
model: rules.generate_model(&seed),
rules,
rounds: 0,
turns: 0,
}
}
pub fn model(&self) -> &RoundsModel<R> {
&self.model
}
pub fn model_mut(&mut self) -> &mut RoundsModel<R> {
&mut self.model
}
pub fn is_acting(&self, entity_id: &EntityId<R>) -> bool {
self.state.has_actor(entity_id)
}
fn eligible(&self, actor: &dyn Actor<R>) -> bool {
self.rules.eligible(&self.model, actor)
}
pub fn state(&self) -> &TurnStateType<R> {
&self.state
}
pub(crate) fn set_state(&mut self, state: TurnStateType<R>) {
self.state = state;
}
pub fn rules(&self) -> &R::RR {
&self.rules
}
pub fn rules_mut(&mut self) -> &mut R::RR {
&mut self.rules
}
pub fn completed_rounds(&self) -> RoundsCount {
self.rounds
}
pub(crate) fn increase_completed_rounds(&mut self) {
self.rounds += 1;
}
pub fn completed_turns(&self) -> TurnsCount {
self.turns
}
pub(crate) fn increase_completed_turns(&mut self) {
self.turns += 1;
}
pub(crate) fn on_actor_added(
&mut self,
actor: &dyn Actor<R>,
entropy: &mut Entropy<R>,
metrics: &mut WriteMetrics<R>,
) {
self.rules
.on_actor_added(&mut self.model, actor, entropy, metrics);
}
pub(crate) fn on_actor_removed(
&mut self,
actor: &dyn Actor<R>,
entropy: &mut Entropy<R>,
metrics: &mut WriteMetrics<R>,
) {
self.rules
.on_actor_removed(&mut self.model, actor, entropy, metrics);
}
pub(crate) fn on_end(
&mut self,
entities: &Entities<R>,
space: &Space<R>,
actor: &dyn Actor<R>,
entropy: &mut Entropy<R>,
metrics: &mut WriteMetrics<R>,
) {
self.rules
.on_end(entities, space, &mut self.model, actor, entropy, metrics);
}
pub(crate) fn regenerate_model(&mut self, seed: &Option<RoundsSeed<R>>) {
self.model = self.rules.generate_model(seed)
}
}
pub type TurnStateType<R> = TurnState<EntityId<R>>;
#[derive(Debug, Clone, PartialEq)]
pub enum TurnState<EI>
where
EI: Debug + Hash + Eq,
{
Ready,
Started(IndexSet<EI>),
}
impl<EI> TurnState<EI>
where
EI: Debug + Hash + Eq,
{
pub fn has_actor(&self, entity_id: &EI) -> bool {
if let Self::Started(actors) = self {
actors.contains(entity_id)
} else {
false
}
}
}
pub trait RoundsRules<R: BattleRules> {
#[cfg(not(feature = "serialization"))]
type RoundsSeed: Debug + Clone + Send;
#[cfg(feature = "serialization")]
type RoundsSeed: Debug + Clone + Send + Serialize + for<'a> Deserialize<'a>;
type RoundsModel;
fn generate_model(&self, seed: &Option<Self::RoundsSeed>) -> Self::RoundsModel;
fn eligible(&self, _model: &Self::RoundsModel, _actor: &dyn Actor<R>) -> bool {
true
}
fn on_start(
&self,
_entities: &Entities<R>,
_space: &Space<R>,
_model: &mut Self::RoundsModel,
_actor: &dyn Actor<R>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn on_end(
&self,
_entities: &Entities<R>,
_space: &Space<R>,
_model: &mut Self::RoundsModel,
_actor: &dyn Actor<R>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn on_actor_added(
&self,
_model: &mut Self::RoundsModel,
_actor: &dyn Actor<R>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
fn on_actor_removed(
&self,
_model: &mut Self::RoundsModel,
_actor: &dyn Actor<R>,
_entropy: &mut Entropy<R>,
_metrics: &mut WriteMetrics<R>,
) {
}
}
pub type RoundsSeed<R> = <<R as BattleRules>::RR as RoundsRules<R>>::RoundsSeed;
pub type RoundsModel<R> = <<R as BattleRules>::RR as RoundsRules<R>>::RoundsModel;
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct StartTurn<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "Vec<EntityId<R>>: Serialize",
deserialize = "Vec<EntityId<R>>: Deserialize<'de>"
))
)]
ids: Vec<EntityId<R>>,
}
impl<R: BattleRules> StartTurn<R> {
pub fn trigger<P: EventProcessor<R>>(
processor: &mut P,
id: EntityId<R>,
) -> StartTurnTrigger<R, P> {
StartTurnTrigger {
processor,
ids: vec![id],
}
}
pub fn trigger_with_actors<P, I>(processor: &mut P, ids: I) -> StartTurnTrigger<R, P>
where
P: EventProcessor<R>,
I: IntoIterator<Item = EntityId<R>>,
{
StartTurnTrigger {
processor,
ids: ids.into_iter().collect(),
}
}
pub fn ids(&self) -> &Vec<EntityId<R>> {
&self.ids
}
}
impl<R: BattleRules> Debug for StartTurn<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "StartTurn {{ ids: {:?} }}", self.ids)
}
}
impl<R: BattleRules> Clone for StartTurn<R> {
fn clone(&self) -> Self {
Self {
ids: self.ids.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for StartTurn<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if let TurnState::Started(_) = battle.rounds().state() {
return Err(WeaselError::TurnInProgress);
}
for id in &self.ids {
if !id.is_actor() {
return Err(WeaselError::NotAnActor(id.clone()));
}
if let Some(actor) = battle.entities().actor(&id) {
if !battle.rounds().eligible(actor) {
return Err(WeaselError::ActorNotEligible(id.clone()));
}
} else {
return Err(WeaselError::EntityNotFound(id.clone()));
}
}
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let actors_ids: IndexSet<_> = self.ids.iter().cloned().collect();
battle
.state
.rounds
.set_state(TurnState::Started(actors_ids.clone()));
for id in &actors_ids {
let metrics = &mut battle.metrics.write_handle();
let actor = battle
.state
.entities
.actor(id)
.unwrap_or_else(|| panic!("constraint violated: actor {:?} not found", id));
battle.state.rounds.rules.on_start(
&battle.state.entities,
&battle.state.space,
&mut battle.state.rounds.model,
actor,
&mut battle.entropy,
metrics,
);
battle.rules.actor_rules().on_turn_start(
&battle.state,
actor,
event_queue,
&mut battle.entropy,
metrics,
);
update_statuses(id, battle, event_queue)
.unwrap_or_else(|err| panic!("constraint violated: {:?}", err));
}
}
fn kind(&self) -> EventKind {
EventKind::StartTurn
}
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 mut teams = Vec::new();
for id in &self.ids {
let actor =
battle.state.entities.actor(id).unwrap_or_else(|| {
panic!("constraint violated: actor {:?} not found", id.clone())
});
teams.push(actor.team_id());
}
EventRights::Teams(teams)
}
}
pub struct StartTurnTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
ids: Vec<EntityId<R>>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for StartTurnTrigger<'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(StartTurn {
ids: self.ids.clone(),
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct EndTurn<R> {
#[cfg_attr(feature = "serialization", serde(skip))]
_phantom: PhantomData<R>,
}
impl<R: BattleRules> EndTurn<R> {
pub fn trigger<P: EventProcessor<R>>(processor: &mut P) -> EndTurnTrigger<R, P> {
EndTurnTrigger {
processor,
_phantom: PhantomData,
}
}
}
impl<R> Debug for EndTurn<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "EndTurn {{ }}")
}
}
impl<R> Clone for EndTurn<R> {
fn clone(&self) -> Self {
Self {
_phantom: PhantomData,
}
}
}
impl<R: BattleRules + 'static> Event<R> for EndTurn<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if let TurnState::Ready = battle.rounds().state() {
return Err(WeaselError::NoTurnInProgress);
}
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let actors_ids = if let TurnState::Started(actors) = battle.state.rounds.state() {
actors.clone()
} else {
panic!("constraint violated: end turn called when state is not started");
};
for actor_id in actors_ids {
let actor = battle.state.entities.actor(&actor_id).unwrap_or_else(|| {
panic!(
"constraint violated: actor {:?} not found",
actor_id.clone()
)
});
let metrics = &mut battle.metrics.write_handle();
battle.rules.actor_rules().on_turn_end(
&battle.state,
actor,
event_queue,
&mut battle.entropy,
metrics,
);
battle.state.rounds.on_end(
&battle.state.entities,
&battle.state.space,
actor,
&mut battle.entropy,
metrics,
);
Battle::check_objectives(
&battle.state,
&battle.rules.team_rules(),
&battle.metrics.read_handle(),
event_queue,
Checkpoint::TurnEnd,
);
}
battle.state.rounds.set_state(TurnState::Ready);
battle.rounds_mut().increase_completed_turns();
}
fn kind(&self) -> EventKind {
EventKind::EndTurn
}
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 actors = if let TurnState::Started(actors) = battle.state.rounds.state() {
actors
} else {
panic!("constraint violated: end turn called when state is not started");
};
let mut teams = Vec::new();
for actor_id in actors {
let actor = battle.state.entities.actor(actor_id).unwrap_or_else(|| {
panic!(
"constraint violated: actor {:?} not found",
actor_id.clone()
)
});
teams.push(actor.team_id());
}
EventRights::Teams(teams)
}
}
pub struct EndTurnTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
_phantom: PhantomData<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for EndTurnTrigger<'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(EndTurn {
_phantom: self._phantom,
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct ResetRounds<R: BattleRules> {
#[cfg_attr(
feature = "serialization",
serde(bound(
serialize = "Option<RoundsSeed<R>>: Serialize",
deserialize = "Option<RoundsSeed<R>>: Deserialize<'de>"
))
)]
seed: Option<RoundsSeed<R>>,
}
impl<R: BattleRules> ResetRounds<R> {
pub fn trigger<P: EventProcessor<R>>(processor: &mut P) -> ResetRoundsTrigger<R, P> {
ResetRoundsTrigger {
processor,
seed: None,
}
}
pub fn seed(&self) -> &Option<RoundsSeed<R>> {
&self.seed
}
}
impl<R: BattleRules> Debug for ResetRounds<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "ResetRounds {{ seed: {:?} }}", self.seed)
}
}
impl<R: BattleRules> Clone for ResetRounds<R> {
fn clone(&self) -> Self {
Self {
seed: self.seed.clone(),
}
}
}
impl<R: BattleRules + 'static> Event<R> for ResetRounds<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if let TurnState::Started(_) = battle.rounds().state() {
return Err(WeaselError::TurnInProgress);
}
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
battle.state.rounds.regenerate_model(&self.seed);
}
fn kind(&self) -> EventKind {
EventKind::ResetRounds
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct ResetRoundsTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
seed: Option<RoundsSeed<R>>,
}
impl<'a, R, P> ResetRoundsTrigger<'a, R, P>
where
R: BattleRules + 'static,
P: EventProcessor<R>,
{
pub fn seed(&'a mut self, seed: RoundsSeed<R>) -> &'a mut Self {
self.seed = Some(seed);
self
}
}
impl<'a, R, P> EventTrigger<'a, R, P> for ResetRoundsTrigger<'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(ResetRounds {
seed: self.seed.clone(),
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct EnvironmentTurn<R> {
#[cfg_attr(feature = "serialization", serde(skip))]
_phantom: PhantomData<R>,
}
impl<R: BattleRules> EnvironmentTurn<R> {
pub fn trigger<P: EventProcessor<R>>(processor: &mut P) -> EnvironmentTurnTrigger<R, P> {
EnvironmentTurnTrigger {
processor,
_phantom: PhantomData,
}
}
}
impl<R> Debug for EnvironmentTurn<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "EnvironmentTurn {{ }}")
}
}
impl<R> Clone for EnvironmentTurn<R> {
fn clone(&self) -> Self {
Self {
_phantom: PhantomData,
}
}
}
impl<R: BattleRules + 'static> Event<R> for EnvironmentTurn<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if let TurnState::Started(_) = battle.rounds().state() {
return Err(WeaselError::TurnInProgress);
}
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
let objects_ids: Vec<_> = battle
.entities()
.objects()
.map(|object| object.entity_id())
.cloned()
.collect();
for object_id in objects_ids {
update_statuses(&object_id, battle, event_queue)
.unwrap_or_else(|err| panic!("constraint violated: {:?}", err));
}
battle.rounds_mut().increase_completed_turns();
}
fn kind(&self) -> EventKind {
EventKind::EnvironmentTurn
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct EnvironmentTurnTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
_phantom: PhantomData<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for EnvironmentTurnTrigger<'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(EnvironmentTurn {
_phantom: self._phantom,
})
}
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct EndRound<R> {
#[cfg_attr(feature = "serialization", serde(skip))]
_phantom: PhantomData<R>,
}
impl<R: BattleRules> EndRound<R> {
pub fn trigger<P: EventProcessor<R>>(processor: &mut P) -> EndRoundTrigger<R, P> {
EndRoundTrigger {
processor,
_phantom: PhantomData,
}
}
}
impl<R> Debug for EndRound<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "EndRound {{ }}")
}
}
impl<R> Clone for EndRound<R> {
fn clone(&self) -> Self {
Self {
_phantom: PhantomData,
}
}
}
impl<R: BattleRules + 'static> Event<R> for EndRound<R> {
fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
if let TurnState::Started(_) = battle.rounds().state() {
return Err(WeaselError::TurnInProgress);
}
Ok(())
}
fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
battle.rounds_mut().increase_completed_rounds();
}
fn kind(&self) -> EventKind {
EventKind::EndRound
}
fn box_clone(&self) -> Box<dyn Event<R> + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct EndRoundTrigger<'a, R, P>
where
R: BattleRules,
P: EventProcessor<R>,
{
processor: &'a mut P,
_phantom: PhantomData<R>,
}
impl<'a, R, P> EventTrigger<'a, R, P> for EndRoundTrigger<'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(EndRound {
_phantom: self._phantom,
})
}
}