1use crate::battle::{Battle, BattleRules, BattleState};
4use crate::entity::{transmute_entity, Entities, Entity, EntityId, Transmutation};
5use crate::entropy::Entropy;
6use crate::error::{WeaselError, WeaselResult};
7use crate::event::{Event, EventKind, EventProcessor, EventQueue, EventTrigger, Prioritized};
8use crate::metric::WriteMetrics;
9use crate::status::{AppliedStatus, Potency, Status, StatusId};
10use crate::util::Id;
11#[cfg(feature = "serialization")]
12use serde::{Deserialize, Serialize};
13use std::any::Any;
14use std::fmt::{Debug, Formatter, Result};
15use std::hash::Hash;
16
17pub trait CharacterRules<R: BattleRules> {
19 #[cfg(not(feature = "serialization"))]
20 type CreatureId: Hash + Eq + Clone + Debug + Send;
22 #[cfg(feature = "serialization")]
23 type CreatureId: Hash + Eq + Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
25
26 #[cfg(not(feature = "serialization"))]
27 type ObjectId: Hash + Eq + Clone + Debug + Send;
29 #[cfg(feature = "serialization")]
30 type ObjectId: Hash + Eq + Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
32
33 type Statistic: Id + 'static;
35
36 #[cfg(not(feature = "serialization"))]
37 type StatisticsSeed: Clone + Debug + Send;
39 #[cfg(feature = "serialization")]
40 type StatisticsSeed: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
42
43 #[cfg(not(feature = "serialization"))]
44 type StatisticsAlteration: Clone + Debug + Send;
46 #[cfg(feature = "serialization")]
47 type StatisticsAlteration: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
49
50 type Status: Id + 'static;
52
53 #[cfg(not(feature = "serialization"))]
54 type StatusesAlteration: Clone + Debug + Send;
56 #[cfg(feature = "serialization")]
57 type StatusesAlteration: Clone + Debug + Send + Serialize + for<'a> Deserialize<'a>;
59
60 fn generate_statistics(
65 &self,
66 _seed: &Option<Self::StatisticsSeed>,
67 _entropy: &mut Entropy<R>,
68 _metrics: &mut WriteMetrics<R>,
69 ) -> Box<dyn Iterator<Item = Self::Statistic>> {
70 Box::new(std::iter::empty())
71 }
72
73 fn alter_statistics(
79 &self,
80 _character: &mut dyn Character<R>,
81 _alteration: &Self::StatisticsAlteration,
82 _entropy: &mut Entropy<R>,
83 _metrics: &mut WriteMetrics<R>,
84 ) -> Option<Transmutation> {
85 None
86 }
87
88 fn generate_status(
94 &self,
95 _character: &dyn Character<R>,
96 _status_id: &StatusId<R>,
97 _potency: &Option<Potency<R>>,
98 _entropy: &mut Entropy<R>,
99 _metrics: &mut WriteMetrics<R>,
100 ) -> Option<Status<R>> {
101 None
102 }
103
104 fn alter_statuses(
108 &self,
109 _character: &mut dyn Character<R>,
110 _alteration: &Self::StatusesAlteration,
111 _entropy: &mut Entropy<R>,
112 _metrics: &mut WriteMetrics<R>,
113 ) {
114 }
115
116 fn on_character_added(
120 &self,
121 _state: &BattleState<R>,
122 _character: &dyn Character<R>,
123 _event_queue: &mut Option<EventQueue<R>>,
124 _entropy: &mut Entropy<R>,
125 _metrics: &mut WriteMetrics<R>,
126 ) {
127 }
128
129 fn on_character_transmuted(
133 &self,
134 _state: &BattleState<R>,
135 _character: &dyn Character<R>,
136 _transmutation: Transmutation,
137 _event_queue: &mut Option<EventQueue<R>>,
138 _entropy: &mut Entropy<R>,
139 _metrics: &mut WriteMetrics<R>,
140 ) {
141 }
142}
143
144pub type Statistic<R> = <<R as BattleRules>::CR as CharacterRules<R>>::Statistic;
149
150pub type StatisticId<R> = <Statistic<R> as Id>::Id;
152
153pub type StatisticsSeed<R> = <<R as BattleRules>::CR as CharacterRules<R>>::StatisticsSeed;
155
156pub type StatisticsAlteration<R> =
158 <<R as BattleRules>::CR as CharacterRules<R>>::StatisticsAlteration;
159
160pub trait Character<R: BattleRules>: Entity<R> {
162 fn statistics<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Statistic<R>> + 'a>;
164
165 fn statistics_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Statistic<R>> + 'a>;
167
168 fn statistic(&self, id: &StatisticId<R>) -> Option<&Statistic<R>>;
170
171 fn statistic_mut(&mut self, id: &StatisticId<R>) -> Option<&mut Statistic<R>>;
173
174 fn add_statistic(&mut self, statistic: Statistic<R>) -> Option<Statistic<R>>;
177
178 fn remove_statistic(&mut self, id: &StatisticId<R>) -> Option<Statistic<R>>;
181
182 fn statuses<'a>(&'a self) -> Box<dyn Iterator<Item = &'a AppliedStatus<R>> + 'a>;
184
185 fn statuses_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut AppliedStatus<R>> + 'a>;
187
188 fn status(&self, id: &StatusId<R>) -> Option<&AppliedStatus<R>>;
190
191 fn status_mut(&mut self, id: &StatusId<R>) -> Option<&mut AppliedStatus<R>>;
193
194 fn add_status(&mut self, status: AppliedStatus<R>) -> Option<AppliedStatus<R>>;
197
198 fn remove_status(&mut self, id: &StatusId<R>) -> Option<AppliedStatus<R>>;
201}
202
203#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
235pub struct AlterStatistics<R: BattleRules> {
236 #[cfg_attr(
237 feature = "serialization",
238 serde(bound(
239 serialize = "EntityId<R>: Serialize",
240 deserialize = "EntityId<R>: Deserialize<'de>"
241 ))
242 )]
243 id: EntityId<R>,
244
245 #[cfg_attr(
246 feature = "serialization",
247 serde(bound(
248 serialize = "StatisticsAlteration<R>: Serialize",
249 deserialize = "StatisticsAlteration<R>: Deserialize<'de>"
250 ))
251 )]
252 alteration: StatisticsAlteration<R>,
253}
254
255impl<R: BattleRules> AlterStatistics<R> {
256 pub fn trigger<'a, P: EventProcessor<R>>(
258 processor: &'a mut P,
259 id: EntityId<R>,
260 alteration: StatisticsAlteration<R>,
261 ) -> AlterStatisticsTrigger<'a, R, P> {
262 AlterStatisticsTrigger {
263 processor,
264 id,
265 alteration,
266 }
267 }
268
269 pub fn id(&self) -> &EntityId<R> {
271 &self.id
272 }
273
274 pub fn alteration(&self) -> &StatisticsAlteration<R> {
276 &self.alteration
277 }
278}
279
280impl<R: BattleRules> Debug for AlterStatistics<R> {
281 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
282 write!(
283 f,
284 "AlterStatistics {{ id: {:?}, alteration: {:?} }}",
285 self.id, self.alteration
286 )
287 }
288}
289
290impl<R: BattleRules> Clone for AlterStatistics<R> {
291 fn clone(&self) -> Self {
292 Self {
293 id: self.id.clone(),
294 alteration: self.alteration.clone(),
295 }
296 }
297}
298
299impl<R: BattleRules + 'static> Event<R> for AlterStatistics<R> {
300 fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
301 verify_get_character(battle.entities(), &self.id).map(|_| ())
302 }
303
304 fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
305 let character = battle
307 .state
308 .entities
309 .character_mut(&self.id)
310 .unwrap_or_else(|| panic!("constraint violated: character {:?} not found", self.id));
311 let transmutation = battle.rules.character_rules().alter_statistics(
313 character,
314 &self.alteration,
315 &mut battle.entropy,
316 &mut battle.metrics.write_handle(),
317 );
318 if let Some(transmutation) = transmutation {
320 transmute_entity(
321 &self.id,
322 transmutation,
323 &mut event_queue.as_mut().map(|queue| Prioritized::new(queue)),
324 );
325 }
326 }
327
328 fn kind(&self) -> EventKind {
329 EventKind::AlterStatistics
330 }
331
332 fn box_clone(&self) -> Box<dyn Event<R> + Send> {
333 Box::new(self.clone())
334 }
335
336 fn as_any(&self) -> &dyn Any {
337 self
338 }
339}
340
341pub struct AlterStatisticsTrigger<'a, R, P>
343where
344 R: BattleRules,
345 P: EventProcessor<R>,
346{
347 processor: &'a mut P,
348 id: EntityId<R>,
349 alteration: StatisticsAlteration<R>,
350}
351
352impl<'a, R, P> EventTrigger<'a, R, P> for AlterStatisticsTrigger<'a, R, P>
353where
354 R: BattleRules + 'static,
355 P: EventProcessor<R>,
356{
357 fn processor(&'a mut self) -> &'a mut P {
358 self.processor
359 }
360
361 fn event(&self) -> Box<dyn Event<R> + Send> {
363 Box::new(AlterStatistics {
364 id: self.id.clone(),
365 alteration: self.alteration.clone(),
366 })
367 }
368}
369
370#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
407pub struct RegenerateStatistics<R: BattleRules> {
408 #[cfg_attr(
409 feature = "serialization",
410 serde(bound(
411 serialize = "EntityId<R>: Serialize",
412 deserialize = "EntityId<R>: Deserialize<'de>"
413 ))
414 )]
415 id: EntityId<R>,
416
417 #[cfg_attr(
418 feature = "serialization",
419 serde(bound(
420 serialize = "Option<StatisticsSeed<R>>: Serialize",
421 deserialize = "Option<StatisticsSeed<R>>: Deserialize<'de>"
422 ))
423 )]
424 seed: Option<StatisticsSeed<R>>,
425}
426
427impl<R: BattleRules> RegenerateStatistics<R> {
428 pub fn trigger<P: EventProcessor<R>>(
430 processor: &'_ mut P,
431 id: EntityId<R>,
432 ) -> RegenerateStatisticsTrigger<'_, R, P> {
433 RegenerateStatisticsTrigger {
434 processor,
435 id,
436 seed: None,
437 }
438 }
439
440 pub fn id(&self) -> &EntityId<R> {
442 &self.id
443 }
444
445 pub fn seed(&self) -> &Option<StatisticsSeed<R>> {
447 &self.seed
448 }
449}
450
451impl<R: BattleRules> Debug for RegenerateStatistics<R> {
452 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
453 write!(
454 f,
455 "RegenerateStatistics {{ id: {:?}, seed: {:?} }}",
456 self.id, self.seed
457 )
458 }
459}
460
461impl<R: BattleRules> Clone for RegenerateStatistics<R> {
462 fn clone(&self) -> Self {
463 Self {
464 id: self.id.clone(),
465 seed: self.seed.clone(),
466 }
467 }
468}
469
470impl<R: BattleRules + 'static> Event<R> for RegenerateStatistics<R> {
471 fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
472 verify_get_character(battle.entities(), &self.id).map(|_| ())
473 }
474
475 fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
476 let character = battle
478 .state
479 .entities
480 .character_mut(&self.id)
481 .unwrap_or_else(|| panic!("constraint violated: character {:?} not found", self.id));
482 let statistics: Vec<_> = battle
484 .rules
485 .character_rules()
486 .generate_statistics(
487 &self.seed,
488 &mut battle.entropy,
489 &mut battle.metrics.write_handle(),
490 )
491 .collect();
492 let mut to_remove = Vec::new();
493 for statistic in character.statistics() {
495 if statistics
496 .iter()
497 .find(|e| e.id() == statistic.id())
498 .is_none()
499 {
500 to_remove.push(statistic.id().clone());
501 }
502 }
503 for statistic_id in to_remove {
504 character.remove_statistic(&statistic_id);
505 }
506 for statistic in statistics {
508 if character.statistic(statistic.id()).is_none() {
509 character.add_statistic(statistic);
510 }
511 }
512 }
513
514 fn kind(&self) -> EventKind {
515 EventKind::RegenerateStatistics
516 }
517
518 fn box_clone(&self) -> Box<dyn Event<R> + Send> {
519 Box::new(self.clone())
520 }
521
522 fn as_any(&self) -> &dyn Any {
523 self
524 }
525}
526
527pub struct RegenerateStatisticsTrigger<'a, R, P>
529where
530 R: BattleRules,
531 P: EventProcessor<R>,
532{
533 processor: &'a mut P,
534 id: EntityId<R>,
535 seed: Option<StatisticsSeed<R>>,
536}
537
538impl<'a, R, P> RegenerateStatisticsTrigger<'a, R, P>
539where
540 R: BattleRules + 'static,
541 P: EventProcessor<R>,
542{
543 pub fn seed(&'a mut self, seed: StatisticsSeed<R>) -> &'a mut Self {
545 self.seed = Some(seed);
546 self
547 }
548}
549
550impl<'a, R, P> EventTrigger<'a, R, P> for RegenerateStatisticsTrigger<'a, R, P>
551where
552 R: BattleRules + 'static,
553 P: EventProcessor<R>,
554{
555 fn processor(&'a mut self) -> &'a mut P {
556 self.processor
557 }
558
559 fn event(&self) -> Box<dyn Event<R> + Send> {
561 Box::new(RegenerateStatistics {
562 id: self.id.clone(),
563 seed: self.seed.clone(),
564 })
565 }
566}
567
568pub(crate) fn verify_get_character<'a, R>(
571 entities: &'a Entities<R>,
572 id: &EntityId<R>,
573) -> WeaselResult<&'a dyn Character<R>, R>
574where
575 R: BattleRules,
576{
577 if !id.is_character() {
579 return Err(WeaselError::NotACharacter(id.clone()));
580 }
581 let character = entities
583 .character(id)
584 .ok_or_else(|| WeaselError::EntityNotFound(id.clone()))?;
585 Ok(character)
586}