Changed logic responsible for determining volume of sound sources.

It's now based on hex distance.
This commit is contained in:
Karol Nowak 2008-03-16 10:22:25 +00:00
parent 3e0594928c
commit 3b9705905b
3 changed files with 64 additions and 70 deletions

View file

@ -1604,6 +1604,7 @@ void event_handler::handle_event_command(const queued_event& event_info,
std::string x = cfg["x"];
std::string y = cfg["y"];
std::string loop = cfg["loop"];
std::string full_range = cfg["full_range"];
assert(state_of_game != NULL);
@ -1619,6 +1620,7 @@ void event_handler::handle_event_command(const queued_event& event_info,
soundsource::sourcespec spec(id, sounds, lexical_cast_default<int>(delay, 1000), lexical_cast_default<int>(chance, 100));
spec.loop(lexical_cast_default<int>(loop, 0));
spec.full_range(lexical_cast_default<int>(full_range, 1));
if(play_fogged.empty()) {
spec.check_fog(true);

View file

@ -14,25 +14,15 @@
#include "global.hpp"
#include <cassert>
#include <cstdlib>
#include "display.hpp"
#include "pathutils.hpp"
#include "sound.hpp"
#include "soundsource.hpp"
static int calculate_volume(int x, int y, const display &disp)
{
SDL_Rect area = disp.map_outside_area();
int dx = area.w / 2 - x; dx *= dx;
int dy = area.h / 2 - y; dy *= dy;
// An obscure formula to calculate SDL_Mixer's "distance" based on the source's
// distance from screen's center
return maximum<int>(0, 128 * static_cast<int>(std::sqrt((double) (dx + dy)) / (std::sqrt((double) (area.w*area.w + area.h * area.h)))));
}
namespace soundsource {
unsigned int positional_source::last_id = 0;
@ -64,8 +54,7 @@ void manager::add(const sourcespec &spec)
if((it = _sources.find(spec.id)) == _sources.end()) {
_sources[spec.id] = new positional_source(spec);
}
else {
} else {
delete (*it).second;
(*it).second = new positional_source(spec);
}
@ -87,16 +76,18 @@ void manager::update()
{
unsigned int time = SDL_GetTicks();
for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it)
for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it) {
(*it).second->update(time, _disp);
}
}
void manager::update_positions()
{
unsigned int time = SDL_GetTicks();
for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it)
for(positional_source_iterator it = _sources.begin(); it != _sources.end(); ++it) {
(*it).second->update_positions(time, _disp);
}
}
void manager::add_location(const std::string &id, const gamemap::location &loc)
@ -111,83 +102,79 @@ void manager::add_location(const std::string &id, const gamemap::location &loc)
positional_source::positional_source(const sourcespec &spec)
: _last_played(0), _min_delay(spec.min_delay), _chance(spec.chance), _loops(spec.loops),
_id(last_id++), _check_fogged(spec.check_fogged), _visible(false), _files(spec.files),
: _last_played(0), _min_delay(spec.min_delay), _chance(spec.chance), _loops(spec.loops),
_id(last_id++), _range(spec.range), _check_fogged(spec.check_fogged), _files(spec.files),
_locations(spec.locations)
{
assert(_range > 0);
}
void positional_source::update(unsigned int time, const display &disp)
{
if(time - _last_played < _min_delay || !_visible)
if(time - _last_played < _min_delay || sound::is_sound_playing(_id))
return;
_last_played = time;
unsigned int i = rand() % 100 + 1;
if(i <= _chance) {
_last_played = time;
// If no locations have been specified, treat the source as if
// it was present everywhere on the map
if(_locations.size() == 0) {
sound::play_sound_positioned(_files, last_id, _loops, 0); // max volume
sound::play_sound_positioned(_files, _id, _loops, 0); // max volume
return;
}
// SDL_Rect area = disp.map_outside_area();
int distance_volume = 256;
int distance_volume = DISTANCE_SILENT;
for(std::vector<gamemap::location>::iterator i = _locations.begin(); i != _locations.end(); ++i) {
int locx = disp.get_location_x(*i);
int locy = disp.get_location_y(*i);
/*
if(disp.outside_area(area, locx, locy) || disp.shrouded((*i).x, (*i).y)
|| (!_play_fogged && disp.fogged((*i).x, (*i).y)))
continue;
else {*/
// Finds the location with the lowest distance == highest volume
int v = calculate_volume(locx, locy, disp);
if(v < distance_volume)
distance_volume = v;
/* }*/
int v = calculate_volume(*i, disp);
if(v < distance_volume) {
distance_volume = v;
}
}
if(!sound::is_sound_playing(last_id)) {
sound::play_sound_positioned(_files, last_id, _loops, distance_volume);
}
if(distance_volume >= DISTANCE_SILENT)
return;
sound::play_sound_positioned(_files, _id, _loops, distance_volume);
}
}
void positional_source::update_positions(unsigned int time, const display &disp)
{
const bool was_visible = _visible;
SDL_Rect area = disp.map_outside_area();
int distance_volume = DISTANCE_SILENT;
for(std::vector<gamemap::location>::iterator i = _locations.begin(); i != _locations.end(); ++i) {
if(disp.shrouded(*i) || (_check_fogged && disp.fogged(*i)))
continue;
_visible = false;
for(std::vector<gamemap::location>::iterator i = _locations.begin(); i != _locations.end(); ++i) {
int locx = disp.get_location_x(*i);
int locy = disp.get_location_y(*i);
if(disp.outside_area(area, locx, locy) || disp.shrouded(*i)
|| (_check_fogged && disp.fogged(*i)))
continue;
else {
_visible = true;
if(!sound::is_sound_playing(last_id)) {
if(!was_visible)
_last_played = 0; // hack make the previously invisible source to play
update(time, disp);
continue;
}
sound::reposition_sound(last_id, calculate_volume(locx, locy, disp));
int v = calculate_volume(*i, disp);
if(v < distance_volume) {
distance_volume = v;
}
}
if(!_visible)
sound::stop_sound(last_id);
if(sound::is_sound_playing(_id)) {
sound::reposition_sound(_id, distance_volume);
} else {
update(time, disp);
}
}
int positional_source::calculate_volume(const gamemap::location &loc, const display &disp)
{
assert(_range > 0);
SDL_Rect area = disp.map_area();
gamemap::location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
int distance = distance_between(loc, center);
if(distance <= _range) {
return 0;
}
int calced = static_cast<int>(( ( (distance - _range) / (double) _range) * DISTANCE_SILENT));
return calced;
}
void positional_source::add_location(const gamemap::location &loc)

View file

@ -40,9 +40,9 @@ class positional_source {
unsigned int _min_delay;
unsigned int _chance;
unsigned int _loops;
unsigned int _id;
const unsigned int _id;
unsigned int _range;
bool _check_fogged;
bool _visible;
std::string _files;
std::vector<gamemap::location> _locations;
@ -64,6 +64,8 @@ class positional_source {
void add_location(const gamemap::location &loc);
void remove_location(const gamemap::location &loc);
void replace_location(const gamemap::location &oldloc, const gamemap::location &newloc);
int calculate_volume(const gamemap::location &loc, const display &disp);
};
class manager : public events::observer {
@ -103,17 +105,15 @@ class sourcespec {
int chance;
int loops;
int range;
bool check_fogged;
std::vector<gamemap::location> locations;
public:
sourcespec(const std::string &id_, const std::string &files_, int min_delay_, int chance_)
: id(id_), files(files_), min_delay(min_delay_), chance(chance_)
: id(id_), files(files_), min_delay(min_delay_), chance(chance_), loops(0), check_fogged(false)
{
loops = 0;
check_fogged = false;
}
sourcespec& loop(int loops_) {
@ -131,6 +131,11 @@ public:
return *this;
}
sourcespec& full_range(int range_) {
range = maximum<int>(1, range_);
return *this;
}
friend class manager;
friend class positional_source;
};