Skip to main content

flatland_presentation/
player_states.rs

1//! Canonical player presentation keys for gfx `sprite_modes` (designer-facing).
2
3/// Standard presentation keys shown in content-admin and used on the wire.
4pub const PLAYER_PRESENTATION_STATES: &[(&str, &str)] = &[
5    ("combat", "Combat — in melee range or casting"),
6    ("pursue", "Pursue — has target, out of attack range"),
7    ("sprinting", "Sprinting — fast movement"),
8    ("walking", "Walking — normal movement"),
9    ("harvesting", "Harvesting — gathering a resource node"),
10    ("crafting", "Crafting — timed blueprint craft"),
11    ("talking", "Talking — open NPC conversation"),
12    ("chatting", "Chatting — recent nearby / whisper-stone chat"),
13    ("idle", "Idle — stationary"),
14];
15
16/// Inputs for player presentation (keeps this crate free of sim types).
17#[derive(Debug, Clone, Copy)]
18pub struct PlayerPresentationInput {
19    pub harvesting: bool,
20    pub crafting: bool,
21    pub talking: bool,
22    pub chatting: bool,
23    pub in_combat: bool,
24    pub pursue: bool,
25    pub in_attack_range: bool,
26    pub is_moving: bool,
27    pub sprinting: bool,
28}
29
30pub fn resolve_player_presentation_key(input: PlayerPresentationInput) -> &'static str {
31    if input.harvesting {
32        return "harvesting";
33    }
34    if input.crafting {
35        return "crafting";
36    }
37    if input.talking {
38        return "talking";
39    }
40    if input.chatting {
41        return "chatting";
42    }
43    if input.in_combat && input.in_attack_range {
44        return "combat";
45    }
46    if input.pursue || (input.in_combat && !input.in_attack_range) {
47        return "pursue";
48    }
49    if input.in_combat {
50        return "combat";
51    }
52    if input.is_moving && input.sprinting {
53        return "sprinting";
54    }
55    if input.is_moving {
56        return "walking";
57    }
58    "idle"
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn player_harvesting_wins() {
67        let key = resolve_player_presentation_key(PlayerPresentationInput {
68            harvesting: true,
69            crafting: false,
70            talking: false,
71            chatting: false,
72            in_combat: true,
73            pursue: false,
74            in_attack_range: true,
75            is_moving: true,
76            sprinting: true,
77        });
78        assert_eq!(key, "harvesting");
79    }
80
81    #[test]
82    fn player_talking_over_walking() {
83        let key = resolve_player_presentation_key(PlayerPresentationInput {
84            harvesting: false,
85            crafting: false,
86            talking: true,
87            chatting: false,
88            in_combat: false,
89            pursue: false,
90            in_attack_range: false,
91            is_moving: true,
92            sprinting: false,
93        });
94        assert_eq!(key, "talking");
95    }
96
97    #[test]
98    fn player_pursue_out_of_range() {
99        let key = resolve_player_presentation_key(PlayerPresentationInput {
100            harvesting: false,
101            crafting: false,
102            talking: false,
103            chatting: false,
104            in_combat: true,
105            pursue: false,
106            in_attack_range: false,
107            is_moving: true,
108            sprinting: true,
109        });
110        assert_eq!(key, "pursue");
111    }
112}