weasel/
entity.rs

1//! Module for entities and their storage.
2
3use 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
20/// An entity represents any being existing in the game world.
21pub trait Entity<R: BattleRules> {
22    /// Returns the id of this entity.
23    fn entity_id(&self) -> &EntityId<R>;
24
25    /// Returns this entity position.
26    fn position(&self) -> &Position<R>;
27
28    /// Sets a new position for this entity.
29    fn set_position(&mut self, position: Position<R>);
30}
31
32/// Id to uniquely identify an entity.
33/// `EntityId` is used as global id to identify entities in the game world
34/// regardless of their type.
35#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
36pub enum EntityId<R: BattleRules> {
37    /// Standard creature.
38    #[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    /// Inanimate object.
47    #[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    /// Returns whether this entity id refers to an object that satisfies the `Character` trait.
59    pub fn is_character(&self) -> bool {
60        match self {
61            Self::Creature(_) => true,
62            Self::Object(_) => true,
63        }
64    }
65
66    /// Returns whether this entity id refers to an object that satisfies the `Actor` trait.
67    pub fn is_actor(&self) -> bool {
68        match self {
69            Self::Creature(_) => true,
70            Self::Object(_) => false,
71        }
72    }
73
74    /// Extracts a creature id out of this entity id.
75    ///
76    /// Returns an error if the entity id's type is not `Creature`.
77    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    /// Extracts an object id out of this entity id.
85    ///
86    /// Returns an error if the entity id's type is not `Object`.
87    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
159/// Represents a change to an entity's existence.
160pub enum Transmutation {
161    /// Entity entirely removed from the battle.
162    REMOVAL,
163}
164
165/// Triggers an event to transmute an entity.
166pub(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
186/// Data structure to manage ownership of teams and entities.
187pub 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    /// Returns an iterator over creatures.
205    pub fn creatures(&self) -> impl Iterator<Item = &Creature<R>> {
206        self.creatures.values()
207    }
208
209    /// Returns a mutable iterator over creatures.
210    pub fn creatures_mut(&mut self) -> impl Iterator<Item = &mut Creature<R>> {
211        self.creatures.values_mut()
212    }
213
214    /// Returns the creature with the given id.
215    pub fn creature(&self, id: &CreatureId<R>) -> Option<&Creature<R>> {
216        self.creatures.get(id)
217    }
218
219    /// Returns a mutable reference to the creature with the given id.
220    pub fn creature_mut(&mut self, id: &CreatureId<R>) -> Option<&mut Creature<R>> {
221        self.creatures.get_mut(id)
222    }
223
224    /// Returns an iterator over objects.
225    pub fn objects(&self) -> impl Iterator<Item = &Object<R>> {
226        self.objects.values()
227    }
228
229    /// Returns a mutable iterator over objects.
230    pub fn objects_mut(&mut self) -> impl Iterator<Item = &mut Object<R>> {
231        self.objects.values_mut()
232    }
233
234    /// Returns the object with the given id.
235    pub fn object(&self, id: &ObjectId<R>) -> Option<&Object<R>> {
236        self.objects.get(id)
237    }
238
239    /// Returns a mutable reference to the object with the given id.
240    pub fn object_mut(&mut self, id: &ObjectId<R>) -> Option<&mut Object<R>> {
241        self.objects.get_mut(id)
242    }
243
244    /// Returns an iterator over teams.
245    pub fn teams(&self) -> impl Iterator<Item = &Team<R>> {
246        self.teams.values()
247    }
248
249    /// Returns a mutable iterator over teams.
250    pub fn teams_mut(&mut self) -> impl Iterator<Item = &mut Team<R>> {
251        self.teams.values_mut()
252    }
253
254    /// Returns the team with the given id.
255    pub fn team(&self, id: &TeamId<R>) -> Option<&Team<R>> {
256        self.teams.get(id)
257    }
258
259    /// Returns a mutable reference to the team with the given id.
260    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        // Update team's creature list.
270        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        // Insert the creature.
276        self.creatures.insert(creature.id().clone(), creature);
277        Ok(())
278    }
279
280    pub(crate) fn add_object(&mut self, object: Object<R>) {
281        // Insert the object.
282        self.objects.insert(object.id().clone(), object);
283    }
284
285    /// Returns an iterator over entities.
286    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    /// Returns a mutable iterator over entities.
294    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    /// Returns the entity with the given id.
302    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    /// Returns a mutable reference to the entity with the given id.
310    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    /// Returns an iterator over characters.
318    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    /// Returns a mutable iterator over characters.
325    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    /// Returns the character with the given id.
337    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    /// Returns a mutable reference to the character with the given id.
345    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    /// Returns an iterator over actors.
353    pub fn actors(&self) -> impl Iterator<Item = &dyn Actor<R>> {
354        self.creatures().map(|e| e as &dyn Actor<R>)
355    }
356
357    /// Returns a mutable iterator over actors.
358    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    /// Returns the character with the given id.
363    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    /// Returns a mutable reference to the actor with the given id.
371    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    /// Updates current relations by merging them with `new_relations`.
379    /// Existing relations are overridden.
380    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    /// Returns the `Relation` between two teams. Relations are symmetric.
387    ///
388    /// The relation of a team towards itself is `Kin`.
389    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    /// Returns all allied teams' id of a team.
400    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    /// Returns all allied teams of a team.
411    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    /// Returns all enemy teams' id of a team.
416    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    /// Returns all enemy teams of a team.
427    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    /// Returns all victorious teams.
432    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    /// Returns the id of all victorious teams.
439    pub fn victorious_id(&self) -> impl Iterator<Item = TeamId<R>> + '_ {
440        self.victorious().map(|team| team.id().clone())
441    }
442
443    /// Returns all defeated teams.
444    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    /// Returns the id of all defeated teams.
451    pub fn defeated_id(&self) -> impl Iterator<Item = TeamId<R>> + '_ {
452        self.defeated().map(|team| team.id().clone())
453    }
454
455    /// Removes a creature from the battle. The creature must exist.
456    ///
457    /// Returns the removed creature.
458    pub(crate) fn remove_creature(&mut self, id: &CreatureId<R>) -> WeaselResult<Creature<R>, R> {
459        // Extract the creature.
460        let creature = self
461            .creatures
462            .remove(id)
463            .ok_or_else(|| WeaselError::CreatureNotFound(id.clone()))?;
464        // Remove the creature's id from the team list of creatures.
465        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    /// Changes a creature's team.
474    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        // Change the original team's creature lists.
485        let current_team = self
486            .teams
487            .get_mut(&current_team_id)
488            .ok_or(WeaselError::TeamNotFound(current_team_id))?;
489        current_team.remove_creature(creature_id);
490        // Change the new team's creature lists.
491        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        // Change the creature's team.
497        creature.set_team_id(team_id.clone());
498        Ok(())
499    }
500
501    /// Removes an object from the battle. The object must exist.
502    ///
503    /// Returns the removed object.
504    pub(crate) fn remove_object(&mut self, id: &ObjectId<R>) -> WeaselResult<Object<R>, R> {
505        // Extract the object.
506        let object = self
507            .objects
508            .remove(id)
509            .ok_or_else(|| WeaselError::ObjectNotFound(id.clone()))?;
510        Ok(object)
511    }
512
513    /// Removes a team from the battle. The team must exist and be empty.
514    ///
515    /// Returns the removed team.
516    pub(crate) fn remove_team(&mut self, id: &TeamId<R>) -> WeaselResult<Team<R>, R> {
517        // Check preconditions.
518        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        // Extract the team.
526        let team = self
527            .teams
528            .remove(id)
529            .ok_or_else(|| WeaselError::TeamNotFound(id.clone()))?;
530        Ok(team)
531    }
532}
533
534/// Helper to get an event trigger capable of removing an entity from the battle.\
535/// It delegates the actual work to a `RemoveCreature` or a `RemoveObject`.
536///
537/// # Examples
538/// ```
539/// use weasel::{
540///     battle_rules, rules::empty::*, Battle, BattleController, BattleRules, CreateCreature,
541///     CreateTeam, EntityId, EventTrigger, RemoveEntity, Server,
542/// };
543///
544/// battle_rules! {}
545///
546/// let battle = Battle::builder(CustomRules::new()).build();
547/// let mut server = Server::builder(battle).build();
548///
549/// let team_id = 1;
550/// CreateTeam::trigger(&mut server, team_id).fire().unwrap();
551/// let creature_id = 1;
552/// let entity_id = EntityId::Creature(creature_id);
553/// let position = ();
554/// CreateCreature::trigger(&mut server, creature_id, team_id, position)
555///     .fire()
556///     .unwrap();
557///
558/// RemoveEntity::trigger(&mut server, entity_id).fire().unwrap();
559/// assert_eq!(server.battle().entities().creatures().count(), 0);
560/// ```
561pub struct RemoveEntity<R> {
562    _phantom: PhantomData<R>,
563}
564
565impl<R: BattleRules> RemoveEntity<R> {
566    /// Returns a trigger for this event helper.
567    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
575/// Trigger to build and a fire the correct event to remove an entity.
576pub 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    /// Returns the event able to remove the entity.
595    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    /// Creates a scenario with two creatures and two objects.
625    macro_rules! scenario {
626        () => {{
627            // Create the battle.
628            let mut server = server(CustomRules::new());
629            // Create a team.
630            team(&mut server, TEAM_1_ID);
631            // Create two creatures.
632            creature(&mut server, CREATURE_1_ID, TEAM_1_ID, ());
633            creature(&mut server, CREATURE_2_ID, TEAM_1_ID, ());
634            // Create two objects.
635            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        // Get a mutable reference to entities.
645        let entities = server.battle.entities_mut();
646        // Creatures.
647        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        // Objects.
654        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        // Teams.
661        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        // Get a mutable reference to entities.
673        let entities = server.battle.entities_mut();
674        // Entities.
675        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        // Characters.
684        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        // Actors.
693        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}