pub const PLAYER_DIRECTIONAL_BASE_MODES: &[&str] = &["idle", "walk", "run"];
pub fn cardinal_facing_label(yaw: f32) -> &'static str {
let deg = yaw.to_degrees().rem_euclid(360.0);
if (45.0..135.0).contains(°) {
"east"
} else if (135.0..225.0).contains(°) {
"south"
} else if (225.0..315.0).contains(°) {
"west"
} else {
"north"
}
}
pub fn base_sprite_mode(mode: &str) -> &str {
for suffix in ["_north", "_east", "_south", "_west"] {
if let Some(base) = mode.strip_suffix(suffix) {
return base;
}
}
mode
}
pub fn sheet_has_mode(sheet_modes: &[String], mode: &str) -> bool {
if sheet_modes.iter().any(|m| m == mode) {
return true;
}
let prefix = format!("{mode}_");
sheet_modes.iter().any(|m| m.starts_with(&prefix))
}
pub fn expand_directional_draw_mode(
sheet_modes: &[String],
base_mode: &str,
facing_yaw: f32,
) -> String {
let base = base_sprite_mode(base_mode);
if !PLAYER_DIRECTIONAL_BASE_MODES.contains(&base) {
return base.to_string();
}
let directional = format!("{}_{}", base, cardinal_facing_label(facing_yaw));
if sheet_has_mode(sheet_modes, &directional) {
directional
} else {
base.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn modes(ids: &[&str]) -> Vec<String> {
ids.iter().map(|s| s.to_string()).collect()
}
#[test]
fn cardinal_facing_label_bins() {
assert_eq!(cardinal_facing_label(0.0), "north");
assert_eq!(cardinal_facing_label(std::f32::consts::FRAC_PI_2), "east");
assert_eq!(cardinal_facing_label(std::f32::consts::PI), "south");
}
#[test]
fn base_sprite_mode_strips_suffix() {
assert_eq!(base_sprite_mode("walk_north"), "walk");
assert_eq!(base_sprite_mode("idle"), "idle");
}
#[test]
fn expand_directional_when_sheet_has_variant() {
let sheet = modes(&["idle_north", "walk_north", "walk_east", "combat"]);
assert_eq!(
expand_directional_draw_mode(&sheet, "walk", 0.0),
"walk_north"
);
assert_eq!(
expand_directional_draw_mode(&sheet, "walk", std::f32::consts::FRAC_PI_2),
"walk_east"
);
assert_eq!(expand_directional_draw_mode(&sheet, "combat", 0.0), "combat");
}
#[test]
fn expand_falls_back_to_base_without_directional() {
let sheet = modes(&["walk", "idle"]);
assert_eq!(expand_directional_draw_mode(&sheet, "walk", 0.0), "walk");
}
}