The Battle for Wesnoth  1.15.1+dev
soundsource.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Karol Nowak <grzywacz@sul.uni.lodz.pl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "display.hpp"
16 #include "log.hpp"
17 #include "random.hpp"
18 #include "sound.hpp"
19 #include "soundsource.hpp"
20 
21 #include <SDL2/SDL_timer.h>
22 
23 namespace soundsource {
24 
25 const unsigned DEFAULT_CHANCE = 100;
26 const unsigned DEFAULT_DELAY = 1000;
27 
28 unsigned int positional_source::last_id = 0;
29 
30 manager::manager(const display &disp) :
31  observer(),
32  sources_(),
33  disp_(disp)
34 {
37 }
38 
40 {
41  sources_.clear();
42 }
43 
44 void manager::handle_generic_event(const std::string &event_name)
45 {
46  if(event_name == "scrolled")
48 }
49 
50 void manager::add(const sourcespec &spec)
51 {
52  sources_[spec.id()].reset(new positional_source(spec));
53 }
54 
55 config 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 
65 void 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 
77 {
78  unsigned int time = SDL_GetTicks();
79 
80  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
81  (*it).second->update(time, disp_);
82  }
83 }
84 
86 {
87  unsigned int time = SDL_GetTicks();
88 
89  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
90  (*it).second->update_positions(time, disp_);
91  }
92 }
93 
95 {
96  for(positional_source_const_iterator i = sources_.begin(); i != sources_.end(); ++i) {
97  assert(i->second);
98 
99  config& child = cfg.add_child("sound_source");
100  child["id"] = i->first;
101  i->second->write_config(child);
102  }
103 }
104 
106  last_played_(0),
107  min_delay_(spec.minimum_delay()),
108  chance_(spec.chance()),
109  loops_(spec.loops()),
110  id_(last_id++),
111  range_(spec.full_range()),
112  faderange_(spec.fade_range()),
113  check_fogged_(spec.check_fogged()),
114  check_shrouded_(spec.check_shrouded()),
115  files_(spec.files()),
116  locations_(spec.get_locations())
117 {
118  assert(range_ > 0);
119  assert(faderange_ > 0);
120 }
121 
123 {
125 }
126 
128 {
129  return locations_.empty();
130 }
131 
132 void positional_source::update(unsigned int time, const display &disp)
133 {
134  if (time - last_played_ < static_cast<unsigned>(min_delay_) || sound::is_sound_playing(id_))
135  return;
136 
138 
139  if(i <= chance_) {
140  last_played_ = time;
141 
142  // If no locations have been specified, treat the source as if
143  // it was present everywhere on the map
144  if(locations_.empty()) {
145  sound::play_sound_positioned(files_, id_, loops_, 0); // max volume
146  return;
147  }
148 
149  int distance_volume = DISTANCE_SILENT;
150  for(const map_location& l : locations_) {
151  int v = calculate_volume(l, disp);
152  if(v < distance_volume) {
153  distance_volume = v;
154  }
155  }
156 
157  if(distance_volume >= DISTANCE_SILENT)
158  return;
159 
160  sound::play_sound_positioned(files_, id_, loops_, distance_volume);
161  }
162 }
163 
164 void positional_source::update_positions(unsigned int time, const display &disp)
165 {
166  if(is_global()) {
167  return;
168  }
169 
170  int distance_volume = DISTANCE_SILENT;
171  for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
172  int v = calculate_volume(*i, disp);
173  if(v < distance_volume) {
174  distance_volume = v;
175  }
176  }
177 
179  sound::reposition_sound(id_, distance_volume);
180  } else {
181  update(time, disp);
182  }
183 }
184 
186 {
187  assert(range_ > 0);
188  assert(faderange_ > 0);
189 
190  if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
191  return DISTANCE_SILENT;
192 
193  SDL_Rect area = disp.map_area();
194  map_location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
195  int distance = distance_between(loc, center);
196 
197  if(distance <= range_) {
198  return 0;
199  }
200 
201  return static_cast<int>((((distance - range_)
202  / static_cast<double>(faderange_)) * DISTANCE_SILENT));
203 }
204 
206 {
207  cfg["sounds"] = files_;
208  cfg["delay"] = min_delay_;
209  cfg["chance"] = chance_;
210  cfg["check_fogged"] = check_fogged_;
211  cfg["check_shrouded"] = check_shrouded_;
212  cfg["loop"] = loops_;
213  cfg["full_range"] = range_;
214  cfg["fade_range"] = faderange_;
216 }
217 
219  id_(cfg["id"]),
220  files_(cfg["sounds"]),
221  min_delay_(cfg["delay"].to_int(DEFAULT_DELAY)),
222  chance_(cfg["chance"].to_int(DEFAULT_CHANCE)),
223  loops_(cfg["loop"]),
224  range_(cfg["full_range"].to_int(3)),
225  faderange_(cfg["fade_range"].to_int(14)),
226  check_fogged_(cfg["check_fogged"].to_bool(true)),
227  check_shrouded_(cfg["check_shrouded"].to_bool(true)),
228  locations_()
229 {
231 }
232 
233 } // namespace soundsource
int calculate_volume(const map_location &loc, const display &disp)
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
Definition: location.cpp:485
bool is_sound_playing(int id)
Definition: sound.cpp:846
void play_sound_positioned(const std::string &files, int id, int repeats, unsigned int distance)
Definition: sound.cpp:995
const 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:570
events::generic_event & scroll_event() const
Expose the event, so observers can be notified about map scrolling.
Definition: display.hpp:561
const SDL_Rect & map_area() const
Returns the area used for the map.
Definition: display.cpp:533
void stop_sound()
Definition: sound.cpp:533
void remove(const std::string &id)
Definition: soundsource.cpp:65
void reposition_sound(int id, unsigned int distance)
Definition: sound.cpp:830
const std::string & id() const
positional_source_map::iterator positional_source_iterator
Definition: soundsource.hpp:80
void update(unsigned int time, const display &disp)
void handle_generic_event(const std::string &event_name)
Definition: soundsource.cpp:44
std::vector< map_location > locations_
positional_source_map sources_
Definition: soundsource.hpp:83
void write_config(config &cfg) const
Serializes attributes as WML config.
map_display and display: classes which take care of displaying the map and game-data on the screen...
void update_positions(unsigned int time, const display &disp)
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:716
Encapsulates the map of the game.
Definition: location.hpp:42
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:711
std::vector< map_location > locations_
Definition: soundsource.hpp:46
Sound source info class.
virtual bool attach_handler(observer *obs)
std::size_t i
Definition: function.cpp:933
void add(const sourcespec &source)
Definition: soundsource.cpp:50
const unsigned DEFAULT_CHANCE
Definition: soundsource.cpp:25
positional_source(const sourcespec &spec)
sourcespec(const std::string &id, const std::string &files, int min_delay, int chance)
Parameter-list constructor.
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
Definition: random.hpp:51
void write_sourcespecs(config &cfg) const
Serializes information into cfg as new children of key "sound_source", appended to existing content...
Definition: soundsource.cpp:94
std::string observer
manager(const display &disp)
Definition: soundsource.cpp:30
config & add_child(config_key_type key)
Definition: config.cpp:476
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:600
#define DISTANCE_SILENT
Definition: sound.hpp:61
Standard logging facilities (interface).
const display & disp_
Definition: soundsource.hpp:84
const unsigned DEFAULT_DELAY
Definition: soundsource.cpp:26
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
config get(const std::string &id)
Definition: soundsource.cpp:55
static rng & default_instance()
Definition: random.cpp:73
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
positional_source_map::const_iterator positional_source_const_iterator
Definition: soundsource.hpp:81
static unsigned int last_id
Definition: soundsource.hpp:50
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,..,yn.
Definition: location.cpp:497