From fd4f148c62f355e6f34824a9c2657e9812d16293 Mon Sep 17 00:00:00 2001 From: Artin Alavi <1361714+Arastais@users.noreply.github.com> Date: Thu, 10 Nov 2022 12:36:18 -0800 Subject: [PATCH] Feature: Hotkey to honk a vehicle's horn (#10110) --- src/newgrf_sound.cpp | 5 +-- src/newgrf_sound.h | 2 +- src/ship.h | 2 +- src/ship_cmd.cpp | 14 +++----- src/sound.cpp | 3 +- src/train.h | 2 +- src/train_cmd.cpp | 7 ++-- src/vehicle_base.h | 3 +- src/vehicle_gui.cpp | 63 ++++++++++++++++++++++++------------ src/widgets/vehicle_widget.h | 1 + 10 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/newgrf_sound.cpp b/src/newgrf_sound.cpp index 48f2105517..fce0ba9e11 100644 --- a/src/newgrf_sound.cpp +++ b/src/newgrf_sound.cpp @@ -181,11 +181,12 @@ SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id) * Checks whether a NewGRF wants to play a different vehicle sound effect. * @param v Vehicle to play sound effect for. * @param event Trigger for the sound effect. + * @param force Should we play the sound effect even if vehicle sound effects are muted? * @return false if the default sound effect shall be played instead. */ -bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event) +bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force) { - if (!_settings_client.sound.vehicle) return true; + if (!_settings_client.sound.vehicle && !force) return true; const GRFFile *file = v->GetGRF(); uint16 callback; diff --git a/src/newgrf_sound.h b/src/newgrf_sound.h index d908173ac8..5b1d1cbc57 100644 --- a/src/newgrf_sound.h +++ b/src/newgrf_sound.h @@ -34,7 +34,7 @@ bool LoadNewGRFSound(SoundEntry *sound); SoundID GetNewGRFSoundID(const struct GRFFile *file, SoundID sound_id); SoundEntry *GetSound(SoundID sound_id); uint GetNumSounds(); -bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event); +bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force = false); void PlayTileSound(const struct GRFFile *file, SoundID sound_id, TileIndex tile); #endif /* NEWGRF_SOUND_H */ diff --git a/src/ship.h b/src/ship.h index 66e29f4c3c..990e3cd8b4 100644 --- a/src/ship.h +++ b/src/ship.h @@ -38,7 +38,7 @@ struct Ship FINAL : public SpecializedVehicle { void MarkDirty(); void UpdateDeltaXY(); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_SHIP_REVENUE : EXPENSES_SHIP_RUN; } - void PlayLeaveStationSound() const; + void PlayLeaveStationSound(bool force = false) const; bool IsPrimaryVehicle() const { return true; } void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; int GetDisplaySpeed() const { return this->cur_speed / 2; } diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 873d45e688..ec90258b69 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -272,16 +272,10 @@ void Ship::MarkDirty() this->UpdateCache(); } -static void PlayShipSound(const Vehicle *v) +void Ship::PlayLeaveStationSound(bool force) const { - if (!PlayVehicleSound(v, VSE_START)) { - SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v); - } -} - -void Ship::PlayLeaveStationSound() const -{ - PlayShipSound(this); + if (PlayVehicleSound(this, VSE_START, force)) return; + SndPlayVehicleFx(ShipVehInfo(this->engine_type)->sfx, this); } TileIndex Ship::GetOrderStationLocation(StationID station) @@ -398,7 +392,7 @@ static bool CheckShipLeaveDepot(Ship *v) v->UpdateViewport(true, true); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); - PlayShipSound(v); + v->PlayLeaveStationSound(); VehicleServiceInDepot(v); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); SetWindowClassesDirty(WC_SHIPS_LIST); diff --git a/src/sound.cpp b/src/sound.cpp index 1d0f7e8417..34807a1d3c 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -235,6 +235,7 @@ void SndCopyToPool() /** * Decide 'where' (between left and right speaker) to play the sound effect. + * Note: Callers must determine if sound effects are enabled. This plays a sound regardless of the setting. * @param sound Sound effect to play * @param left Left edge of virtual coordinates where the sound is produced * @param right Right edge of virtual coordinates where the sound is produced @@ -243,8 +244,6 @@ void SndCopyToPool() */ static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom) { - if (_settings_client.music.effect_vol == 0) return; - /* Iterate from back, so that main viewport is checked first */ for (const Window *w : Window::IterateFromBack()) { const Viewport *vp = w->viewport; diff --git a/src/train.h b/src/train.h index 4b0a739b01..1e5583ea65 100644 --- a/src/train.h +++ b/src/train.h @@ -110,7 +110,7 @@ struct Train FINAL : public GroundVehicle { void MarkDirty() override; void UpdateDeltaXY() override; ExpensesType GetExpenseType(bool income) const override { return income ? EXPENSES_TRAIN_REVENUE : EXPENSES_TRAIN_RUN; } - void PlayLeaveStationSound() const override; + void PlayLeaveStationSound(bool force = false) const override; bool IsPrimaryVehicle() const override { return this->IsFrontEngine(); } void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override; int GetDisplaySpeed() const override { return this->gcache.last_speed; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index eeae7f1e9d..7d3a1fb361 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2100,7 +2100,7 @@ bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bo } /** Play a sound for a train leaving the station. */ -void Train::PlayLeaveStationSound() const +void Train::PlayLeaveStationSound(bool force) const { static const SoundFx sfx[] = { SND_04_DEPARTURE_STEAM, @@ -2110,10 +2110,9 @@ void Train::PlayLeaveStationSound() const SND_41_DEPARTURE_MAGLEV }; - if (PlayVehicleSound(this, VSE_START)) return; + if (PlayVehicleSound(this, VSE_START, force)) return; - EngineID engtype = this->engine_type; - SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this); + SndPlayVehicleFx(sfx[RailVehInfo(this->engine_type)->engclass], this); } /** diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 63fc7b524b..c643cff859 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -450,8 +450,9 @@ public: /** * Play the sound associated with leaving the station + * @param force Should we play the sound even if sound effects are muted? (horn hotkey) */ - virtual void PlayLeaveStationSound() const {} + virtual void PlayLeaveStationSound(bool force = false) const {} /** * Whether this is the primary vehicle in the chain. diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 789dd37929..7ccb7e6c2f 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -41,6 +41,7 @@ #include "order_cmd.h" #include "roadveh_cmd.h" #include "train_cmd.h" +#include "hotkeys.h" #include "safeguards.h" @@ -2686,26 +2687,6 @@ static const NWidgetPart _nested_vehicle_view_widgets[] = { EndContainer(), }; -/** Vehicle view window descriptor for all vehicles but trains. */ -static WindowDesc _vehicle_view_desc( - WDP_AUTO, "view_vehicle", 250, 116, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); - -/** - * Vehicle view window descriptor for trains. Only minimum_height and - * default_height are different for train view. - */ -static WindowDesc _train_view_desc( - WDP_AUTO, "view_vehicle_train", 250, 134, - WC_VEHICLE_VIEW, WC_NONE, - 0, - _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) -); - - /* Just to make sure, nobody has changed the vehicle type constants, as we are using them for array indexing in a number of places here. */ static_assert(VEH_TRAIN == 0); @@ -3151,6 +3132,20 @@ public: } } + EventState OnHotkey(int hotkey) override + { + /* If the hotkey is not for any widget in the UI (i.e. for honking) */ + if (hotkey == WID_VV_HONK_HORN) { + const Window* mainwindow = FindWindowById(WC_MAIN_WINDOW, 0); + const Vehicle* v = Vehicle::Get(window_number); + /*Only play the sound if we're following this vehicle */ + if (mainwindow->viewport->follow_vehicle == v->index) { + v->PlayLeaveStationSound(true); + } + } + return Window::OnHotkey(hotkey); + } + void OnQueryTextFinished(char *str) override { if (str == nullptr) return; @@ -3225,8 +3220,36 @@ public: { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } + + static HotkeyList hotkeys; }; +static Hotkey vehicleview_hotkeys[] = { + Hotkey('H', "honk", WID_VV_HONK_HORN), + HOTKEY_LIST_END +}; +HotkeyList VehicleViewWindow::hotkeys("vehicleview", vehicleview_hotkeys); + +/** Vehicle view window descriptor for all vehicles but trains. */ +static WindowDesc _vehicle_view_desc( + WDP_AUTO, "view_vehicle", 250, 116, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets), + &VehicleViewWindow::hotkeys +); + +/** + * Vehicle view window descriptor for trains. Only minimum_height and + * default_height are different for train view. + */ +static WindowDesc _train_view_desc( + WDP_AUTO, "view_vehicle_train", 250, 134, + WC_VEHICLE_VIEW, WC_NONE, + 0, + _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets), + &VehicleViewWindow::hotkeys +); /** Shows the vehicle view window of the given vehicle. */ void ShowVehicleViewWindow(const Vehicle *v) diff --git a/src/widgets/vehicle_widget.h b/src/widgets/vehicle_widget.h index 375f914e10..8e960bcb79 100644 --- a/src/widgets/vehicle_widget.h +++ b/src/widgets/vehicle_widget.h @@ -27,6 +27,7 @@ enum VehicleViewWidgets { WID_VV_SELECT_REFIT_TURN, ///< Selection widget between 'refit' and 'turn around' buttons. WID_VV_TURN_AROUND, ///< Turn this vehicle around. WID_VV_FORCE_PROCEED, ///< Force this vehicle to pass a signal at danger. + WID_VV_HONK_HORN, ///< Honk the vehicles horn (not drawn on UI, only used for hotkey). }; /** Widgets of the #RefitWindow class. */