1#[cfg(feature = "chumsky")]
4use chumsky::{IterParser as _, Parser, text::digits};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
8#[expect(
9 clippy::module_name_repetitions,
10 reason = "this type is used outside of this module"
11)]
12pub struct ChatChannel(pub i32);
13
14#[cfg(feature = "chumsky")]
20#[must_use]
21#[expect(
22 clippy::module_name_repetitions,
23 reason = "this parser is used outside of this module"
24)]
25pub fn chat_channel_parser<'src>()
26-> impl Parser<'src, &'src str, ChatChannel, chumsky::extra::Err<chumsky::error::Rich<'src, char>>>
27{
28 digits(10).collect::<String>().try_map(|d, span| {
29 let d: i32 = d
30 .parse()
31 .map_err(|e| chumsky::error::Rich::custom(span, format!("{e:?}")))?;
32 Ok(ChatChannel(d))
33 })
34}
35
36impl std::fmt::Display for ChatChannel {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}", self.0)
39 }
40}
41
42impl std::str::FromStr for ChatChannel {
43 type Err = <i32 as std::str::FromStr>::Err;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 <i32 as std::str::FromStr>::from_str(s).map(ChatChannel)
47 }
48}
49
50pub const PUBLIC_CHANNEL: ChatChannel = ChatChannel(0);
52
53pub const COMBAT_CHANNEL: ChatChannel = ChatChannel(0x7FFF_FFFE);
55
56pub const DEBUG_CHANNEL: ChatChannel = ChatChannel(0x7FFF_FFFF);
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, strum::EnumIs)]
61#[expect(
62 clippy::module_name_repetitions,
63 reason = "this type is used outside of this module"
64)]
65pub enum ChatVolume {
66 Whisper,
68 Say,
70 Shout,
72 RegionSay,
74}
75
76impl ChatVolume {
77 #[must_use]
79 pub fn volume_and_message(s: String) -> (Self, String) {
80 if let Some(whisper_message) = s.strip_prefix("whispers: ") {
81 (Self::Whisper, whisper_message.to_string())
82 } else if let Some(shout_message) = s.strip_prefix("shouts: ") {
83 (Self::Shout, shout_message.to_string())
84 } else {
85 (Self::Say, s)
86 }
87 }
88}