Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "global.hpp"
00017
00018
00019 #include "display.hpp"
00020 #include "foreach.hpp"
00021 #include "log.hpp"
00022 #include "serialization/string_utils.hpp"
00023 #include "sound.hpp"
00024 #include "soundsource.hpp"
00025
00026 namespace soundsource {
00027
00028 const unsigned DEFAULT_CHANCE = 100;
00029 const unsigned DEFAULT_DELAY = 1000;
00030 const unsigned DEFAULT_FULL_RANGE = 3;
00031 const unsigned DEFAULT_FADE_RANGE = 14;
00032
00033 unsigned int positional_source::last_id = 0;
00034
00035 manager::manager(const display &disp) :
00036 observer(),
00037 savegame_config(),
00038 sources_(),
00039 disp_(disp)
00040 {
00041 disp_.scroll_event().attach_handler(this);
00042 update_positions();
00043 }
00044
00045 manager::~manager()
00046 {
00047 for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
00048 delete (*it).second;
00049 }
00050
00051 sources_.clear();
00052 }
00053
00054 void manager::handle_generic_event(const std::string &event_name)
00055 {
00056 if(event_name == "scrolled")
00057 update_positions();
00058 }
00059
00060 void manager::add(const sourcespec &spec)
00061 {
00062 positional_source_iterator it;
00063
00064 if((it = sources_.find(spec.id())) == sources_.end()) {
00065 sources_[spec.id()] = new positional_source(spec);
00066 } else {
00067 delete (*it).second;
00068 (*it).second = new positional_source(spec);
00069 }
00070 }
00071
00072 void manager::remove(const std::string &id)
00073 {
00074 positional_source_iterator it;
00075
00076 if((it = sources_.find(id)) == sources_.end())
00077 return;
00078 else {
00079 delete (*it).second;
00080 sources_.erase(it);
00081 }
00082 }
00083
00084 void manager::update()
00085 {
00086 unsigned int time = SDL_GetTicks();
00087
00088 for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
00089 (*it).second->update(time, disp_);
00090 }
00091 }
00092
00093 void manager::update_positions()
00094 {
00095 unsigned int time = SDL_GetTicks();
00096
00097 for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
00098 (*it).second->update_positions(time, disp_);
00099 }
00100 }
00101
00102 void manager::write_sourcespecs(config& cfg) const
00103 {
00104 for(positional_source_const_iterator i = sources_.begin(); i != sources_.end(); ++i) {
00105 assert(i->second);
00106
00107 config& child = cfg.add_child("sound_source");
00108 child["id"] = i->first;
00109 i->second->write_config(child);
00110 }
00111 }
00112
00113 config manager::to_config() const
00114 {
00115 config cfg;
00116 write_sourcespecs(cfg);
00117 return cfg.child("sound_source");
00118 }
00119
00120 positional_source::positional_source(const sourcespec &spec) :
00121 last_played_(0),
00122 min_delay_(spec.minimum_delay()),
00123 chance_(spec.chance()),
00124 loops_(spec.loops()),
00125 id_(last_id++),
00126 range_(spec.full_range()),
00127 faderange_(spec.fade_range()),
00128 check_fogged_(spec.check_fogged()),
00129 check_shrouded_(spec.check_shrouded()),
00130 files_(spec.files()),
00131 locations_(spec.get_locations())
00132 {
00133 assert(range_ > 0);
00134 assert(faderange_ > 0);
00135 }
00136
00137 positional_source::~positional_source()
00138 {
00139 sound::reposition_sound(id_, DISTANCE_SILENT);
00140 }
00141
00142 bool positional_source::is_global()
00143 {
00144 return locations_.empty();
00145 }
00146
00147 void positional_source::update(unsigned int time, const display &disp)
00148 {
00149 if (time - last_played_ < unsigned(min_delay_) || sound::is_sound_playing(id_))
00150 return;
00151
00152 int i = rand() % 100 + 1;
00153
00154 if(i <= chance_) {
00155 last_played_ = time;
00156
00157
00158
00159 if(locations_.empty()) {
00160 sound::play_sound_positioned(files_, id_, loops_, 0);
00161 return;
00162 }
00163
00164 int distance_volume = DISTANCE_SILENT;
00165 for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
00166 int v = calculate_volume(*i, disp);
00167 if(v < distance_volume) {
00168 distance_volume = v;
00169 }
00170 }
00171
00172 if(distance_volume >= DISTANCE_SILENT)
00173 return;
00174
00175 sound::play_sound_positioned(files_, id_, loops_, distance_volume);
00176 }
00177 }
00178
00179 void positional_source::update_positions(unsigned int time, const display &disp)
00180 {
00181 if(is_global()) {
00182 return;
00183 }
00184
00185 int distance_volume = DISTANCE_SILENT;
00186 for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
00187 int v = calculate_volume(*i, disp);
00188 if(v < distance_volume) {
00189 distance_volume = v;
00190 }
00191 }
00192
00193 if(sound::is_sound_playing(id_)) {
00194 sound::reposition_sound(id_, distance_volume);
00195 } else {
00196 update(time, disp);
00197 }
00198 }
00199
00200 int positional_source::calculate_volume(const map_location &loc, const display &disp)
00201 {
00202 assert(range_ > 0);
00203 assert(faderange_ > 0);
00204
00205 if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
00206 return DISTANCE_SILENT;
00207
00208 SDL_Rect area = disp.map_area();
00209 map_location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
00210 int distance = distance_between(loc, center);
00211
00212 if(distance <= range_) {
00213 return 0;
00214 }
00215
00216 return static_cast<int>((((distance - range_)
00217 / static_cast<double>(faderange_)) * DISTANCE_SILENT));
00218 }
00219
00220 void positional_source::write_config(config& cfg) const
00221 {
00222 cfg["sounds"] = files_;
00223 cfg["delay"] = min_delay_;
00224 cfg["chance"] = chance_;
00225 cfg["check_fogged"] = check_fogged_;
00226 cfg["check_shrouded"] = check_shrouded_;
00227 cfg["loop"] = loops_;
00228 cfg["full_range"] = range_;
00229 cfg["fade_range"] = faderange_;
00230 write_locations(locations_, cfg);
00231 }
00232
00233 sourcespec::sourcespec(const config& cfg) :
00234 id_(cfg["id"]),
00235 files_(cfg["sounds"]),
00236 min_delay_(cfg["delay"].to_int(DEFAULT_DELAY)),
00237 chance_(cfg["chance"].to_int(DEFAULT_CHANCE)),
00238 loops_(cfg["loop"]),
00239 range_(cfg["full_range"].to_int(3)),
00240 faderange_(cfg["fade_range"].to_int(14)),
00241 check_fogged_(cfg["check_fogged"].to_bool(true)),
00242 check_shrouded_(cfg["check_shrouded"].to_bool(true)),
00243 locations_()
00244 {
00245 read_locations(cfg, locations_);
00246 }
00247
00248 }
00249