use std::fmt::{Display, Formatter, Result};
use weasel::character::StatisticId;
use weasel::rules::entropy::UniformDistribution;
use weasel::rules::statistic::SimpleStatistic;
use weasel::{
battle_rules, rules::empty::*, Actor, BattleRules, CharacterRules, Entities, EntityId, Entropy,
RoundsRules, Space, WriteMetrics,
};
static SPEED: StatisticId<CustomRules> = 0;
battle_rules! {
EmptyTeamRules,
CustomCharacterRules,
EmptyActorRules,
EmptyFightRules,
EmptyUserRules,
EmptySpaceRules,
CustomRoundsRules,
UniformDistribution<u32>
}
#[derive(Default)]
pub struct CustomCharacterRules {}
impl CharacterRules<CustomRules> for CustomCharacterRules {
type CreatureId = u8;
type ObjectId = u8;
type Statistic = SimpleStatistic<u8, u16>;
type StatisticsSeed = u16;
type StatisticsAlteration = ();
type Status = EmptyStatus;
type StatusesAlteration = ();
fn generate_statistics(
&self,
seed: &Option<Self::StatisticsSeed>,
_entropy: &mut Entropy<CustomRules>,
_metrics: &mut WriteMetrics<CustomRules>,
) -> Box<dyn Iterator<Item = Self::Statistic>> {
let v = vec![SimpleStatistic::new(SPEED, seed.unwrap())];
Box::new(v.into_iter())
}
}
#[derive(Default)]
pub struct CustomRoundsRules {}
impl RoundsRules<CustomRules> for CustomRoundsRules {
type RoundsSeed = ();
type RoundsModel = InitiativeModel;
fn generate_model(&self, _: &Option<Self::RoundsSeed>) -> Self::RoundsModel {
InitiativeModel::default()
}
fn eligible(&self, model: &Self::RoundsModel, actor: &dyn Actor<CustomRules>) -> bool {
if model.actors.is_empty() {
false
} else {
model.actors[0].0 == *actor.entity_id()
}
}
fn on_end(
&self,
entities: &Entities<CustomRules>,
_: &Space<CustomRules>,
model: &mut Self::RoundsModel,
actor: &dyn Actor<CustomRules>,
entropy: &mut Entropy<CustomRules>,
_: &mut WriteMetrics<CustomRules>,
) {
for actor in entities.actors() {
let speed: f64 = actor.statistic(&SPEED).unwrap().value().into();
model.update(
actor,
entropy.generate(
(speed - (speed * 0.25)) as u32,
(speed + (speed * 0.25)) as u32,
),
);
}
model.reset(actor);
model.sort();
}
fn on_actor_added(
&self,
model: &mut Self::RoundsModel,
actor: &dyn Actor<CustomRules>,
_: &mut Entropy<CustomRules>,
_: &mut WriteMetrics<CustomRules>,
) {
model.insert(actor);
}
fn on_actor_removed(
&self,
model: &mut Self::RoundsModel,
actor: &dyn Actor<CustomRules>,
_: &mut Entropy<CustomRules>,
_: &mut WriteMetrics<CustomRules>,
) {
model.remove(actor);
}
}
#[derive(Default)]
pub(crate) struct InitiativeModel {
actors: Vec<(EntityId<CustomRules>, u32)>,
}
impl InitiativeModel {
fn sort(&mut self) {
self.actors.sort_by(|lhs, rhs| rhs.1.cmp(&lhs.1));
}
fn insert(&mut self, actor: &dyn Actor<CustomRules>) {
self.actors.push((
*actor.entity_id(),
actor.statistic(&SPEED).unwrap().value().into(),
));
self.sort();
}
pub(crate) fn top(&self) -> EntityId<CustomRules> {
self.actors[0].0
}
fn reset(&mut self, actor: &dyn Actor<CustomRules>) {
if let Some(index) = self.actor_index(actor) {
self.actors[index].1 = 0;
}
}
fn update(&mut self, actor: &dyn Actor<CustomRules>, value: u32) {
if let Some(index) = self.actor_index(actor) {
self.actors[index].1 += value;
}
}
fn remove(&mut self, actor: &dyn Actor<CustomRules>) {
if let Some(index) = self.actor_index(actor) {
self.actors.remove(index);
}
}
fn actor_index(&self, actor: &dyn Actor<CustomRules>) -> Option<usize> {
self.actors
.iter()
.position(|(actor_id, _)| actor_id == actor.entity_id())
}
}
impl Display for InitiativeModel {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
writeln!(f, "Actor Score")?;
for (actor_id, score) in &self.actors {
writeln!(f, "{} {}", actor_id, score)?;
}
Ok(())
}
}