1use crate::actor::Actor;
4use crate::battle::BattleRules;
5use crate::character::Character;
6use crate::creature::{Creature, CreatureId, RemoveCreature};
7use crate::error::{WeaselError, WeaselResult};
8use crate::event::{Event, EventProcessor, EventTrigger};
9use crate::object::{Object, ObjectId, RemoveObject};
10use crate::space::Position;
11use crate::team::{Conclusion, Relation, RelationshipPair, Team, TeamId};
12use crate::util::Id;
13use indexmap::IndexMap;
14#[cfg(feature = "serialization")]
15use serde::{Deserialize, Serialize};
16use std::fmt::{Debug, Display, Formatter, Result};
17use std::hash::{Hash, Hasher};
18use std::marker::PhantomData;
19
20pub trait Entity<R: BattleRules> {
22 fn entity_id(&self) -> &EntityId<R>;
24
25 fn position(&self) -> &Position<R>;
27
28 fn set_position(&mut self, position: Position<R>);
30}
31
32#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
36pub enum EntityId<R: BattleRules> {
37 #[cfg_attr(
39 feature = "serialization",
40 serde(bound(
41 serialize = "CreatureId<R>: Serialize",
42 deserialize = "CreatureId<R>: Deserialize<'de>"
43 ))
44 )]
45 Creature(CreatureId<R>),
46 #[cfg_attr(
48 feature = "serialization",
49 serde(bound(
50 serialize = "ObjectId<R>: Serialize",
51 deserialize = "ObjectId<R>: Deserialize<'de>"
52 ))
53 )]
54 Object(ObjectId<R>),
55}
56
57impl<R: BattleRules> EntityId<R> {
58 pub fn is_character(&self) -> bool {
60 match self {
61 Self::Creature(_) => true,
62 Self::Object(_) => true,
63 }
64 }
65
66 pub fn is_actor(&self) -> bool {
68 match self {
69 Self::Creature(_) => true,
70 Self::Object(_) => false,
71 }
72 }
73
74 pub fn creature(&self) -> WeaselResult<CreatureId<R>, R> {
78 match self {
79 Self::Creature(id) => Ok(id.clone()),
80 Self::Object(_) => Err(WeaselError::NotACreature(self.clone())),
81 }
82 }
83
84 pub fn object(&self) -> WeaselResult<ObjectId<R>, R> {
88 match self {
89 Self::Creature(_) => Err(WeaselError::NotAnObject(self.clone())),
90 Self::Object(id) => Ok(id.clone()),
91 }
92 }
93}
94
95impl<R: BattleRules> Debug for EntityId<R> {
96 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
97 match self {
98 Self::Creature(id) => write!(f, "EntityId::Creature {{ {:?} }}", id),
99 Self::Object(id) => write!(f, "EntityId::Object {{ {:?} }}", id),
100 }
101 }
102}
103
104impl<R: BattleRules> Copy for EntityId<R>
105where
106 CreatureId<R>: Copy,
107 ObjectId<R>: Copy,
108{
109}
110
111impl<R: BattleRules> Display for EntityId<R>
112where
113 CreatureId<R>: Display,
114 ObjectId<R>: Display,
115{
116 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
117 match self {
118 Self::Creature(id) => write!(f, "Creature ({})", id),
119 Self::Object(id) => write!(f, "Object ({})", id),
120 }
121 }
122}
123
124impl<R: BattleRules> Clone for EntityId<R> {
125 fn clone(&self) -> Self {
126 match self {
127 Self::Creature(id) => Self::Creature(id.clone()),
128 Self::Object(id) => Self::Object(id.clone()),
129 }
130 }
131}
132
133impl<R: BattleRules> PartialEq<Self> for EntityId<R> {
134 fn eq(&self, other: &Self) -> bool {
135 match self {
136 Self::Creature(id) => match other {
137 Self::Creature(other_id) => id == other_id,
138 _ => false,
139 },
140 Self::Object(id) => match other {
141 Self::Object(other_id) => id == other_id,
142 _ => false,
143 },
144 }
145 }
146}
147
148impl<R: BattleRules> Eq for EntityId<R> {}
149
150impl<R: BattleRules> Hash for EntityId<R> {
151 fn hash<H: Hasher>(&self, state: &mut H) {
152 match self {
153 Self::Creature(id) => id.hash(state),
154 Self::Object(id) => id.hash(state),
155 }
156 }
157}
158
159pub enum Transmutation {
161 REMOVAL,
163}
164
165pub(crate) fn transmute_entity<R, P>(
167 id: &EntityId<R>,
168 transmutation: Transmutation,
169 processor: &mut P,
170) where
171 R: BattleRules + 'static,
172 P: EventProcessor<R>,
173{
174 match transmutation {
175 Transmutation::REMOVAL => match id {
176 EntityId::Creature(id) => {
177 RemoveCreature::trigger(processor, id.clone()).fire();
178 }
179 EntityId::Object(id) => {
180 RemoveObject::trigger(processor, id.clone()).fire();
181 }
182 },
183 }
184}
185
186pub struct Entities<R: BattleRules> {
188 teams: IndexMap<TeamId<R>, Team<R>>,
189 creatures: IndexMap<CreatureId<R>, Creature<R>>,
190 objects: IndexMap<ObjectId<R>, Object<R>>,
191 relations: IndexMap<RelationshipPair<R>, Relation>,
192}
193
194impl<R: BattleRules> Entities<R> {
195 pub(crate) fn new() -> Self {
196 Self {
197 teams: IndexMap::new(),
198 creatures: IndexMap::new(),
199 objects: IndexMap::new(),
200 relations: IndexMap::new(),
201 }
202 }
203
204 pub fn creatures(&self) -> impl Iterator<Item = &Creature<R>> {
206 self.creatures.values()
207 }
208
209 pub fn creatures_mut(&mut self) -> impl Iterator<Item = &mut Creature<R>> {
211 self.creatures.values_mut()
212 }
213
214 pub fn creature(&self, id: &CreatureId<R>) -> Option<&Creature<R>> {
216 self.creatures.get(id)
217 }
218
219 pub fn creature_mut(&mut self, id: &CreatureId<R>) -> Option<&mut Creature<R>> {
221 self.creatures.get_mut(id)
222 }
223
224 pub fn objects(&self) -> impl Iterator<Item = &Object<R>> {
226 self.objects.values()
227 }
228
229 pub fn objects_mut(&mut self) -> impl Iterator<Item = &mut Object<R>> {
231 self.objects.values_mut()
232 }
233
234 pub fn object(&self, id: &ObjectId<R>) -> Option<&Object<R>> {
236 self.objects.get(id)
237 }
238
239 pub fn object_mut(&mut self, id: &ObjectId<R>) -> Option<&mut Object<R>> {
241 self.objects.get_mut(id)
242 }
243
244 pub fn teams(&self) -> impl Iterator<Item = &Team<R>> {
246 self.teams.values()
247 }
248
249 pub fn teams_mut(&mut self) -> impl Iterator<Item = &mut Team<R>> {
251 self.teams.values_mut()
252 }
253
254 pub fn team(&self, id: &TeamId<R>) -> Option<&Team<R>> {
256 self.teams.get(id)
257 }
258
259 pub fn team_mut(&mut self, id: &TeamId<R>) -> Option<&mut Team<R>> {
261 self.teams.get_mut(id)
262 }
263
264 pub(crate) fn add_team(&mut self, team: Team<R>) {
265 self.teams.insert(team.id().clone(), team);
266 }
267
268 pub(crate) fn add_creature(&mut self, creature: Creature<R>) -> WeaselResult<(), R> {
269 let team = self
271 .teams
272 .get_mut(creature.team_id())
273 .ok_or_else(|| WeaselError::TeamNotFound(creature.team_id().clone()))?;
274 team.creatures_mut().push(creature.id().clone());
275 self.creatures.insert(creature.id().clone(), creature);
277 Ok(())
278 }
279
280 pub(crate) fn add_object(&mut self, object: Object<R>) {
281 self.objects.insert(object.id().clone(), object);
283 }
284
285 pub fn entities(&self) -> impl Iterator<Item = &dyn Entity<R>> {
287 self.creatures
288 .values()
289 .map(|e| e as &dyn Entity<R>)
290 .chain(self.objects.values().map(|e| e as &dyn Entity<R>))
291 }
292
293 pub fn entities_mut(&mut self) -> impl Iterator<Item = &mut dyn Entity<R>> {
295 self.creatures
296 .values_mut()
297 .map(|e| e as &mut dyn Entity<R>)
298 .chain(self.objects.values_mut().map(|e| e as &mut dyn Entity<R>))
299 }
300
301 pub fn entity(&self, id: &EntityId<R>) -> Option<&dyn Entity<R>> {
303 match id {
304 EntityId::Creature(id) => self.creature(id).map(|e| e as &dyn Entity<R>),
305 EntityId::Object(id) => self.object(id).map(|e| e as &dyn Entity<R>),
306 }
307 }
308
309 pub fn entity_mut(&mut self, id: &EntityId<R>) -> Option<&mut dyn Entity<R>> {
311 match id {
312 EntityId::Creature(id) => self.creature_mut(id).map(|e| e as &mut dyn Entity<R>),
313 EntityId::Object(id) => self.object_mut(id).map(|e| e as &mut dyn Entity<R>),
314 }
315 }
316
317 pub fn characters(&self) -> impl Iterator<Item = &dyn Character<R>> {
319 self.creatures()
320 .map(|e| e as &dyn Character<R>)
321 .chain(self.objects().map(|e| e as &dyn Character<R>))
322 }
323
324 pub fn characters_mut(&mut self) -> impl Iterator<Item = &mut dyn Character<R>> {
326 self.creatures
327 .values_mut()
328 .map(|e| e as &mut dyn Character<R>)
329 .chain(
330 self.objects
331 .values_mut()
332 .map(|e| e as &mut dyn Character<R>),
333 )
334 }
335
336 pub fn character(&self, id: &EntityId<R>) -> Option<&dyn Character<R>> {
338 match id {
339 EntityId::Creature(id) => self.creature(id).map(|e| e as &dyn Character<R>),
340 EntityId::Object(id) => self.object(id).map(|e| e as &dyn Character<R>),
341 }
342 }
343
344 pub fn character_mut(&mut self, id: &EntityId<R>) -> Option<&mut dyn Character<R>> {
346 match id {
347 EntityId::Creature(id) => self.creature_mut(id).map(|e| e as &mut dyn Character<R>),
348 EntityId::Object(id) => self.object_mut(id).map(|e| e as &mut dyn Character<R>),
349 }
350 }
351
352 pub fn actors(&self) -> impl Iterator<Item = &dyn Actor<R>> {
354 self.creatures().map(|e| e as &dyn Actor<R>)
355 }
356
357 pub fn actors_mut(&mut self) -> impl Iterator<Item = &mut dyn Actor<R>> {
359 self.creatures_mut().map(|e| e as &mut dyn Actor<R>)
360 }
361
362 pub fn actor(&self, id: &EntityId<R>) -> Option<&dyn Actor<R>> {
364 match id {
365 EntityId::Creature(id) => self.creature(id).map(|e| e as &dyn Actor<R>),
366 EntityId::Object(_) => None,
367 }
368 }
369
370 pub fn actor_mut(&mut self, id: &EntityId<R>) -> Option<&mut dyn Actor<R>> {
372 match id {
373 EntityId::Creature(id) => self.creature_mut(id).map(|e| e as &mut dyn Actor<R>),
374 EntityId::Object(_) => None,
375 }
376 }
377
378 pub(crate) fn update_relations(&mut self, relations: Vec<(RelationshipPair<R>, Relation)>) {
381 for (pair, relation) in relations {
382 self.relations.insert(pair, relation);
383 }
384 }
385
386 pub fn relation(&self, first: &TeamId<R>, second: &TeamId<R>) -> Option<Relation> {
390 if first == second {
391 Some(Relation::Kin)
392 } else {
393 self.relations
394 .get(&RelationshipPair::new(first.clone(), second.clone()))
395 .copied()
396 }
397 }
398
399 pub fn allies_id<'a>(&'a self, id: &'a TeamId<R>) -> impl Iterator<Item = TeamId<R>> + 'a {
401 self.relations
402 .iter()
403 .filter(move |&(k, _)| k.first == *id || k.second == *id)
404 .filter(|&(_, v)| *v == Relation::Ally)
405 .map(|(k, _)| k.values())
406 .flatten()
407 .filter(move |v| v != id)
408 }
409
410 pub fn allies<'a>(&'a self, id: &'a TeamId<R>) -> impl Iterator<Item = &Team<R>> + 'a {
412 self.allies_id(id).map(move |id| self.team(&id).unwrap())
413 }
414
415 pub fn enemies_id<'a>(&'a self, id: &'a TeamId<R>) -> impl Iterator<Item = TeamId<R>> + 'a {
417 self.relations
418 .iter()
419 .filter(move |&(k, _)| k.first == *id || k.second == *id)
420 .filter(|&(_, v)| *v == Relation::Enemy)
421 .map(|(k, _)| k.values())
422 .flatten()
423 .filter(move |v| v != id)
424 }
425
426 pub fn enemies<'a>(&'a self, id: &'a TeamId<R>) -> impl Iterator<Item = &Team<R>> + 'a {
428 self.enemies_id(id).map(move |id| self.team(&id).unwrap())
429 }
430
431 pub fn victorious(&self) -> impl Iterator<Item = &Team<R>> {
433 self.teams
434 .values()
435 .filter(|&team| team.conclusion() == Some(Conclusion::Victory))
436 }
437
438 pub fn victorious_id(&self) -> impl Iterator<Item = TeamId<R>> + '_ {
440 self.victorious().map(|team| team.id().clone())
441 }
442
443 pub fn defeated(&self) -> impl Iterator<Item = &Team<R>> {
445 self.teams
446 .values()
447 .filter(|&team| team.conclusion() == Some(Conclusion::Defeat))
448 }
449
450 pub fn defeated_id(&self) -> impl Iterator<Item = TeamId<R>> + '_ {
452 self.defeated().map(|team| team.id().clone())
453 }
454
455 pub(crate) fn remove_creature(&mut self, id: &CreatureId<R>) -> WeaselResult<Creature<R>, R> {
459 let creature = self
461 .creatures
462 .remove(id)
463 .ok_or_else(|| WeaselError::CreatureNotFound(id.clone()))?;
464 let team = self
466 .teams
467 .get_mut(creature.team_id())
468 .ok_or_else(|| WeaselError::TeamNotFound(creature.team_id().clone()))?;
469 team.remove_creature(id);
470 Ok(creature)
471 }
472
473 pub(crate) fn convert_creature(
475 &mut self,
476 creature_id: &CreatureId<R>,
477 team_id: &TeamId<R>,
478 ) -> WeaselResult<(), R> {
479 let creature = self
480 .creatures
481 .get_mut(creature_id)
482 .ok_or_else(|| WeaselError::CreatureNotFound(creature_id.clone()))?;
483 let current_team_id = creature.team_id().clone();
484 let current_team = self
486 .teams
487 .get_mut(¤t_team_id)
488 .ok_or(WeaselError::TeamNotFound(current_team_id))?;
489 current_team.remove_creature(creature_id);
490 let new_team = self
492 .teams
493 .get_mut(team_id)
494 .ok_or_else(|| WeaselError::TeamNotFound(team_id.clone()))?;
495 new_team.creatures_mut().push(creature_id.clone());
496 creature.set_team_id(team_id.clone());
498 Ok(())
499 }
500
501 pub(crate) fn remove_object(&mut self, id: &ObjectId<R>) -> WeaselResult<Object<R>, R> {
505 let object = self
507 .objects
508 .remove(id)
509 .ok_or_else(|| WeaselError::ObjectNotFound(id.clone()))?;
510 Ok(object)
511 }
512
513 pub(crate) fn remove_team(&mut self, id: &TeamId<R>) -> WeaselResult<Team<R>, R> {
517 let team = self
519 .teams
520 .get(id)
521 .ok_or_else(|| WeaselError::TeamNotFound(id.clone()))?;
522 if team.creatures().peekable().peek().is_some() {
523 return Err(WeaselError::TeamNotEmpty(id.clone()));
524 }
525 let team = self
527 .teams
528 .remove(id)
529 .ok_or_else(|| WeaselError::TeamNotFound(id.clone()))?;
530 Ok(team)
531 }
532}
533
534pub struct RemoveEntity<R> {
562 _phantom: PhantomData<R>,
563}
564
565impl<R: BattleRules> RemoveEntity<R> {
566 pub fn trigger<P: EventProcessor<R>>(
568 processor: &mut P,
569 id: EntityId<R>,
570 ) -> RemoveEntityTrigger<R, P> {
571 RemoveEntityTrigger { processor, id }
572 }
573}
574
575pub struct RemoveEntityTrigger<'a, R, P>
577where
578 R: BattleRules,
579 P: EventProcessor<R>,
580{
581 processor: &'a mut P,
582 id: EntityId<R>,
583}
584
585impl<'a, R, P> EventTrigger<'a, R, P> for RemoveEntityTrigger<'a, R, P>
586where
587 R: BattleRules + 'static,
588 P: EventProcessor<R>,
589{
590 fn processor(&'a mut self) -> &'a mut P {
591 self.processor
592 }
593
594 fn event(&self) -> Box<dyn Event<R> + Send> {
596 match &self.id {
597 EntityId::Creature(id) => RemoveCreature::trigger(&mut (), id.clone()).event(),
598 EntityId::Object(id) => RemoveObject::trigger(&mut (), id.clone()).event(),
599 }
600 }
601}
602
603#[cfg(test)]
604mod tests {
605 use crate::battle::BattleRules;
606 use crate::entity::EntityId;
607 use crate::util::tests::{creature, object, server, team};
608 use crate::{battle_rules, rules::empty::*};
609
610 const TEAM_1_ID: u32 = 1;
611 const TEAM_ERR_ID: u32 = 99;
612 const CREATURE_1_ID: u32 = 1;
613 const CREATURE_2_ID: u32 = 2;
614 const CREATURE_ERR_ID: u32 = 99;
615 const OBJECT_1_ID: u32 = 1;
616 const OBJECT_2_ID: u32 = 2;
617 const OBJECT_ERR_ID: u32 = 99;
618 const ENTITY_C1_ID: EntityId<CustomRules> = EntityId::Creature(CREATURE_1_ID);
619 const ENTITY_O1_ID: EntityId<CustomRules> = EntityId::Object(OBJECT_1_ID);
620 const ENTITY_ERR_ID: EntityId<CustomRules> = EntityId::Creature(CREATURE_ERR_ID);
621
622 battle_rules! {}
623
624 macro_rules! scenario {
626 () => {{
627 let mut server = server(CustomRules::new());
629 team(&mut server, TEAM_1_ID);
631 creature(&mut server, CREATURE_1_ID, TEAM_1_ID, ());
633 creature(&mut server, CREATURE_2_ID, TEAM_1_ID, ());
634 object(&mut server, OBJECT_1_ID, ());
636 object(&mut server, OBJECT_2_ID, ());
637 server
638 }};
639 }
640
641 #[test]
642 fn retrieval_concrete() {
643 let mut server = scenario!();
644 let entities = server.battle.entities_mut();
646 assert_eq!(entities.creatures().count(), 2);
648 assert_eq!(entities.creatures_mut().count(), 2);
649 assert!(entities.creature(&CREATURE_1_ID).is_some());
650 assert!(entities.creature_mut(&CREATURE_1_ID).is_some());
651 assert!(entities.creature(&CREATURE_ERR_ID).is_none());
652 assert!(entities.creature_mut(&CREATURE_ERR_ID).is_none());
653 assert_eq!(entities.objects().count(), 2);
655 assert_eq!(entities.objects_mut().count(), 2);
656 assert!(entities.object(&OBJECT_1_ID).is_some());
657 assert!(entities.object_mut(&OBJECT_2_ID).is_some());
658 assert!(entities.object(&OBJECT_ERR_ID).is_none());
659 assert!(entities.object_mut(&OBJECT_ERR_ID).is_none());
660 assert_eq!(entities.teams().count(), 1);
662 assert_eq!(entities.teams_mut().count(), 1);
663 assert!(entities.team(&TEAM_1_ID).is_some());
664 assert!(entities.team_mut(&TEAM_1_ID).is_some());
665 assert!(entities.team(&TEAM_ERR_ID).is_none());
666 assert!(entities.team_mut(&TEAM_ERR_ID).is_none());
667 }
668
669 #[test]
670 fn retrieval_trait() {
671 let mut server = scenario!();
672 let entities = server.battle.entities_mut();
674 assert_eq!(entities.entities().count(), 4);
676 assert_eq!(entities.entities_mut().count(), 4);
677 assert!(entities.entity(&ENTITY_C1_ID).is_some());
678 assert!(entities.entity_mut(&ENTITY_C1_ID).is_some());
679 assert!(entities.entity(&ENTITY_O1_ID).is_some());
680 assert!(entities.entity_mut(&ENTITY_O1_ID).is_some());
681 assert!(entities.entity(&ENTITY_ERR_ID).is_none());
682 assert!(entities.entity_mut(&ENTITY_ERR_ID).is_none());
683 assert_eq!(entities.characters().count(), 4);
685 assert_eq!(entities.characters_mut().count(), 4);
686 assert!(entities.character(&ENTITY_C1_ID).is_some());
687 assert!(entities.character_mut(&ENTITY_C1_ID).is_some());
688 assert!(entities.character(&ENTITY_O1_ID).is_some());
689 assert!(entities.character_mut(&ENTITY_O1_ID).is_some());
690 assert!(entities.character(&ENTITY_ERR_ID).is_none());
691 assert!(entities.character_mut(&ENTITY_ERR_ID).is_none());
692 assert_eq!(entities.actors().count(), 2);
694 assert_eq!(entities.actors_mut().count(), 2);
695 assert!(entities.actor(&ENTITY_C1_ID).is_some());
696 assert!(entities.actor_mut(&ENTITY_C1_ID).is_some());
697 assert!(entities.actor(&ENTITY_O1_ID).is_none());
698 assert!(entities.actor_mut(&ENTITY_O1_ID).is_none());
699 assert!(entities.actor(&ENTITY_ERR_ID).is_none());
700 assert!(entities.actor_mut(&ENTITY_ERR_ID).is_none());
701 }
702}