use super::UserMessage;
use crate::bitbuf::BitWriter;
use crate::math::Color32;
use crate::net::EncodeError;
use std::ffi::CStr;
const FADE_FRACTION_BITS: u32 = 9;
#[doc(alias("ScreenFade_t", "UTIL_ScreenFade", "env_fade"))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Fade {
pub duration: f32,
#[doc(alias("holdTime"))]
pub hold: f32,
#[doc(alias("fadeFlags"))]
pub flags: FadeFlags,
pub color: Color32,
}
impl UserMessage for Fade {
fn name(&self) -> &CStr {
c"Fade"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u16(fade_time(self.duration));
out.write_u16(fade_time(self.hold));
out.write_u16(self.flags.bits());
out.write_u8(self.color.r);
out.write_u8(self.color.g);
out.write_u8(self.color.b);
out.write_u8(self.color.a);
Ok(())
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct FadeFlags: u16 {
#[doc(alias("FFADE_IN"))]
const IN = 0x1;
#[doc(alias("FFADE_MODULATE"))]
const MODULATE = 0x4;
#[doc(alias("FFADE_OUT"))]
const OUT = 0x2;
#[doc(alias("FFADE_PURGE"))]
const PURGE = 0x10;
#[doc(alias("FFADE_STAYOUT"))]
const STAY_OUT = 0x8;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HintText<'a> {
pub text: &'a CStr,
}
impl UserMessage for HintText<'_> {
fn name(&self) -> &CStr {
c"HintText"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_cstr(self.text);
Ok(())
}
}
#[doc(alias("HudMsg", "game_text", "hudtextparms_t", "UTIL_HudMessage"))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct HudText<'a> {
pub channel: u8,
pub x: f32,
pub y: f32,
pub color: Color32,
pub effect_color: Color32,
pub effect: HudTextEffect,
#[doc(alias("fadeinTime"))]
pub fade_in: f32,
#[doc(alias("fadeoutTime"))]
pub fade_out: f32,
#[doc(alias("holdTime"))]
pub hold: f32,
#[doc(alias("fxTime"))]
pub effect_time: f32,
pub text: &'a CStr,
}
impl UserMessage for HudText<'_> {
fn name(&self) -> &CStr {
c"HudMsg"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u8(self.channel);
out.write_f32(self.x);
out.write_f32(self.y);
for color in [self.color, self.effect_color] {
out.write_u8(color.r);
out.write_u8(color.g);
out.write_u8(color.b);
out.write_u8(color.a);
}
out.write_u8(self.effect as u8);
out.write_f32(self.fade_in);
out.write_f32(self.fade_out);
out.write_f32(self.hold);
out.write_f32(self.effect_time);
out.write_cstr(self.text);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[repr(u8)]
pub enum HudTextEffect {
#[default]
Fade = 0,
Flicker = 1,
ScanOut = 2,
}
#[doc(alias("env_hudhint", "UTIL_HudHintText"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KeyHintText<'a> {
pub text: &'a CStr,
}
impl UserMessage for KeyHintText<'_> {
fn name(&self) -> &CStr {
c"KeyHintText"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u8(1);
out.write_cstr(self.text);
Ok(())
}
}
#[doc(alias("UTIL_SayText2Filter"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SayText2<'a> {
pub speaker: u8,
pub chat: bool,
pub message: &'a CStr,
pub arguments: [&'a CStr; 4],
}
impl UserMessage for SayText2<'_> {
fn name(&self) -> &CStr {
c"SayText2"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u8(self.speaker);
out.write_u8(self.chat.into());
out.write_cstr(self.message);
for argument in self.arguments {
out.write_cstr(argument);
}
Ok(())
}
}
#[doc(alias("ScreenShake_t", "UTIL_ScreenShake", "env_shake"))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Shake {
pub command: ShakeCommand,
pub amplitude: f32,
pub frequency: f32,
pub duration: f32,
}
impl UserMessage for Shake {
fn name(&self) -> &CStr {
c"Shake"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u8(self.command as u8);
out.write_f32(self.amplitude);
out.write_f32(self.frequency);
out.write_f32(self.duration);
Ok(())
}
}
#[doc(alias("ShakeCommand_t"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum ShakeCommand {
#[doc(alias("SHAKE_START"))]
Start = 0,
#[doc(alias("SHAKE_STOP"))]
Stop = 1,
#[doc(alias("SHAKE_AMPLITUDE"))]
Amplitude = 2,
#[doc(alias("SHAKE_FREQUENCY"))]
Frequency = 3,
#[doc(alias("SHAKE_START_RUMBLEONLY"))]
StartRumbleOnly = 4,
#[doc(alias("SHAKE_START_NORUMBLE"))]
StartNoRumble = 5,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum TextDestination {
#[doc(alias("HUD_PRINTNOTIFY"))]
Notify = 1,
#[doc(alias("HUD_PRINTCONSOLE"))]
Console = 2,
#[doc(alias("HUD_PRINTTALK"))]
Chat = 3,
#[doc(alias("HUD_PRINTCENTER"))]
Center = 4,
}
#[doc(alias("ClientPrint", "UTIL_ClientPrintFilter"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TextMsg<'a> {
pub destination: TextDestination,
pub message: &'a CStr,
pub arguments: [&'a CStr; 4],
}
impl UserMessage for TextMsg<'_> {
fn name(&self) -> &CStr {
c"TextMsg"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
out.write_u8(self.destination as u8);
out.write_cstr(self.message);
for argument in self.arguments {
out.write_cstr(argument);
}
Ok(())
}
}
#[doc(alias("VGUIMenu", "ShowViewPortPanel"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VguiMenu<'a> {
pub name: &'a CStr,
pub show: bool,
pub keys: &'a [(&'a CStr, &'a CStr)],
}
impl UserMessage for VguiMenu<'_> {
fn name(&self) -> &CStr {
c"VGUIMenu"
}
fn write(&self, out: &mut BitWriter) -> Result<(), EncodeError> {
let count = u8::try_from(self.keys.len()).map_err(|_| EncodeError::OutOfRange {
field: "key count",
value: self.keys.len() as u64,
max: u8::MAX.into(),
})?;
out.write_cstr(self.name);
out.write_u8(self.show.into());
out.write_u8(count);
for &(key, value) in self.keys {
out.write_cstr(key);
out.write_cstr(value);
}
Ok(())
}
}
fn fade_time(seconds: f32) -> u16 {
(seconds * (1 << FADE_FRACTION_BITS) as f32).clamp(0.0, u16::MAX.into()) as u16
}