Skip to main content

dreamwell_engine/input/
action.rs

1// InputAction — platform-independent game actions.
2// Decouples "what the player wants to do" from "which key they pressed".
3
4/// A game action produced by the input system. Platform-agnostic.
5/// Consumed by game logic (movement, combat, UI) without knowing the source device.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum InputAction {
8    // Movement
9    MoveForward,
10    MoveBackward,
11    MoveLeft,
12    MoveRight,
13    MoveUp,
14    MoveDown,
15    Sprint,
16    Crouch,
17    Jump,
18
19    // Camera
20    CameraRotate,
21    CameraPan,
22    CameraZoomIn,
23    CameraZoomOut,
24    CameraReset,
25
26    // Interaction
27    PrimaryAction,
28    SecondaryAction,
29    Interact,
30    Cancel,
31    Confirm,
32
33    // UI
34    OpenInventory,
35    OpenMap,
36    OpenChat,
37    OpenMenu,
38    ToggleFullscreen,
39    QuickSlot(u8),
40
41    // Combat
42    Attack,
43    Block,
44    Dodge,
45    UseAbility(u8),
46
47    // System
48    Pause,
49    Screenshot,
50}
51
52/// Input mode determines which bindings and camera behavior are active.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
54pub enum InputMode {
55    /// 2D tile-based: WASD moves on grid, scroll zooms, no rotation.
56    #[default]
57    TileMap,
58    /// 3D free camera: WASD moves in camera-relative direction, mouse rotates.
59    FreeCamera,
60    /// UI focus: keyboard goes to text fields/menus, movement suppressed.
61    UiFocus,
62    /// Cinematic: input suppressed, camera follows scripted path.
63    Cinematic,
64}
65
66impl InputMode {
67    /// Whether WASD movement keys should produce movement actions.
68    pub fn movement_enabled(&self) -> bool {
69        matches!(self, Self::TileMap | Self::FreeCamera)
70    }
71
72    /// Whether mouse/stick rotation should produce camera rotation.
73    pub fn camera_rotation_enabled(&self) -> bool {
74        matches!(self, Self::FreeCamera)
75    }
76
77    /// Whether keyboard input should be routed to UI text fields.
78    pub fn ui_capture(&self) -> bool {
79        matches!(self, Self::UiFocus)
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn input_mode_defaults_to_tilemap() {
89        assert_eq!(InputMode::default(), InputMode::TileMap);
90    }
91
92    #[test]
93    fn movement_enabled_modes() {
94        assert!(InputMode::TileMap.movement_enabled());
95        assert!(InputMode::FreeCamera.movement_enabled());
96        assert!(!InputMode::UiFocus.movement_enabled());
97        assert!(!InputMode::Cinematic.movement_enabled());
98    }
99
100    #[test]
101    fn camera_rotation_only_free_camera() {
102        assert!(!InputMode::TileMap.camera_rotation_enabled());
103        assert!(InputMode::FreeCamera.camera_rotation_enabled());
104        assert!(!InputMode::UiFocus.camera_rotation_enabled());
105    }
106
107    #[test]
108    fn ui_capture_only_ui_focus() {
109        assert!(!InputMode::TileMap.ui_capture());
110        assert!(!InputMode::FreeCamera.ui_capture());
111        assert!(InputMode::UiFocus.ui_capture());
112        assert!(!InputMode::Cinematic.ui_capture());
113    }
114
115    #[test]
116    fn input_action_quick_slot() {
117        let a = InputAction::QuickSlot(0);
118        let b = InputAction::QuickSlot(1);
119        assert_ne!(a, b);
120    }
121
122    #[test]
123    fn input_action_use_ability() {
124        let a = InputAction::UseAbility(0);
125        let b = InputAction::UseAbility(3);
126        assert_ne!(a, b);
127    }
128}