1use crate::{client::Client, events::shared::update_map_markers};
2use common::{
3 comp::{
4 self, Agent, Alignment, Behavior, BehaviorCapability, Pet, TradingBehavior, anchor::Anchor,
5 group::GroupManager,
6 },
7 uid::Uid,
8};
9use common_net::msg::ServerGeneral;
10use specs::{Entity, Join, WorldExt};
11use tracing::{error, warn};
12
13pub fn restore_pet(ecs: &specs::World, pet_entity: Entity, owner: Entity, pet: Pet) {
16 tame_pet_internal(ecs, pet_entity, owner, Some(pet));
17}
18
19pub fn tame_pet(ecs: &specs::World, pet_entity: Entity, owner: Entity) {
21 tame_pet_internal(ecs, pet_entity, owner, None);
22}
23
24fn tame_pet_internal(ecs: &specs::World, pet_entity: Entity, owner: Entity, pet: Option<Pet>) {
25 let uids = ecs.read_storage::<Uid>();
26 let (owner_uid, pet_uid) = match (uids.get(owner), uids.get(pet_entity)) {
27 (Some(uid_owner), Some(uid_pet)) => (*uid_owner, *uid_pet),
28 _ => return,
29 };
30 let mut alignments = ecs.write_storage::<Alignment>();
31 let Some(owner_alignment) = alignments.get(owner).copied() else {
32 error!("Owner of a pet must have an Alignment");
33 return;
34 };
35
36 if let Some(Alignment::Owned(existing_owner_uid)) = alignments.get(pet_entity) {
37 if *existing_owner_uid != owner_uid {
38 warn!("Disallowing taming of pet already owned by another entity");
39 return;
40 }
41 }
42
43 if let Alignment::Owned(owner_alignment_uid) = owner_alignment {
44 if owner_alignment_uid != owner_uid {
45 error!("Pets cannot be owners of pets");
46 return;
47 }
48 }
49
50 if (
51 &ecs.entities(),
52 &alignments,
53 ecs.read_storage::<Pet>().mask(),
54 )
55 .join()
56 .any(|(_, alignment, _)| matches!(alignment, Alignment::Owned(uid) if *uid == pet_uid))
57 {
58 error!("Cannot tame entity which owns pets");
59 return;
60 }
61
62 let _ = alignments.insert(pet_entity, common::comp::Alignment::Owned(owner_uid));
63
64 let _ = ecs
68 .write_storage()
69 .insert(pet_entity, Anchor::Entity(owner));
70
71 let _ = ecs
72 .write_storage()
73 .insert(pet_entity, pet.unwrap_or_default());
74
75 if let Some(body) = ecs.read_storage().get(pet_entity) {
77 let mut agent = Agent::from_body(body).with_behavior(
79 Behavior::default().maybe_with_capabilities(Some(BehaviorCapability::TRADE)),
80 );
81 agent.behavior.trading_behavior = TradingBehavior::AcceptFood;
82 agent.psyche.idle_wander_factor = 0.25;
84 agent.psyche.aggro_range_multiplier = 0.25;
85 agent.patrol_origin = None;
86 let _ = ecs.write_storage().insert(pet_entity, agent);
87 }
88
89 let clients = ecs.read_storage::<Client>();
91 let mut group_manager = ecs.write_resource::<GroupManager>();
92 let map_markers = ecs.read_storage::<comp::MapMarker>();
93
94 drop(alignments);
95 group_manager.new_pet(
96 pet_entity,
97 owner,
98 &mut ecs.write_storage(),
99 &ecs.entities(),
100 &ecs.read_storage(),
101 &uids,
102 &mut |entity, group_change| {
103 clients
104 .get(entity)
105 .and_then(|c| {
106 group_change
107 .try_map_ref(|e| uids.get(*e).copied())
108 .map(|g| (g, c))
109 })
110 .map(|(g, c)| {
111 update_map_markers(&map_markers, &uids, c, &group_change);
114 c.send_fallible(ServerGeneral::GroupUpdate(g));
115 });
116 },
117 );
118}