mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-03 21:48:48 +00:00
250 lines
5.8 KiB
C++
250 lines
5.8 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2006 - 2011 by Karol Nowak <grzywacz@sul.uni.lodz.pl>
|
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
#include "global.hpp"
|
|
|
|
|
|
#include "display.hpp"
|
|
#include "foreach.hpp"
|
|
#include "log.hpp"
|
|
#include "serialization/string_utils.hpp"
|
|
#include "sound.hpp"
|
|
#include "soundsource.hpp"
|
|
|
|
namespace soundsource {
|
|
|
|
const unsigned DEFAULT_CHANCE = 100;
|
|
const unsigned DEFAULT_DELAY = 1000;
|
|
const unsigned DEFAULT_FULL_RANGE = 3;
|
|
const unsigned DEFAULT_FADE_RANGE = 14;
|
|
|
|
unsigned int positional_source::last_id = 0;
|
|
|
|
manager::manager(const display &disp) :
|
|
observer(),
|
|
savegame_config(),
|
|
sources_(),
|
|
disp_(disp)
|
|
{
|
|
disp_.scroll_event().attach_handler(this);
|
|
update_positions();
|
|
}
|
|
|
|
manager::~manager()
|
|
{
|
|
for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
|
|
delete (*it).second;
|
|
}
|
|
|
|
sources_.clear();
|
|
}
|
|
|
|
void manager::handle_generic_event(const std::string &event_name)
|
|
{
|
|
if(event_name == "scrolled")
|
|
update_positions();
|
|
}
|
|
|
|
void manager::add(const sourcespec &spec)
|
|
{
|
|
positional_source_iterator it;
|
|
|
|
if((it = sources_.find(spec.id())) == sources_.end()) {
|
|
sources_[spec.id()] = new positional_source(spec);
|
|
} else {
|
|
delete (*it).second;
|
|
(*it).second = new positional_source(spec);
|
|
}
|
|
}
|
|
|
|
void manager::remove(const std::string &id)
|
|
{
|
|
positional_source_iterator it;
|
|
|
|
if((it = sources_.find(id)) == sources_.end())
|
|
return;
|
|
else {
|
|
delete (*it).second;
|
|
sources_.erase(it);
|
|
}
|
|
}
|
|
|
|
void manager::update()
|
|
{
|
|
unsigned int time = SDL_GetTicks();
|
|
|
|
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) {
|
|
(*it).second->update_positions(time, disp_);
|
|
}
|
|
}
|
|
|
|
void manager::write_sourcespecs(config& cfg) const
|
|
{
|
|
for(positional_source_const_iterator i = sources_.begin(); i != sources_.end(); ++i) {
|
|
assert(i->second);
|
|
|
|
config& child = cfg.add_child("sound_source");
|
|
child["id"] = i->first;
|
|
i->second->write_config(child);
|
|
}
|
|
}
|
|
|
|
config manager::to_config() const
|
|
{
|
|
config cfg;
|
|
write_sourcespecs(cfg);
|
|
return cfg.child("sound_source");
|
|
}
|
|
|
|
positional_source::positional_source(const sourcespec &spec) :
|
|
last_played_(0),
|
|
min_delay_(spec.minimum_delay()),
|
|
chance_(spec.chance()),
|
|
loops_(spec.loops()),
|
|
id_(last_id++),
|
|
range_(spec.full_range()),
|
|
faderange_(spec.fade_range()),
|
|
check_fogged_(spec.check_fogged()),
|
|
check_shrouded_(spec.check_shrouded()),
|
|
files_(spec.files()),
|
|
locations_(spec.get_locations())
|
|
{
|
|
assert(range_ > 0);
|
|
assert(faderange_ > 0);
|
|
}
|
|
|
|
positional_source::~positional_source()
|
|
{
|
|
sound::reposition_sound(id_, DISTANCE_SILENT);
|
|
}
|
|
|
|
bool positional_source::is_global()
|
|
{
|
|
return locations_.empty();
|
|
}
|
|
|
|
void positional_source::update(unsigned int time, const display &disp)
|
|
{
|
|
if (time - last_played_ < unsigned(min_delay_) || sound::is_sound_playing(id_))
|
|
return;
|
|
|
|
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_.empty()) {
|
|
sound::play_sound_positioned(files_, id_, loops_, 0); // max volume
|
|
return;
|
|
}
|
|
|
|
int distance_volume = DISTANCE_SILENT;
|
|
for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
|
|
int v = calculate_volume(*i, disp);
|
|
if(v < distance_volume) {
|
|
distance_volume = v;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
if(is_global()) {
|
|
return;
|
|
}
|
|
|
|
int distance_volume = DISTANCE_SILENT;
|
|
for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
|
|
int v = calculate_volume(*i, disp);
|
|
if(v < distance_volume) {
|
|
distance_volume = v;
|
|
}
|
|
}
|
|
|
|
if(sound::is_sound_playing(id_)) {
|
|
sound::reposition_sound(id_, distance_volume);
|
|
} else {
|
|
update(time, disp);
|
|
}
|
|
}
|
|
|
|
int positional_source::calculate_volume(const map_location &loc, const display &disp)
|
|
{
|
|
assert(range_ > 0);
|
|
assert(faderange_ > 0);
|
|
|
|
if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
|
|
return DISTANCE_SILENT;
|
|
|
|
SDL_Rect area = disp.map_area();
|
|
map_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;
|
|
}
|
|
|
|
return static_cast<int>((((distance - range_)
|
|
/ static_cast<double>(faderange_)) * DISTANCE_SILENT));
|
|
}
|
|
|
|
void positional_source::write_config(config& cfg) const
|
|
{
|
|
cfg["sounds"] = files_;
|
|
cfg["delay"] = min_delay_;
|
|
cfg["chance"] = chance_;
|
|
cfg["check_fogged"] = check_fogged_;
|
|
cfg["check_shrouded"] = check_shrouded_;
|
|
cfg["loop"] = loops_;
|
|
cfg["full_range"] = range_;
|
|
cfg["fade_range"] = faderange_;
|
|
write_locations(locations_, cfg);
|
|
}
|
|
|
|
sourcespec::sourcespec(const config& cfg) :
|
|
id_(cfg["id"]),
|
|
files_(cfg["sounds"]),
|
|
min_delay_(cfg["delay"].to_int(DEFAULT_DELAY)),
|
|
chance_(cfg["chance"].to_int(DEFAULT_CHANCE)),
|
|
loops_(cfg["loop"]),
|
|
range_(cfg["full_range"].to_int(3)),
|
|
faderange_(cfg["fade_range"].to_int(14)),
|
|
check_fogged_(cfg["check_fogged"].to_bool(true)),
|
|
check_shrouded_(cfg["check_shrouded"].to_bool(true)),
|
|
locations_()
|
|
{
|
|
read_locations(cfg, locations_);
|
|
}
|
|
|
|
} // namespace soundsource
|
|
|