veloren_common/comp/
loot_owner.rs

1use crate::{
2    comp::{Alignment, Body, Group, Player},
3    uid::Uid,
4};
5use serde::{Deserialize, Serialize};
6use specs::{Component, DerefFlaggedStorage};
7use std::{
8    ops::Add,
9    time::{Duration, Instant},
10};
11
12#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
13pub struct LootOwner {
14    // TODO: Fix this if expiry is needed client-side, Instant is not serializable
15    #[serde(skip, default = "Instant::now")]
16    expiry: Instant,
17    owner: LootOwnerKind,
18    soft: bool,
19}
20
21// Loot becomes free-for-all after the initial ownership period
22const OWNERSHIP_SECS: u64 = 45;
23
24impl LootOwner {
25    pub fn new(kind: LootOwnerKind, soft: bool) -> Self {
26        Self {
27            expiry: Instant::now().add(Duration::from_secs(OWNERSHIP_SECS)),
28            owner: kind,
29            soft,
30        }
31    }
32
33    pub fn uid(&self) -> Option<Uid> {
34        match &self.owner {
35            LootOwnerKind::Player(uid) => Some(*uid),
36            LootOwnerKind::Group(_) => None,
37        }
38    }
39
40    pub fn owner(&self) -> LootOwnerKind { self.owner }
41
42    pub fn time_until_expiration(&self) -> Duration { self.expiry - Instant::now() }
43
44    pub fn expired(&self) -> bool { self.expiry <= Instant::now() }
45
46    pub fn default_instant() -> Instant { Instant::now() }
47
48    /// This field stands as a wish for NPC's to not pick the loot up, they will
49    /// however be able to decide whether they want to follow your wishes or not
50    /// (players will be able to pick the item up)
51    pub fn is_soft(&self) -> bool { self.soft }
52
53    pub fn can_pickup(
54        &self,
55        uid: Uid,
56        group: Option<&Group>,
57        alignment: Option<&Alignment>,
58        body: Option<&Body>,
59        player: Option<&Player>,
60    ) -> bool {
61        let is_owned = matches!(alignment, Some(Alignment::Owned(_)));
62        let is_player = player.is_some();
63        let is_pet = is_owned && !is_player;
64
65        let owns_loot = match self.owner {
66            LootOwnerKind::Player(loot_uid) => loot_uid.0 == uid.0,
67            LootOwnerKind::Group(loot_group) => {
68                matches!(group, Some(group) if loot_group == *group)
69            },
70        };
71        let is_humanoid = matches!(body, Some(Body::Humanoid(_)));
72
73        // Pet's can't pick up owned loot
74        // Humanoids must own the loot
75        // Non-humanoids ignore loot ownership
76        !is_pet && (self.soft || owns_loot || !is_humanoid)
77    }
78}
79
80impl Component for LootOwner {
81    type Storage = DerefFlaggedStorage<Self, specs::DenseVecStorage<Self>>;
82}
83
84#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub enum LootOwnerKind {
86    Player(Uid),
87    Group(Group),
88}