1use crate::battle::{Battle, BattleRules};
4use crate::character::{verify_get_character, CharacterRules};
5use crate::entity::EntityId;
6use crate::error::{WeaselError, WeaselResult};
7use crate::event::{
8 Event, EventId, EventKind, EventProcessor, EventQueue, EventTrigger, LinkedQueue,
9};
10use crate::fight::FightRules;
11use crate::util::Id;
12#[cfg(feature = "serialization")]
13use serde::{Deserialize, Serialize};
14use std::any::Any;
15use std::fmt::{Debug, Formatter, Result};
16
17pub type Status<R> = <<R as BattleRules>::CR as CharacterRules<R>>::Status;
23
24pub type StatusId<R> = <Status<R> as Id>::Id;
26
27pub type Potency<R> = <<R as BattleRules>::FR as FightRules<R>>::Potency;
29
30pub type StatusesAlteration<R> = <<R as BattleRules>::CR as CharacterRules<R>>::StatusesAlteration;
32
33pub type StatusDuration = EventId;
35
36pub struct AppliedStatus<R: BattleRules> {
38 status: Status<R>,
40 origin: Option<EventId>,
42 duration: StatusDuration,
44}
45
46impl<R: BattleRules> AppliedStatus<R> {
47 pub fn new(status: Status<R>) -> Self {
49 Self {
50 status,
51 origin: None,
52 duration: 0,
53 }
54 }
55
56 pub fn with_origin(status: Status<R>, origin: EventId) -> Self {
58 Self {
59 status,
60 origin: Some(origin),
61 duration: 0,
62 }
63 }
64
65 pub fn status(&self) -> &Status<R> {
67 &self.status
68 }
69
70 pub fn status_mut(&mut self) -> &mut Status<R> {
72 &mut self.status
73 }
74
75 pub fn origin(&self) -> Option<EventId> {
77 self.origin
78 }
79
80 pub fn duration(&self) -> StatusDuration {
83 self.duration
84 }
85
86 pub(crate) fn update(&mut self) {
88 self.duration += 1;
89 }
90}
91
92impl<R: BattleRules> std::ops::Deref for AppliedStatus<R> {
93 type Target = Status<R>;
94
95 fn deref(&self) -> &Self::Target {
96 &self.status
97 }
98}
99
100impl<R: BattleRules> std::ops::DerefMut for AppliedStatus<R> {
101 fn deref_mut(&mut self) -> &mut Self::Target {
102 &mut self.status
103 }
104}
105
106pub type NewStatus<R> = AppliedStatus<R>;
108
109pub type OldStatus<R> = AppliedStatus<R>;
111
112pub enum Application<'a, R: BattleRules> {
114 New(&'a NewStatus<R>),
116 Replacement(&'a OldStatus<R>, &'a NewStatus<R>),
118}
119
120pub(crate) fn update_statuses<R: BattleRules + 'static>(
123 id: &EntityId<R>,
124 battle: &mut Battle<R>,
125 event_queue: &mut Option<EventQueue<R>>,
126) -> WeaselResult<(), R> {
127 let character = battle
129 .state
130 .entities
131 .character_mut(id)
132 .ok_or_else(|| WeaselError::EntityNotFound(id.clone()))?;
133 for status in character.statuses_mut() {
134 status.update();
135 }
136 let character = battle
138 .state
139 .entities
140 .character(id)
141 .ok_or_else(|| WeaselError::EntityNotFound(id.clone()))?;
142 for status in character.statuses() {
143 let terminated = battle.rules.fight_rules().update_status(
144 &battle.state,
145 character,
146 status,
147 &mut event_queue
149 .as_mut()
150 .map(|queue| LinkedQueue::new(queue, status.origin())),
151 &mut battle.entropy,
152 &mut battle.metrics.write_handle(),
153 );
154 if terminated {
155 ClearStatus::trigger(
157 event_queue,
158 character.entity_id().clone(),
159 status.id().clone(),
160 )
161 .fire();
162 }
163 }
164 Ok(())
165}
166
167#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
201pub struct InflictStatus<R: BattleRules> {
202 #[cfg_attr(
203 feature = "serialization",
204 serde(bound(
205 serialize = "EntityId<R>: Serialize",
206 deserialize = "EntityId<R>: Deserialize<'de>"
207 ))
208 )]
209 entity_id: EntityId<R>,
210
211 #[cfg_attr(
212 feature = "serialization",
213 serde(bound(
214 serialize = "StatusId<R>: Serialize",
215 deserialize = "StatusId<R>: Deserialize<'de>"
216 ))
217 )]
218 status_id: StatusId<R>,
219
220 #[cfg_attr(
221 feature = "serialization",
222 serde(bound(
223 serialize = "Option<Potency<R>>: Serialize",
224 deserialize = "Option<Potency<R>>: Deserialize<'de>"
225 ))
226 )]
227 potency: Option<Potency<R>>,
228}
229
230impl<R: BattleRules> InflictStatus<R> {
231 pub fn trigger<'a, P: EventProcessor<R>>(
233 processor: &'a mut P,
234 entity_id: EntityId<R>,
235 status_id: StatusId<R>,
236 ) -> InflictStatusTrigger<'a, R, P> {
237 InflictStatusTrigger {
238 processor,
239 entity_id,
240 status_id,
241 potency: None,
242 }
243 }
244
245 pub fn entity_id(&self) -> &EntityId<R> {
247 &self.entity_id
248 }
249
250 pub fn status_id(&self) -> &StatusId<R> {
252 &self.status_id
253 }
254
255 pub fn potency(&self) -> &Option<Potency<R>> {
257 &self.potency
258 }
259}
260
261impl<R: BattleRules> Debug for InflictStatus<R> {
262 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
263 write!(
264 f,
265 "InflictStatus {{ entity_id: {:?}, status_id: {:?}, potency: {:?} }}",
266 self.entity_id, self.status_id, self.potency
267 )
268 }
269}
270
271impl<R: BattleRules> Clone for InflictStatus<R> {
272 fn clone(&self) -> Self {
273 Self {
274 entity_id: self.entity_id.clone(),
275 status_id: self.status_id.clone(),
276 potency: self.potency.clone(),
277 }
278 }
279}
280
281impl<R: BattleRules + 'static> Event<R> for InflictStatus<R> {
282 fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
283 verify_get_character(battle.entities(), &self.entity_id).map(|_| ())
284 }
285
286 fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
287 let character = battle
289 .state
290 .entities
291 .character_mut(&self.entity_id)
292 .unwrap_or_else(|| {
293 panic!(
294 "constraint violated: character {:?} not found",
295 self.entity_id
296 )
297 });
298 let status = battle.rules.character_rules().generate_status(
300 character,
301 &self.status_id,
302 &self.potency,
303 &mut battle.entropy,
304 &mut battle.metrics.write_handle(),
305 );
306 if let Some(status) = status {
307 let origin = battle.history.next_id();
310 let old_status = character.add_status(AppliedStatus::with_origin(status, origin));
312 let character = battle
314 .state
315 .entities
316 .character(&self.entity_id)
317 .unwrap_or_else(|| {
318 panic!(
319 "constraint violated: character {:?} not found",
320 self.entity_id
321 )
322 });
323 let status = character.status(&self.status_id).unwrap_or_else(|| {
325 panic!(
326 "constraint violated: status {:?} not found in {:?}",
327 self.status_id, self.entity_id
328 )
329 });
330 let application = if let Some(old) = old_status.as_ref() {
331 Application::Replacement(old, status)
332 } else {
333 Application::New(status)
334 };
335 battle.rules.fight_rules().apply_status(
336 &battle.state,
337 character,
338 application,
339 event_queue,
340 &mut battle.entropy,
341 &mut battle.metrics.write_handle(),
342 );
343 }
344 }
345
346 fn kind(&self) -> EventKind {
347 EventKind::InflictStatus
348 }
349
350 fn box_clone(&self) -> Box<dyn Event<R> + Send> {
351 Box::new(self.clone())
352 }
353
354 fn as_any(&self) -> &dyn Any {
355 self
356 }
357}
358
359pub struct InflictStatusTrigger<'a, R, P>
361where
362 R: BattleRules,
363 P: EventProcessor<R>,
364{
365 processor: &'a mut P,
366 entity_id: EntityId<R>,
367 status_id: StatusId<R>,
368 potency: Option<Potency<R>>,
369}
370
371impl<'a, R, P> InflictStatusTrigger<'a, R, P>
372where
373 R: BattleRules + 'static,
374 P: EventProcessor<R>,
375{
376 pub fn potency(&'a mut self, potency: Potency<R>) -> &'a mut Self {
378 self.potency = Some(potency);
379 self
380 }
381}
382
383impl<'a, R, P> EventTrigger<'a, R, P> for InflictStatusTrigger<'a, R, P>
384where
385 R: BattleRules + 'static,
386 P: EventProcessor<R>,
387{
388 fn processor(&'a mut self) -> &'a mut P {
389 self.processor
390 }
391
392 fn event(&self) -> Box<dyn Event<R> + Send> {
394 Box::new(InflictStatus {
395 entity_id: self.entity_id.clone(),
396 status_id: self.status_id.clone(),
397 potency: self.potency.clone(),
398 })
399 }
400}
401
402#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
432pub struct ClearStatus<R: BattleRules> {
433 #[cfg_attr(
434 feature = "serialization",
435 serde(bound(
436 serialize = "EntityId<R>: Serialize",
437 deserialize = "EntityId<R>: Deserialize<'de>"
438 ))
439 )]
440 entity_id: EntityId<R>,
441
442 #[cfg_attr(
443 feature = "serialization",
444 serde(bound(
445 serialize = "StatusId<R>: Serialize",
446 deserialize = "StatusId<R>: Deserialize<'de>"
447 ))
448 )]
449 status_id: StatusId<R>,
450}
451
452impl<R: BattleRules> ClearStatus<R> {
453 pub fn trigger<'a, P: EventProcessor<R>>(
455 processor: &'a mut P,
456 entity_id: EntityId<R>,
457 status_id: StatusId<R>,
458 ) -> ClearStatusTrigger<'a, R, P> {
459 ClearStatusTrigger {
460 processor,
461 entity_id,
462 status_id,
463 }
464 }
465
466 pub fn entity_id(&self) -> &EntityId<R> {
468 &self.entity_id
469 }
470
471 pub fn status_id(&self) -> &StatusId<R> {
473 &self.status_id
474 }
475}
476
477impl<R: BattleRules> Debug for ClearStatus<R> {
478 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
479 write!(
480 f,
481 "ClearStatus {{ entity_id: {:?}, status_id: {:?} }}",
482 self.entity_id, self.status_id
483 )
484 }
485}
486
487impl<R: BattleRules> Clone for ClearStatus<R> {
488 fn clone(&self) -> Self {
489 Self {
490 entity_id: self.entity_id.clone(),
491 status_id: self.status_id.clone(),
492 }
493 }
494}
495
496impl<R: BattleRules + 'static> Event<R> for ClearStatus<R> {
497 fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
498 let character = verify_get_character(battle.entities(), &self.entity_id)?;
499 if character.status(&self.status_id).is_none() {
501 Err(WeaselError::StatusNotPresent(
502 self.entity_id.clone(),
503 self.status_id.clone(),
504 ))
505 } else {
506 Ok(())
507 }
508 }
509
510 fn apply(&self, battle: &mut Battle<R>, event_queue: &mut Option<EventQueue<R>>) {
511 let character = battle
513 .state
514 .entities
515 .character(&self.entity_id)
516 .unwrap_or_else(|| {
517 panic!(
518 "constraint violated: character {:?} not found",
519 self.entity_id
520 )
521 });
522 let status = character.status(&self.status_id).unwrap_or_else(|| {
524 panic!(
525 "constraint violated: status {:?} not found in {:?}",
526 self.status_id, self.entity_id
527 )
528 });
529 battle.rules.fight_rules().delete_status(
530 &battle.state,
531 character,
532 status,
533 event_queue,
534 &mut battle.entropy,
535 &mut battle.metrics.write_handle(),
536 );
537 let character = battle
539 .state
540 .entities
541 .character_mut(&self.entity_id)
542 .unwrap_or_else(|| {
543 panic!(
544 "constraint violated: character {:?} not found",
545 self.entity_id
546 )
547 });
548 character.remove_status(&self.status_id);
550 }
551
552 fn kind(&self) -> EventKind {
553 EventKind::ClearStatus
554 }
555
556 fn box_clone(&self) -> Box<dyn Event<R> + Send> {
557 Box::new(self.clone())
558 }
559
560 fn as_any(&self) -> &dyn Any {
561 self
562 }
563}
564
565pub struct ClearStatusTrigger<'a, R, P>
567where
568 R: BattleRules,
569 P: EventProcessor<R>,
570{
571 processor: &'a mut P,
572 entity_id: EntityId<R>,
573 status_id: StatusId<R>,
574}
575
576impl<'a, R, P> EventTrigger<'a, R, P> for ClearStatusTrigger<'a, R, P>
577where
578 R: BattleRules + 'static,
579 P: EventProcessor<R>,
580{
581 fn processor(&'a mut self) -> &'a mut P {
582 self.processor
583 }
584
585 fn event(&self) -> Box<dyn Event<R> + Send> {
587 Box::new(ClearStatus {
588 entity_id: self.entity_id.clone(),
589 status_id: self.status_id.clone(),
590 })
591 }
592}
593
594#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
626pub struct AlterStatuses<R: BattleRules> {
627 #[cfg_attr(
628 feature = "serialization",
629 serde(bound(
630 serialize = "EntityId<R>: Serialize",
631 deserialize = "EntityId<R>: Deserialize<'de>"
632 ))
633 )]
634 id: EntityId<R>,
635
636 #[cfg_attr(
637 feature = "serialization",
638 serde(bound(
639 serialize = "StatusesAlteration<R>: Serialize",
640 deserialize = "StatusesAlteration<R>: Deserialize<'de>"
641 ))
642 )]
643 alteration: StatusesAlteration<R>,
644}
645
646impl<R: BattleRules> AlterStatuses<R> {
647 pub fn trigger<'a, P: EventProcessor<R>>(
649 processor: &'a mut P,
650 id: EntityId<R>,
651 alteration: StatusesAlteration<R>,
652 ) -> AlterStatusesTrigger<'a, R, P> {
653 AlterStatusesTrigger {
654 processor,
655 id,
656 alteration,
657 }
658 }
659
660 pub fn id(&self) -> &EntityId<R> {
662 &self.id
663 }
664
665 pub fn alteration(&self) -> &StatusesAlteration<R> {
667 &self.alteration
668 }
669}
670
671impl<R: BattleRules> Debug for AlterStatuses<R> {
672 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
673 write!(
674 f,
675 "AlterStatuses {{ id: {:?}, alteration: {:?} }}",
676 self.id, self.alteration
677 )
678 }
679}
680
681impl<R: BattleRules> Clone for AlterStatuses<R> {
682 fn clone(&self) -> Self {
683 Self {
684 id: self.id.clone(),
685 alteration: self.alteration.clone(),
686 }
687 }
688}
689
690impl<R: BattleRules + 'static> Event<R> for AlterStatuses<R> {
691 fn verify(&self, battle: &Battle<R>) -> WeaselResult<(), R> {
692 verify_get_character(battle.entities(), &self.id).map(|_| ())
693 }
694
695 fn apply(&self, battle: &mut Battle<R>, _: &mut Option<EventQueue<R>>) {
696 let character = battle
698 .state
699 .entities
700 .character_mut(&self.id)
701 .unwrap_or_else(|| panic!("constraint violated: character {:?} not found", self.id));
702 battle.rules.character_rules().alter_statuses(
704 character,
705 &self.alteration,
706 &mut battle.entropy,
707 &mut battle.metrics.write_handle(),
708 );
709 }
710
711 fn kind(&self) -> EventKind {
712 EventKind::AlterStatuses
713 }
714
715 fn box_clone(&self) -> Box<dyn Event<R> + Send> {
716 Box::new(self.clone())
717 }
718
719 fn as_any(&self) -> &dyn Any {
720 self
721 }
722}
723
724pub struct AlterStatusesTrigger<'a, R, P>
726where
727 R: BattleRules,
728 P: EventProcessor<R>,
729{
730 processor: &'a mut P,
731 id: EntityId<R>,
732 alteration: StatusesAlteration<R>,
733}
734
735impl<'a, R, P> EventTrigger<'a, R, P> for AlterStatusesTrigger<'a, R, P>
736where
737 R: BattleRules + 'static,
738 P: EventProcessor<R>,
739{
740 fn processor(&'a mut self) -> &'a mut P {
741 self.processor
742 }
743
744 fn event(&self) -> Box<dyn Event<R> + Send> {
746 Box::new(AlterStatuses {
747 id: self.id.clone(),
748 alteration: self.alteration.clone(),
749 })
750 }
751}