diff --git a/CHANGELOG.md b/CHANGELOG.md index f2deec77f2..9d59b08a17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Unlockable door blocks. - Sprite rotation for Spots. - Better entity placement options for spots. +- Camera zoom can now be locked, to prevent accidental zooming while rolling in combat. It comes + with a keybind to enable/disable the setting, and an Auto/Toggle behavior setting. Auto behavior + will only lock the camera zoom while movement and combat inputs are also being pressed. ### Changed - Bats move slower and use a simple proportional controller to maintain altitude diff --git a/assets/voxygen/i18n/de_DE/gameinput.ftl b/assets/voxygen/i18n/de_DE/gameinput.ftl index 00f8f0d167..70e99afb84 100644 --- a/assets/voxygen/i18n/de_DE/gameinput.ftl +++ b/assets/voxygen/i18n/de_DE/gameinput.ftl @@ -49,6 +49,7 @@ gameinput-togglewield = Waffe ziehen/wegstecken gameinput-interact = Interagieren gameinput-freelook = Freie Sicht gameinput-autowalk = Automatisch Laufen/Schwimmen +gameinput-zoomlock = Kamera-Zoomsperre gameinput-cameraclamp = Kamera fixieren gameinput-dance = Tanzen gameinput-select = Einheit auswählen diff --git a/assets/voxygen/i18n/de_DE/hud/misc.ftl b/assets/voxygen/i18n/de_DE/hud/misc.ftl index c6259a2a68..53fd52efac 100644 --- a/assets/voxygen/i18n/de_DE/hud/misc.ftl +++ b/assets/voxygen/i18n/de_DE/hud/misc.ftl @@ -35,6 +35,9 @@ hud-diary = Tagebuch hud-free_look_indicator = Freie Sicht aktiv. Drücke { $key } zum deaktivieren. hud-camera_clamp_indicator = Vertikale Kamerafixierung aktiv. Drücke { $key } zum deaktivieren. hud-auto_walk_indicator = Auto Laufen/Schwimmen aktiv +hud-zoom_lock_indicator-remind = Zoom gesperrt +hud-zoom_lock_indicator-enable = Kamerazoom gesperrt +hud-zoom_lock_indicator-disable = Kamerazoom entsperrt hud-collect = Aufsammeln hud-pick_up = Aufheben hud-open = Öffnen diff --git a/assets/voxygen/i18n/de_DE/hud/settings.ftl b/assets/voxygen/i18n/de_DE/hud/settings.ftl index 64a3fe0bdc..989b2c7ff5 100644 --- a/assets/voxygen/i18n/de_DE/hud/settings.ftl +++ b/assets/voxygen/i18n/de_DE/hud/settings.ftl @@ -2,6 +2,8 @@ hud-settings-general = Allgemein hud-settings-none = Keine hud-settings-press_behavior-toggle = Umschalten hud-settings-press_behavior-hold = Halten +hud-settings-autopress_behavior-toggle = Umschalten +hud-settings-autopress_behavior-auto = Auto hud-settings-help_window = Hilfe zu Fenstern hud-settings-debug_info = Debug-Informationen hud-settings-show_hitboxes = Hitboxen anzeigen @@ -50,10 +52,12 @@ hud-settings-enable_mouse_smoothing = Kamera-Glättung hud-settings-free_look_behavior = Verhalten bei freiem Kameramodus hud-settings-auto_walk_behavior = Verhalten bei automatischem Gehen hud-settings-camera_clamp_behavior = Verhalten bei starrer Kamera +hud-settings-zoom_lock_behavior = Verhalten bei Kamera-Zoomsperre hud-settings-player_physics_behavior = Spielerphysik (experimentell) hud-settings-stop_auto_walk_on_input = Automatisches Gehen bei Spieleraktivität anhalten hud-settings-auto_camera = Auto Kamera hud-settings-bow_zoom = Hinein zoomen, wenn der Bogen aufgeladen wird +hud-settings-zoom_lock = Kamera-Zoomsperre hud-settings-reset_gameplay = Einstellungen zurücksetzen diff --git a/assets/voxygen/i18n/en/gameinput.ftl b/assets/voxygen/i18n/en/gameinput.ftl index f8900e24b2..7237382e62 100644 --- a/assets/voxygen/i18n/en/gameinput.ftl +++ b/assets/voxygen/i18n/en/gameinput.ftl @@ -49,6 +49,7 @@ gameinput-togglewield = Toggle Wield gameinput-interact = Interact gameinput-freelook = Free Look gameinput-autowalk = Auto Walk/Swim +gameinput-zoomlock = Camera zoom lock gameinput-cameraclamp = Camera Clamp gameinput-dance = Dance gameinput-select = Select Entity diff --git a/assets/voxygen/i18n/en/hud/misc.ftl b/assets/voxygen/i18n/en/hud/misc.ftl index ef5d48c584..54c4a4612a 100644 --- a/assets/voxygen/i18n/en/hud/misc.ftl +++ b/assets/voxygen/i18n/en/hud/misc.ftl @@ -35,6 +35,9 @@ hud-diary = Diary hud-free_look_indicator = Free look active. Press { $key } to disable. hud-camera_clamp_indicator = Camera vertical clamp active. Press { $key } to disable. hud-auto_walk_indicator = Auto walk/swim active +hud-zoom_lock_indicator-remind = Zoom locked +hud-zoom_lock_indicator-enable = Camera zoom locked +hud-zoom_lock_indicator-disable = Camera zoom unlocked hud-collect = Collect hud-pick_up = Pick up hud-open = Open diff --git a/assets/voxygen/i18n/en/hud/settings.ftl b/assets/voxygen/i18n/en/hud/settings.ftl index 9504ed2f2c..0575de807b 100644 --- a/assets/voxygen/i18n/en/hud/settings.ftl +++ b/assets/voxygen/i18n/en/hud/settings.ftl @@ -2,6 +2,8 @@ hud-settings-general = General hud-settings-none = None hud-settings-press_behavior-toggle = Toggle hud-settings-press_behavior-hold = Hold +hud-settings-autopress_behavior-toggle = Toggle +hud-settings-autopress_behavior-auto = Auto hud-settings-help_window = Help Window hud-settings-debug_info = Debug Info hud-settings-show_hitboxes = Show hitboxes @@ -49,10 +51,12 @@ hud-settings-enable_mouse_smoothing = Camera Smoothing hud-settings-free_look_behavior = Free look behavior hud-settings-auto_walk_behavior = Auto walk behavior hud-settings-camera_clamp_behavior = Camera clamp behavior +hud-settings-zoom_lock_behavior = Camera zoom lock behavior hud-settings-player_physics_behavior = Player physics (experimental) hud-settings-stop_auto_walk_on_input = Stop auto walk on movement hud-settings-auto_camera = Auto camera hud-settings-bow_zoom = Zoom in when charging bow +hud-settings-zoom_lock = Camera zoom lock hud-settings-reset_gameplay = Reset to Defaults hud-settings-view_distance = View Distance hud-settings-entity_view_distance = Entities View Distance diff --git a/voxygen/src/game_input.rs b/voxygen/src/game_input.rs index b9902f9fdc..80ca3afeee 100644 --- a/voxygen/src/game_input.rs +++ b/voxygen/src/game_input.rs @@ -132,6 +132,8 @@ pub enum GameInput { FreeLook, #[strum(serialize = "gameinput-autowalk")] AutoWalk, + #[strum(serialize = "gameinput-zoomlock")] + ZoomLock, #[strum(serialize = "gameinput-cameraclamp")] CameraClamp, #[strum(serialize = "gameinput-cyclecamera")] diff --git a/voxygen/src/hud/change_notification.rs b/voxygen/src/hud/change_notification.rs new file mode 100644 index 0000000000..e05c6712a7 --- /dev/null +++ b/voxygen/src/hud/change_notification.rs @@ -0,0 +1,86 @@ +use serde::{Deserialize, Serialize}; + +use std::time::Duration; + +/// Default initial alpha of a Notify +const NOTIF_START_ALPHA: f32 = 1.0; + +/// Default time to live of a notify +const NOTIF_LIFETIME: f32 = 2.0; +/// Default fading time of a notify +const NOTIF_FADETIME: f32 = 1.5; + +/// The reason this notification is being shown: the setting is being enabled or +/// disabled, or we are reminding the player of the current state. +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub enum NotificationReason { + Remind = 2, + Enable = 1, + #[serde(other)] + Disable = 0, +} +/// A temporal, fading message that a setting +/// or other state was changed (probably by direct player input) +#[derive(Default)] +pub struct ChangeNotification { + pub reason: Option, + pub alpha: f32, + lifetime: Duration, + fadetime: Duration, + initial_fadetime: Duration, +} + +impl ChangeNotification { + pub fn new( + reason: Option, + alpha: f32, + lifetime: Duration, + fadetime: Duration, + ) -> Result { + if fadetime.is_zero() { + Err(fadetime) + } else { + Ok(Self { + reason, + alpha, + lifetime, + fadetime, + initial_fadetime: fadetime, + }) + } + } + + pub fn from_reason(reason: NotificationReason) -> Self { + ChangeNotification::new( + Some(reason), + NOTIF_START_ALPHA, + Duration::from_secs_f32(NOTIF_LIFETIME), + Duration::from_secs_f32(NOTIF_FADETIME), + ) + .unwrap() + } + + pub fn from_state(state: bool) -> Self { + ChangeNotification::from_reason(match state { + true => NotificationReason::Enable, + false => NotificationReason::Disable, + }) + } + + pub fn update(&mut self, dt: Duration) { + if self.reason.is_some() { + // Timer before fade + if !self.lifetime.is_zero() { + self.lifetime = self.lifetime.saturating_sub(dt); + // Lifetime expired, start to fade + } else if !self.fadetime.is_zero() { + self.fadetime = self.fadetime.saturating_sub(dt); + // alpha as elapsed duration fraction, multiply with this for nice fade curve + self.alpha = self.fadetime.as_secs_f32() / self.initial_fadetime.as_secs_f32(); + // Done fading + } else { + self.reason = None; + } + } + } +} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 3396449483..adaefa381f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -2,6 +2,7 @@ mod animation; mod bag; mod buffs; mod buttons; +mod change_notification; mod chat; mod crafting; mod diary; @@ -33,6 +34,7 @@ pub use settings_window::ScaleChange; use bag::Bag; use buffs::BuffsBar; use buttons::Buttons; +use change_notification::{ChangeNotification, NotificationReason}; use chat::Chat; use chrono::NaiveTime; use crafting::Crafting; @@ -329,6 +331,10 @@ widget_ids! { auto_walk_txt, auto_walk_bg, + // Temporal (fading) camera zoom lock indicator + zoom_lock_txt, + zoom_lock_bg, + // Camera clamp indicator camera_clamp_txt, camera_clamp_bg, @@ -797,6 +803,16 @@ pub enum PressBehavior { #[serde(other)] Toggle = 0, } +/// Similar to [PressBehavior], with different semantics for settings that +/// change state automatically. There is no [PressBehavior::update][update] +/// implementation because it doesn't apply to the use case; this is just a +/// sentinel. +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum AutoPressBehavior { + Auto = 1, + #[serde(other)] + Toggle = 0, +} #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct ChatTab { pub label: String, @@ -889,6 +905,7 @@ pub struct Show { stats: bool, free_look: bool, auto_walk: bool, + zoom_lock: ChangeNotification, camera_clamp: bool, prompt_dialog: Option, location_markers: MapMarkers, @@ -1367,6 +1384,7 @@ impl Hud { stats: false, free_look: false, auto_walk: false, + zoom_lock: ChangeNotification::default(), camera_clamp: false, prompt_dialog: None, location_markers: MapMarkers::default(), @@ -3522,6 +3540,31 @@ impl Hud { .set(self.ids.auto_walk_txt, ui_widgets); } + // Camera zoom lock + self.show.zoom_lock.update(dt); + + if let Some(zoom_lock) = self.show.zoom_lock.reason { + let zoom_lock_message = match zoom_lock { + NotificationReason::Remind => "hud-zoom_lock_indicator-remind", + NotificationReason::Enable => "hud-zoom_lock_indicator-enable", + NotificationReason::Disable => "hud-zoom_lock_indicator-disable", + }; + + Text::new(&i18n.get_msg(zoom_lock_message)) + .color(TEXT_BG.alpha(self.show.zoom_lock.alpha)) + .mid_top_with_margin_on(ui_widgets.window, indicator_offset) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(20)) + .set(self.ids.zoom_lock_bg, ui_widgets); + indicator_offset += 30.0; + Text::new(&i18n.get_msg(zoom_lock_message)) + .color(TEXT_COLOR.alpha(self.show.zoom_lock.alpha)) + .top_left_with_margins_on(self.ids.zoom_lock_bg, -1.0, -1.0) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(20)) + .set(self.ids.zoom_lock_txt, ui_widgets); + } + // Camera clamp indicator if let Some(cameraclamp_key) = global_state .settings @@ -4562,6 +4605,20 @@ impl Hud { pub fn camera_clamp(&mut self, camera_clamp: bool) { self.show.camera_clamp = camera_clamp; } + /// Remind the player camera zoom is currently locked, for example if they + /// are trying to zoom. + pub fn zoom_lock_reminder(&mut self) { + if self.show.zoom_lock.reason.is_none() { + self.show.zoom_lock = ChangeNotification::from_reason(NotificationReason::Remind); + } + } + + /// Start showing a temporary notification ([ChangeNotification]) that zoom + /// lock was toggled on/off. + pub fn zoom_lock_toggle(&mut self, state: bool) { + self.show.zoom_lock = ChangeNotification::from_state(state); + } + pub fn handle_outcome( &mut self, outcome: &Outcome, diff --git a/voxygen/src/hud/settings_window/gameplay.rs b/voxygen/src/hud/settings_window/gameplay.rs index 4f0ddd5e13..666f8ba573 100644 --- a/voxygen/src/hud/settings_window/gameplay.rs +++ b/voxygen/src/hud/settings_window/gameplay.rs @@ -1,7 +1,7 @@ use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH}; use crate::{ - hud::{img_ids::Imgs, PressBehavior, MENU_BG, TEXT_COLOR}, + hud::{img_ids::Imgs, AutoPressBehavior, PressBehavior, MENU_BG, TEXT_COLOR}, session::settings_change::{Gameplay as GameplayChange, Gameplay::*}, ui::{fonts::Fonts, ImageSlider, ToggleButton}, GlobalState, @@ -44,12 +44,16 @@ widget_ids! { auto_walk_behavior_list, camera_clamp_behavior_text, camera_clamp_behavior_list, + zoom_lock_behavior_text, + zoom_lock_behavior_list, stop_auto_walk_on_input_button, stop_auto_walk_on_input_label, auto_camera_button, auto_camera_label, bow_zoom_button, bow_zoom_label, + zoom_lock_button, + zoom_lock_label, } } @@ -528,6 +532,68 @@ impl<'a> Widget for Gameplay<'a> { .color(TEXT_COLOR) .set(state.ids.bow_zoom_label, ui); + let zoom_lock_label_list = [ + self.localized_strings + .get_msg("hud-settings-autopress_behavior-toggle"), + self.localized_strings + .get_msg("hud-settings-autopress_behavior-auto"), + ]; + + // Camera zoom lock behavior + Text::new( + &self + .localized_strings + .get_msg("hud-settings-zoom_lock_behavior"), + ) + .down_from(state.ids.auto_walk_behavior_list, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.zoom_lock_behavior_text, ui); + + let zoom_lock_selected = self.global_state.settings.gameplay.zoom_lock_behavior as usize; + + if let Some(clicked) = DropDownList::new(&zoom_lock_label_list, Some(zoom_lock_selected)) + .w_h(200.0, 30.0) + .color(MENU_BG) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .down_from(state.ids.zoom_lock_behavior_text, 8.0) + .set(state.ids.zoom_lock_behavior_list, ui) + { + match clicked { + 0 => events.push(ChangeZoomLockBehavior(AutoPressBehavior::Toggle)), + 1 => events.push(ChangeZoomLockBehavior(AutoPressBehavior::Auto)), + _ => unreachable!(), + } + } + + // Camera zoom lock toggle + let zoom_lock_toggle = ToggleButton::new( + self.global_state.settings.gameplay.zoom_lock, + self.imgs.checkbox, + self.imgs.checkbox_checked, + ) + .w_h(18.0, 18.0) + .down_from(state.ids.bow_zoom_button, 8.0) + .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) + .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) + .set(state.ids.zoom_lock_button, ui); + + if self.global_state.settings.gameplay.zoom_lock != zoom_lock_toggle { + events.push(ChangeZoomLock( + !self.global_state.settings.gameplay.zoom_lock, + )); + } + + Text::new(&self.localized_strings.get_msg("hud-settings-zoom_lock")) + .right_from(state.ids.zoom_lock_button, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .graphics_for(state.ids.zoom_lock_button) + .color(TEXT_COLOR) + .set(state.ids.zoom_lock_label, ui); + // Reset the gameplay settings to the default settings if Button::image(self.imgs.button) .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT) diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index f256f9a1e9..073728b03b 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -43,8 +43,8 @@ use crate::{ error::Error, game_input::GameInput, hud::{ - DebugInfo, Event as HudEvent, Hud, HudCollectFailedReason, HudInfo, LootMessage, - PromptDialogSettings, + AutoPressBehavior, DebugInfo, Event as HudEvent, Hud, HudCollectFailedReason, HudInfo, + LootMessage, PromptDialogSettings, }, key_state::KeyState, menu::char_selection::CharSelectionState, @@ -61,6 +61,25 @@ use target::targets_under_cursor; #[cfg(feature = "egui-ui")] use voxygen_egui::EguiDebugInfo; +/** The zoom scroll delta that is considered an "intent" + to zoom, rather than the accidental zooming that Zoom Lock + is supposed to help. + This is used for both [AutoPressBehaviors::Toggle] and [AutoPressBehaviors::Auto]. + + This value should likely differ between trackpad scrolling + and various mouse wheels, but we just choose a reasonable + default. + + All the mice I have can only scroll at |delta|=15 no matter + how fast, I guess the default should be less than that so + it gets seen. This could possibly be a user setting changed + only in a config file; it's too minor to put in the GUI. + If a player reports that their scroll wheel is apparently not + working, this value may be to blame (i.e. their intent to scroll + is not being detected at a low enough scroll speed). +*/ +const ZOOM_LOCK_SCROLL_DELTA_INTENT: f32 = 14.0; + /// The action to perform after a tick enum TickAction { // Continue executing @@ -83,6 +102,7 @@ pub struct SessionState { free_look: bool, auto_walk: bool, camera_clamp: bool, + zoom_lock: bool, is_aiming: bool, target_entity: Option, selected_entity: Option<(specs::Entity, std::time::Instant)>, @@ -152,6 +172,7 @@ impl SessionState { free_look: false, auto_walk: false, camera_clamp: false, + zoom_lock: false, is_aiming: false, target_entity: None, selected_entity: None, @@ -171,6 +192,24 @@ impl SessionState { self.key_state.auto_walk = false; } + /// Possibly lock the camera zoom depending on the current behaviour, and + /// the current inputs if in the Auto state. + fn maybe_auto_zoom_lock( + &mut self, + zoom_lock_enabled: bool, + zoom_lock_behavior: AutoPressBehavior, + ) { + if let AutoPressBehavior::Auto = zoom_lock_behavior { + // to add Analog detection, update the condition rhs with a check for + // MovementX/Y event from the last tick + self.zoom_lock = zoom_lock_enabled && self.should_auto_zoom_lock(); + } else { + // it's intentional that the HUD notification is not shown in this case: + // refresh session from Settings HUD checkbox change + self.zoom_lock = zoom_lock_enabled; + } + } + /// Gets the entity that is the current viewpoint, and a bool if the client /// is allowed to edit it's data. fn viewpoint_entity(&self) -> (specs::Entity, bool) { @@ -406,6 +445,45 @@ impl SessionState { /// Clean up the session (and the client attached to it) after a tick. pub fn cleanup(&mut self) { self.client.borrow_mut().cleanup(); } + + fn should_auto_zoom_lock(&self) -> bool { + let inputs_state = &self.inputs_state; + for input in inputs_state { + match input { + GameInput::Primary + | GameInput::Secondary + | GameInput::Block + | GameInput::MoveForward + | GameInput::MoveLeft + | GameInput::MoveRight + | GameInput::MoveBack + | GameInput::Jump + | GameInput::Roll + | GameInput::Sneak + | GameInput::AutoWalk + | GameInput::Climb + | GameInput::ClimbDown + | GameInput::SwimUp + | GameInput::SwimDown + | GameInput::SwapLoadout + | GameInput::ToggleWield + | GameInput::Slot1 + | GameInput::Slot2 + | GameInput::Slot3 + | GameInput::Slot4 + | GameInput::Slot5 + | GameInput::Slot6 + | GameInput::Slot7 + | GameInput::Slot8 + | GameInput::Slot9 + | GameInput::Slot10 + | GameInput::SpectateViewpoint + | GameInput::SpectateSpeedBoost => return true, + _ => (), + } + } + false + } } impl PlayState for SessionState { @@ -547,6 +625,11 @@ impl PlayState for SessionState { drop(client); + self.maybe_auto_zoom_lock( + global_state.settings.gameplay.zoom_lock, + global_state.settings.gameplay.zoom_lock_behavior, + ); + if presence == PresenceKind::Spectator { let mut client = self.client.borrow_mut(); if client.spectate_position(cam_pos) { @@ -609,7 +692,6 @@ impl PlayState for SessionState { continue; } } - match event { Event::Close => { return PlayStateResult::Shutdown; @@ -950,6 +1032,14 @@ impl PlayState for SessionState { self.key_state.auto_walk = self.auto_walk && !self.client.borrow().is_gliding(); }, + GameInput::ZoomLock => { + if state { + global_state.settings.gameplay.zoom_lock ^= true; + + self.hud + .zoom_lock_toggle(global_state.settings.gameplay.zoom_lock); + } + }, GameInput::CameraClamp => { let hud = &mut self.hud; global_state.settings.gameplay.camera_clamp_behavior.update( @@ -1032,6 +1122,13 @@ impl PlayState for SessionState { message: screenshot_message, }), + Event::Zoom(delta) if self.zoom_lock => { + // only fire this Hud event when player has "intent" to zoom + if delta.abs() > ZOOM_LOCK_SCROLL_DELTA_INTENT { + self.hud.zoom_lock_reminder(); + } + }, + // Pass all other events to the scene event => { self.scene.handle_input_event(event, &self.client.borrow()); diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 82c630f5d1..429eed96b1 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -3,8 +3,8 @@ use crate::{ controller::ControllerSettings, game_input::GameInput, hud::{ - BarNumbers, BuffPosition, ChatTab, CrosshairType, Intro, PressBehavior, ScaleChange, - ShortcutNumbers, XpBar, + AutoPressBehavior, BarNumbers, BuffPosition, ChatTab, CrosshairType, Intro, PressBehavior, + ScaleChange, ShortcutNumbers, XpBar, }, render::RenderMode, settings::{ @@ -68,9 +68,11 @@ pub enum Gameplay { ChangeFreeLookBehavior(PressBehavior), ChangeAutoWalkBehavior(PressBehavior), ChangeCameraClampBehavior(PressBehavior), + ChangeZoomLockBehavior(AutoPressBehavior), ChangeStopAutoWalkOnInput(bool), ChangeAutoCamera(bool), ChangeBowZoom(bool), + ChangeZoomLock(bool), ResetGameplaySettings, } @@ -386,6 +388,9 @@ impl SettingsChange { Gameplay::ChangeCameraClampBehavior(behavior) => { settings.gameplay.camera_clamp_behavior = behavior; }, + Gameplay::ChangeZoomLockBehavior(state) => { + settings.gameplay.zoom_lock_behavior = state; + }, Gameplay::ChangeStopAutoWalkOnInput(state) => { settings.gameplay.stop_auto_walk_on_input = state; }, @@ -395,6 +400,9 @@ impl SettingsChange { Gameplay::ChangeBowZoom(state) => { settings.gameplay.bow_zoom = state; }, + Gameplay::ChangeZoomLock(state) => { + settings.gameplay.zoom_lock = state; + }, Gameplay::ResetGameplaySettings => { // Reset Gameplay Settings settings.gameplay = GameplaySettings::default(); diff --git a/voxygen/src/settings/control.rs b/voxygen/src/settings/control.rs index 43957f8624..e064593a62 100644 --- a/voxygen/src/settings/control.rs +++ b/voxygen/src/settings/control.rs @@ -170,6 +170,7 @@ impl ControlSettings { GameInput::ToggleWield => Some(KeyMouse::Key(VirtualKeyCode::R)), GameInput::FreeLook => Some(KeyMouse::Key(VirtualKeyCode::L)), GameInput::AutoWalk => Some(KeyMouse::Key(VirtualKeyCode::Period)), + GameInput::ZoomLock => Some(KeyMouse::Key(VirtualKeyCode::Semicolon)), GameInput::CameraClamp => Some(KeyMouse::Key(VirtualKeyCode::Apostrophe)), GameInput::CycleCamera => Some(KeyMouse::Key(VirtualKeyCode::Key0)), GameInput::Slot1 => Some(KeyMouse::Key(VirtualKeyCode::Key1)), diff --git a/voxygen/src/settings/gameplay.rs b/voxygen/src/settings/gameplay.rs index 20a94a6a0e..6a8fe35ce1 100644 --- a/voxygen/src/settings/gameplay.rs +++ b/voxygen/src/settings/gameplay.rs @@ -1,4 +1,4 @@ -use crate::hud::PressBehavior; +use crate::hud::{AutoPressBehavior, PressBehavior}; use serde::{Deserialize, Serialize}; /// `GameplaySettings` contains sensitivity and gameplay options. @@ -14,9 +14,11 @@ pub struct GameplaySettings { pub free_look_behavior: PressBehavior, pub auto_walk_behavior: PressBehavior, pub camera_clamp_behavior: PressBehavior, + pub zoom_lock_behavior: AutoPressBehavior, pub stop_auto_walk_on_input: bool, pub auto_camera: bool, pub bow_zoom: bool, + pub zoom_lock: bool, } impl Default for GameplaySettings { @@ -31,9 +33,11 @@ impl Default for GameplaySettings { free_look_behavior: PressBehavior::Toggle, auto_walk_behavior: PressBehavior::Toggle, camera_clamp_behavior: PressBehavior::Toggle, + zoom_lock_behavior: AutoPressBehavior::Auto, stop_auto_walk_on_input: true, auto_camera: false, bow_zoom: true, + zoom_lock: false, } } }