The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
soundsource.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2006 - 2025
3 by Karol Nowak <grzywacz@sul.uni.lodz.pl>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#include "display.hpp"
17#include "random.hpp"
19#include "sound.hpp"
20#include "soundsource.hpp"
21
22namespace soundsource {
23
24using namespace std::chrono_literals;
25const unsigned DEFAULT_CHANCE = 100;
26const auto DEFAULT_DELAY = 1000ms;
27
28unsigned int positional_source::last_id = 0;
29
31 : observer()
32 , sources_()
33 , disp_(disp)
34{
37}
38
40{
41 sources_.clear();
42}
43
44void manager::handle_generic_event(const std::string &event_name)
45{
46 if(event_name == "scrolled")
48}
49
50void manager::add(const sourcespec &spec)
51{
52 sources_[spec.id()].reset(new positional_source(spec));
53}
54
55sourcespec manager::get(const std::string &id)
56{
57 config cfg;
59 if(it != sources_.end()) {
60 it->second->write_config(cfg);
61 }
62 return cfg;
63}
64
65void manager::remove(const std::string &id)
66{
68
69 if((it = sources_.find(id)) == sources_.end())
70 return;
71 else {
72 sources_.erase(it);
73 }
74}
75
76bool manager::contains(const std::string& id)
77{
78 return sources_.find(id) != sources_.end();
79}
80
82{
83 auto time = std::chrono::steady_clock::now();
84
85 for(const auto& [source_id, source] : sources_) {
86 source->update(time, disp_);
87 }
88}
89
91{
92 auto time = std::chrono::steady_clock::now();
93
94 for(const auto& [source_id, source] : sources_) {
95 source->update_positions(time, disp_);
96 }
97}
98
100{
101 for(const auto& [source_id, source] : sources_) {
102 assert(source);
103
104 config& child = cfg.add_child("sound_source");
105 child["id"] = source_id;
106 source->write_config(child);
107 }
108}
109
111 : last_played_()
112 , min_delay_(spec.minimum_delay())
113 , chance_(spec.chance())
114 , loops_(spec.loops())
115 , id_(last_id++)
116 , range_(spec.full_range())
117 , faderange_(spec.fade_range())
118 , check_fogged_(spec.check_fogged())
119 , check_shrouded_(spec.check_shrouded())
120 , files_(spec.files())
121 , locations_(spec.get_locations())
122{
123 assert(range_ >= 0);
124 assert(faderange_ >= 0);
125}
126
131
133{
134 return locations_.empty();
135}
136
137void positional_source::update(const std::chrono::steady_clock::time_point& time, const display &disp)
138{
140 return;
141
143
144 if(i <= chance_) {
145 last_played_ = time;
146
147 // If no locations have been specified, treat the source as if
148 // it was present everywhere on the map
149 if(locations_.empty()) {
150 sound::play_sound_positioned(files_, loops_, 0, id_); // max volume
151 return;
152 }
153
154 int distance_volume = sound::distance_silent;
155 for(const map_location& l : locations_) {
156 int v = calculate_volume(l, disp);
157 if(v < distance_volume) {
158 distance_volume = v;
159 }
160 }
161
162 if(distance_volume >= sound::distance_silent)
163 return;
164
165 sound::play_sound_positioned(files_, loops_, distance_volume, id_);
166 }
167}
168
169void positional_source::update_positions(const std::chrono::steady_clock::time_point& time, const display &disp)
170{
171 if(is_global()) {
172 return;
173 }
174
175 int distance_volume = sound::distance_silent;
176 for(const map_location& loc : locations_) {
177 int v = calculate_volume(loc, disp);
178 if(v < distance_volume) {
179 distance_volume = v;
180 }
181 }
182
184 sound::reposition_sound(id_, distance_volume);
185 } else {
186 update(time, disp);
187 }
188}
189
191{
192 assert(range_ >= 0);
193 assert(faderange_ >= 0);
194
195 if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
197
198 rect area = disp.map_area();
199 map_location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
200 int distance = distance_between(loc, center);
201
202 if(distance <= range_) {
203 return 0;
204 }
205
206 if(faderange_ == 0) {
208 }
209
210 return static_cast<int>((((distance - range_)
211 / static_cast<double>(faderange_)) * sound::distance_silent));
212}
213
215{
216 cfg["sounds"] = files_;
217 cfg["delay"] = min_delay_;
218 cfg["chance"] = chance_;
219 cfg["check_fogged"] = check_fogged_;
220 cfg["check_shrouded"] = check_shrouded_;
221 cfg["loop"] = loops_;
222 cfg["full_range"] = range_;
223 cfg["fade_range"] = faderange_;
225}
226
228{
229 cfg["id"] = id_;
230 cfg["sounds"] = files_;
231 cfg["delay"] = min_delay_;
232 cfg["chance"] = chance_;
233 cfg["check_fogged"] = check_fogged_;
234 cfg["check_shrouded"] = check_shrouded_;
235 cfg["loop"] = loops_;
236 cfg["full_range"] = range_;
237 cfg["fade_range"] = faderange_;
239}
240
242 : id_(cfg["id"])
243 , files_(cfg["sounds"])
244 , min_delay_(chrono::parse_duration(cfg["delay"], DEFAULT_DELAY))
245 , chance_(cfg["chance"].to_int(DEFAULT_CHANCE))
246 , loops_(cfg["loop"].to_int())
247 , range_(cfg["full_range"].to_int(3))
248 , faderange_(cfg["fade_range"].to_int(14))
249 , check_fogged_(cfg["check_fogged"].to_bool(true))
250 , check_shrouded_(cfg["check_shrouded"].to_bool(true))
251 , locations_(read_locations(cfg))
252{
253}
254
255} // namespace soundsource
map_location loc
Definition move.cpp:172
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & add_child(std::string_view key)
Definition config.cpp:436
all_children_iterator erase(const all_children_iterator &i)
Definition config.cpp:618
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition display.hpp:88
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition display.cpp:669
rect map_area() const
Returns the area used for the map.
Definition display.cpp:490
events::generic_event & scroll_event() const
Expose the event, so observers can be notified about map scrolling.
Definition display.hpp:523
map_location hex_clicked_on(int x, int y) const
given x,y co-ordinates of an onscreen pixel, will return the location of the hex that this pixel corr...
Definition display.cpp:533
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition display.cpp:664
virtual bool attach_handler(observer *obs)
static rng & default_instance()
Definition random.cpp:73
int get_random_int(int min, int max)
Definition random.hpp:51
void handle_generic_event(const std::string &event_name)
sourcespec get(const std::string &id)
positional_source_map sources_
const display & disp_
positional_source_map::iterator positional_source_iterator
manager(const display &disp)
void write_sourcespecs(config &cfg) const
Serializes information into cfg as new children of key "sound_source", appended to existing content.
void add(const sourcespec &source)
bool contains(const std::string &id)
void remove(const std::string &id)
std::chrono::steady_clock::time_point last_played_
void update(const std::chrono::steady_clock::time_point &time, const display &disp)
void write_config(config &cfg) const
Serializes attributes as WML config.
std::vector< map_location > locations_
int calculate_volume(const map_location &loc, const display &disp)
positional_source(const sourcespec &spec)
static unsigned int last_id
std::chrono::milliseconds min_delay_
void update_positions(const std::chrono::steady_clock::time_point &time, const display &disp)
Sound source info class.
const std::string & id() const
void write(config &cfg) const
Serializes information into cfg as a new (appended) child of key "sound_source".
const std::string id_
std::vector< map_location > locations_
sourcespec(const std::string &id, const std::string &files, const std::chrono::milliseconds &min_delay, int chance)
Parameter-list constructor.
std::chrono::milliseconds min_delay_
map_display and display: classes which take care of displaying the map and game-data on the screen.
const config * cfg
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition location.cpp:584
void write_locations(const std::vector< map_location > &locs, config &cfg)
Write a vector of locations into a config adding keys x=x1,x2,..,xn and y=y1,y2,.....
Definition location.cpp:493
std::vector< map_location > read_locations(const config &cfg)
Parse x,y keys of a config into a vector of locations.
Definition location.cpp:475
void reposition_sound(unsigned id, unsigned int distance)
Definition sound.cpp:833
constexpr int distance_silent
Definition sound.hpp:72
bool is_sound_playing(int id)
Definition sound.cpp:848
void play_sound_positioned(const std::string &files, int repeats, unsigned int distance, unsigned int id)
Definition sound.cpp:985
void stop_sound()
Definition sound.cpp:543
const unsigned DEFAULT_CHANCE
const auto DEFAULT_DELAY
Encapsulates the map of the game.
Definition location.hpp:46
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
#define i