00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #include <cassert>
00018 #include <cstdlib>
00019
00020 #include "display.hpp"
00021 #include "pathutils.hpp"
00022 #include "sound.hpp"
00023 #include "soundsource.hpp"
00024
00025
00026 namespace soundsource {
00027
00028 unsigned int positional_source::last_id = 0;
00029
00030 manager::manager(const display &disp) : _disp(disp)
00031 {
00032 _disp.scroll_event().attach_handler(this);
00033 update_positions();
00034 }
00035
00036 manager::~manager()
00037 {
00038 for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it) {
00039 delete (*it).second;
00040 }
00041
00042 _sources.clear();
00043 }
00044
00045 void manager::handle_generic_event(const std::string &event_name)
00046 {
00047 if(event_name == "scrolled")
00048 update_positions();
00049 }
00050
00051 void manager::add(const sourcespec &spec)
00052 {
00053 positional_source_iterator it;
00054
00055 if((it = _sources.find(spec.id)) == _sources.end()) {
00056 _sources[spec.id] = new positional_source(spec);
00057 } else {
00058 delete (*it).second;
00059 (*it).second = new positional_source(spec);
00060 }
00061 }
00062
00063 void manager::remove(const std::string &id)
00064 {
00065 positional_source_iterator it;
00066
00067 if((it = _sources.find(id)) == _sources.end())
00068 return;
00069 else {
00070 delete (*it).second;
00071 _sources.erase(it);
00072 }
00073 }
00074
00075 void manager::update()
00076 {
00077 unsigned int time = SDL_GetTicks();
00078
00079 for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it) {
00080 (*it).second->update(time, _disp);
00081 }
00082 }
00083
00084 void manager::update_positions()
00085 {
00086 unsigned int time = SDL_GetTicks();
00087
00088 for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it) {
00089 (*it).second->update_positions(time, _disp);
00090 }
00091 }
00092
00093 void manager::add_location(const std::string &id, const gamemap::location &loc)
00094 {
00095 positional_source_iterator it = _sources.find(id);
00096
00097 if(it == _sources.end())
00098 return;
00099 else
00100 (*it).second->add_location(loc);
00101 }
00102
00103
00104 positional_source::positional_source(const sourcespec &spec)
00105 : _last_played(0), _min_delay(spec.min_delay), _chance(spec.chance), _loops(spec.loops),
00106 _id(last_id++), _range(spec.range), _faderange(spec.faderange),
00107 _check_fogged(spec.check_fogged), _files(spec.files), _locations(spec.locations)
00108 {
00109 assert(_range > 0);
00110 assert(_faderange > 0);
00111 }
00112
00113 positional_source::~positional_source()
00114 {
00115 sound::reposition_sound(_id, DISTANCE_SILENT);
00116 }
00117
00118 void positional_source::update(unsigned int time, const display &disp)
00119 {
00120 if(time - _last_played < _min_delay || sound::is_sound_playing(_id))
00121 return;
00122
00123 unsigned int i = rand() % 100 + 1;
00124
00125 if(i <= _chance) {
00126 _last_played = time;
00127
00128
00129
00130 if(_locations.size() == 0) {
00131 sound::play_sound_positioned(_files, _id, _loops, 0);
00132 return;
00133 }
00134
00135 int distance_volume = DISTANCE_SILENT;
00136 for(std::vector<gamemap::location>::iterator i = _locations.begin(); i != _locations.end(); ++i) {
00137 int v = calculate_volume(*i, disp);
00138 if(v < distance_volume) {
00139 distance_volume = v;
00140 }
00141 }
00142
00143 if(distance_volume >= DISTANCE_SILENT)
00144 return;
00145
00146 sound::play_sound_positioned(_files, _id, _loops, distance_volume);
00147 }
00148 }
00149
00150 void positional_source::update_positions(unsigned int time, const display &disp)
00151 {
00152 int distance_volume = DISTANCE_SILENT;
00153 for(std::vector<gamemap::location>::iterator i = _locations.begin(); i != _locations.end(); ++i) {
00154 if(disp.shrouded(*i) || (_check_fogged && disp.fogged(*i)))
00155 continue;
00156
00157 int v = calculate_volume(*i, disp);
00158 if(v < distance_volume) {
00159 distance_volume = v;
00160 }
00161 }
00162
00163 if(sound::is_sound_playing(_id)) {
00164 sound::reposition_sound(_id, distance_volume);
00165 } else {
00166 update(time, disp);
00167 }
00168 }
00169
00170 int positional_source::calculate_volume(const gamemap::location &loc, const display &disp)
00171 {
00172 assert(_range > 0);
00173 assert(_faderange > 0);
00174
00175 SDL_Rect area = disp.map_area();
00176 gamemap::location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
00177 size_t distance = distance_between(loc, center);
00178
00179 if(distance <= _range) {
00180 return 0;
00181 }
00182
00183 return static_cast<int>(( ( (distance - _range) / (double) _faderange) * DISTANCE_SILENT));
00184 }
00185
00186 void positional_source::add_location(const gamemap::location &loc)
00187 {
00188 _locations.push_back(loc);
00189 }
00190
00191 }
00192