Add client side ambience

master
Brandon 2015-07-02 18:38:12 -05:00
parent 6d94cd3edf
commit 027f4d83cb
3 changed files with 224 additions and 87 deletions

View File

@ -46,14 +46,17 @@ Ambiance::Ambiance(ISoundManager *sound, ClientEnvironment &e):
m_sound->loadSoundFile("splash","client/sounds/splash.ogg");
m_sound->loadSoundFile("swimming1","client/sounds/water_swimming_splashing.ogg");
m_sound->loadSoundFile("swimming2","client/sounds/water_swimming_splashing_breath.ogg");
m_sound->loadSoundFile("waves","client/sounds/waves.ogg");
m_sound->loadSoundFile("waves2","client/sounds/waves2.ogg");
m_sound->loadSoundFile("wolves","client/sounds/wolves.ogg");
verbosestream << "done" << std::endl;
verbosestream << "[AMBIANCE] Setting up environments...";
a_env[ENV_UNKNOWN] = { "Unknown", 0, 0, "", "", 0 };
a_env[ENV_UNKNOWN] = { "Unknown", 0, 0, "", "", "", 0 };
// setup the various environment's sounds and frequencies
a_env[ENV_CAVE] = { "Cave", 400, 6, "", "", 5.75 };
a_env[ENV_CAVE] = { "Cave", 400, 6, "", "", "", 5.75 };
a_env[ENV_CAVE].sounds[1] = {"bats",.4};
a_env[ENV_CAVE].sounds[2] = {"drip_a",.8};
a_env[ENV_CAVE].sounds[3] = {"drip_b",.8};
@ -61,42 +64,67 @@ verbosestream << "[AMBIANCE] Setting up environments...";
a_env[ENV_CAVE].sounds[5] = {"drip_d",.4};
a_env[ENV_CAVE].sounds[6] = {"drip_e",.5};
a_env[ENV_UNDERWATER] = { "Underwater", 1001, 5, "splash", "drowning_gasp", 0 };
a_env[ENV_UNDERWATER] = { "Underwater", 1001, 5, "splash", "drowning_gasp", "", 0 };
a_env[ENV_UNDERWATER].sounds[1] = {"scuba1",1};
a_env[ENV_UNDERWATER].sounds[2] = {"scuba2",1};
a_env[ENV_UNDERWATER].sounds[3] = {"scuba3",1};
a_env[ENV_UNDERWATER].sounds[4] = {"scuba4",1};
a_env[ENV_UNDERWATER].sounds[5] = {"scuba5",1};
a_env[ENV_INWATER] = { "Standing in Water", 1001, 2, "splash", "splash", 0 };
a_env[ENV_INWATER] = { "Standing in Water", 1001, 2, "splash", "splash", "", 0 };
a_env[ENV_INWATER].sounds[1] = {"swimming1",.6};
a_env[ENV_INWATER].sounds[2] = {"swimming2",.6};
a_env[ENV_MORNING] = { "Morning", 300, 3, "", "", 7 };
a_env[ENV_MORNING].sounds[1] = {"bird2",.5};
a_env[ENV_MORNING].sounds[2] = {"bird4",.5};
a_env[ENV_MORNING].sounds[3] = {"bird3",.5};
a_env[ENV_PLAINS] = { "Plains", 300, 5, "", "", "", 4 };
a_env[ENV_PLAINS].sounds[1] = {"bird2",.2};
a_env[ENV_PLAINS].sounds[2] = {"bird4",.2};
a_env[ENV_PLAINS].sounds[3] = {"bird3",.2};
a_env[ENV_PLAINS].sounds[4] = {"bird",.2};
a_env[ENV_PLAINS].sounds[5] = {"birdsong",.2};
a_env[ENV_DAY] = { "Day", 400, 5, "", "", 6 };
a_env[ENV_DAY].sounds[1] = {"bird2",.5};
a_env[ENV_DAY].sounds[2] = {"bird4",.5};
a_env[ENV_DAY].sounds[3] = {"bird3",.5};
a_env[ENV_DAY].sounds[4] = {"bird",.5};
a_env[ENV_DAY].sounds[5] = {"birdsong",.5};
a_env[ENV_PLAINS_NIGHT] = { "Plains Night", 300, 0, "", "", "crickets", 6 };
a_env[ENV_DUSK] = { "Dusk", 1001, 1, "", "", 0 };
a_env[ENV_DUSK].sounds[1] = {"crickets",.5};
a_env[ENV_FOREST] = { "Forest", 700, 5, "", "", "", 3 };
a_env[ENV_FOREST].sounds[1] = {"bird2",.5};
a_env[ENV_FOREST].sounds[2] = {"bird4",.5};
a_env[ENV_FOREST].sounds[3] = {"bird3",.5};
a_env[ENV_FOREST].sounds[4] = {"bird",.5};
a_env[ENV_FOREST].sounds[5] = {"birdsong",.5};
a_env[ENV_NIGHT] = { "Night", 600, 1, "", "", 3 };
a_env[ENV_NIGHT].sounds[1] = {"crickets",.7};
a_env[ENV_FOREST_NIGHT] = { "Forest Night", 400, 3, "", "", "crickets", 4 };
a_env[ENV_FOREST_NIGHT].sounds[1] = {"owl",.8};
a_env[ENV_FOREST_NIGHT].sounds[2] = {"coyote",.8};
a_env[ENV_FOREST_NIGHT].sounds[3] = {"wolves",.9};
a_env[ENV_SNOW] = { "Snow", -1, 0, "", "", "", 0 };
a_env[ENV_SNOW_NIGHT] = { "Snow Night", -1, 0, "", "", "", 0 };
a_env[ENV_OCEAN] = { "Ocean", 800, 3, "", "", "", 1 };
a_env[ENV_OCEAN].sounds[1] = {"waves", .8};
a_env[ENV_OCEAN].sounds[2] = {"waves2",.8};
a_env[ENV_OCEAN].sounds[3] = {"seagull",.7};
a_env[ENV_DESERT] = { "Desert", 625, 1, "", "", "desert", 3 };
a_env[ENV_DESERT].sounds[1] = { "rattlesnake", .6 };
a_env[ENV_DESERT_NIGHT] = { "Desert Night", 400, 1, "", "", "", 3 };
a_env[ENV_DESERT_NIGHT].sounds[1] = { "desert", .8 };
a_env[ENV_JUNGLE] = { "Jungle", -1, 0, "", "", "", 0 };
a_env[ENV_JUNGLE_NIGHT] = { "Jungle Night", -1, 0, "", "", "", 0 };
verbosestream << "done" << std::endl;
}
void Ambiance::doAmbiance(float dtime){
void Ambiance::doAmbiance(float dtime, u32 tod){
static bool newEnv = false;
if ( startDelay > 3 ) { // delay ambiance 3 seconds from launch of game
m_timeOfDay = tod;
tickDelay += dtime;
if ( startDelay > 3 && tickDelay > .1 ) { // delay ambiance 3 seconds from launch of game
lastPlay += dtime;
//verbosestream << "[AMBIANCE] doAmbiance()" << std::endl;
tickDelay = 0;
int env_result = readEnvironment();
if ( env_result != currentEnv ){
lastEnv = currentEnv;
@ -106,15 +134,18 @@ void Ambiance::doAmbiance(float dtime){
playSound(a_env[currentEnv].on_start, 1);
}
newEnv = true;
verbosestream << "[AMBIANCE] readEnvironment Results: " << a_env[currentEnv].name << std::endl;
actionstream << "[AMBIANCE] readEnvironment Results: " << a_env[currentEnv].name << std::endl;
if ( !a_env[currentEnv].background_sound.empty() ){
m_background_sound = m_sound->playSound(a_env[currentEnv].background_sound,true,0.6);
} else {
m_background_sound = 0;
}
} else {
newEnv = false;
}
if ( m_sounds_playing.rbegin() != m_sounds_playing.rend() ){
if ( m_sound->soundExists(m_sounds_playing.rbegin()->second) ){
// if the last sound isn't doesn't playing don't start another one
//verbosestream << "[AMBIANCE] dont start a new sound" << std::endl;
return;
} else {
m_sounds_it it = m_sounds_playing.find(m_sounds_playing.rbegin()->first);
@ -122,17 +153,22 @@ void Ambiance::doAmbiance(float dtime){
}
}
if ( newEnv == true || lastPlay > a_env[currentEnv].next_sound_delay ){
srand (time(NULL));
int freq = rand() % 1000;
//verbosestream << "[AMBIANCE] Freq Random Number: " << to_string(freq) << " :: " << to_string(a_env[currentEnv].frequency) << std::endl;
if ( freq <= a_env[currentEnv].frequency ){
int s = ( rand() % a_env[currentEnv].sound_count ) + 1;
verbosestream << "[AMBIANCE] Sound selected: " << to_string(s) << " " << a_env[currentEnv].sounds[s].name << std::endl;
playSound(a_env[currentEnv].sounds[s].name, a_env[currentEnv].sounds[s].gain);
if ( a_env[currentEnv].sound_count > 0 ){
if ( lastPlay >= a_env[currentEnv].next_sound_delay ){
srand (time(NULL));
int freq = rand() % 1000;
//verbosestream << "[AMBIANCE] Freq Random Number: " << to_string(freq) << " :: " << to_string(a_env[currentEnv].frequency) << std::endl;
if ( freq <= a_env[currentEnv].frequency ){
int s = ( rand() % a_env[currentEnv].sound_count ) + 1;
float v = ( rand() % 60 ); // add a little random variation to the sound volume
if ( v > 0 )
v = v / 100;
verbosestream << "[AMBIANCE] Sound selected: " << to_string(s) << " " << a_env[currentEnv].sounds[s].name << std::endl;
playSound(a_env[currentEnv].sounds[s].name, ( a_env[currentEnv].sounds[s].gain - v ));
}
} else {
//verbosestream << "[AMBIANCE] No Play" << to_string(lastPlay) <<std::endl;
}
} else {
//verbosestream << "[AMBIANCE] No Play" << to_string(lastPlay) <<std::endl;
}
} else {
startDelay += dtime;
@ -161,7 +197,7 @@ bool Ambiance::playSound(std::string name, float gain){
}
int Ambiance::readEnvironment(){
//verbosestream << "[AMBIANCE] readEnvironment() ";
//actionstream << "[AMBIANCE] readEnvironment() ";
ascending = false;
descending = false;
moving = false;
@ -174,7 +210,19 @@ int Ambiance::readEnvironment(){
// DAY AND NIGHT ARE KIND OF CATCH ALLS
// 19000 night starts
// 5000 morning starts
u32 t = m_env.getTimeOfDay();
u32 t = m_timeOfDay;
if ( t > 5000 && t < 8000 )
TOD = MORNING;
if ( t > 8000 && t < 18500 )
TOD = DAY;
if ( t > 18500 && t < 19500 )
TOD = DUSK;
if ( t > 19500 || t < 5000 )
TOD = NIGHT;
//verbosestream << t << std::endl;
if ( pos.Y > ( lastpos.Y + .5 ) )
@ -186,81 +234,116 @@ int Ambiance::readEnvironment(){
if ( pos.X != lastpos.X || pos.Z != lastpos.Z )
moving = true;
if ( moving == false && currentEnv == ENV_INWATER ) // for in water only play sounds if they are moving otherwise return unknown
return ENV_UNKNOWN;
// if they aren't moving and the time of day hasn't changed don't recheck the environment
if ( moving != true && TOD == lastTOD && currentEnv != ENV_INWATER )
return currentEnv;
// if they haven't moved much don't check the environment
//if ( ascending == false && descending == false && moving == false ){
// return currentEnv;
//}
// don't update lastpos until they have moved
lastpos = pos;
//verbosestream << p->getName() << " " << to_string(spos.X) << "," << to_string(spos.Y) << "," << to_string(spos.Z) << std::endl;
lastTOD = TOD;
// find the nodes at their body positions
std::string lowerBodyNodeName = getNodeName(v3s16(spos.X, (spos.Y+1), spos.Z));
std::string upperBodyNodeName = getNodeName(v3s16(spos.X, (spos.Y+2), spos.Z));
std::string standingOnNodeName = getNodeName(v3s16(spos.X, spos.Y, spos.Z));
std::string aboveHeadNodeName = getNodeName(v3s16(spos.X, (spos.Y+3), spos.Z));
std::string lowerBodyNode = getNodeName(v3s16(spos.X, (spos.Y+1), spos.Z));
std::string upperBodyNode = getNodeName(v3s16(spos.X, (spos.Y+2), spos.Z));
std::string standingOnNode = getNodeName(v3s16(spos.X, spos.Y, spos.Z));
std::string aboveHeadNode = getNodeName(v3s16(spos.X, (spos.Y+3), spos.Z));
if ( ( upperBodyNodeName == "default:water_source" || upperBodyNodeName == "default:water_flowing" ) ){
if ( ( upperBodyNode == WATER || upperBodyNode == WATER_FLOWING ) ){
underwater = true;
return ENV_UNDERWATER;
}
if ( moving == true && ( lowerBodyNodeName == "default:water_source" || lowerBodyNodeName == "default:water_flowing" ) ){
if ( moving == true && ( lowerBodyNode == WATER || lowerBodyNode == WATER_FLOWING ) ){
return ENV_INWATER;
}
if ( spos.Y < -15 && nodesInRange(spos, 5, "default:stone") > 8 ){
// see if they are surrounded by stone
return ENV_CAVE;
// all of these happen above ground
if ( spos.Y > 0 ){
if ( nodesInRange(spos,10, 3, -1, JUNGLE_TREE,1,15) || nodesInRange(spos,10,2,-1,JUNGLE_GRASS,1,5) ){
if ( TOD == MORNING || TOD == DAY )
return ENV_JUNGLE;
else
return ENV_JUNGLE_NIGHT;
}
if ( nodesInRange(spos, 10, 4, -1, TREE,1,10) || nodesInRange(spos,10, 7, -1, LEAVES,1, 8 ) ){
if ( TOD == MORNING || TOD == DAY )
return ENV_FOREST;
else
return ENV_FOREST_NIGHT;
}
if ( nodesInRange(spos, 5, 1, 1, GRASS,1,8) ){
if ( TOD == MORNING || TOD == DAY )
return ENV_PLAINS;
else
return ENV_PLAINS_NIGHT;
}
if ( nodesInRange(spos, 5, 1, 2, SNOW, 1, 10) || nodesInRange(spos,5, 1, 2, DIRT_SNOW,1,10) ){
if ( TOD == MORNING || TOD == DAY )
return ENV_SNOW;
else
return ENV_SNOW_NIGHT;
}
if ( nodesInRange(spos, 10, 1, 2, DESERT_SAND, 1, 15) || nodesInRange(spos,10,1,2,DESERT_STONE,1,15) ){
if ( TOD == MORNING || TOD == DAY )
return ENV_DESERT;
else
return ENV_DESERT_NIGHT;
}
if ( spos.Y < 7 && spos.Y > -1 ){
if ( nodesInRange(spos,10,2,7,SAND, 1, 10) ){
if ( nodesInRange(spos, 20, 0, 7, WATER, 5, 8) ){
return ENV_OCEAN;
}
}
}
}
// time based catchalls
if ( t > 5000 && t < 8000 )
return ENV_MORNING;
if ( t > 8000 && t < 18500 )
return ENV_DAY;
if ( t > 18500 && t < 19500 )
return ENV_DUSK;
if ( t > 19500 || t < 5000 )
return ENV_NIGHT;
if ( nodesInRange(spos, 3, 6, 0, STONE,1,25) ){
return ENV_CAVE;
}
return ENV_UNKNOWN;
}
int Ambiance::nodesInRange(v3s16 pos, short searchRange, std::string nodeName){
bool Ambiance::nodesInRange(v3s16 pos, short searchRange, short searchAbove, short searchBelow, std::string nodeName, short accuracy, int count){
//verbosestream << "[AMBIANCE] nodesInRange(pos, " << to_string(searchRange) << ", " << nodeName << ")" << std::endl;
int nodeCount = 0;
std::string cNode;
bool valid_pos;
// set positions for node checks
v3s16 p1 = v3s16((pos.X - searchRange), (pos.Y - searchRange), (pos.Z - searchRange));
v3s16 p2 = v3s16((pos.X + searchRange), (pos.Y + searchRange), (pos.Z + searchRange));
v3s16 p1 = v3s16((pos.X - searchRange), (pos.Y - searchBelow), (pos.Z - searchRange));
v3s16 p2 = v3s16((pos.X + searchRange), (pos.Y + searchAbove), (pos.Z + searchRange));
//verbosestream << "[AMBIANCE] Searching from " << to_string(p1.X) << ", " << to_string(p1.Y) << ", " << to_string(p1.Z) << " to " << to_string(p2.X) << ", " << to_string(p2.Y) << ", " << to_string(p2.Z) << std::endl;
for ( int y = p1.Y; y < p2.Y; y++ ){
for ( int x = p1.X; x < p2.X; x++ ){
for ( int z = p1.Z; z < p2.Z; z++ ){
for ( int y = p1.Y; y < p2.Y; y+=accuracy ){
for ( int x = p1.X; x < p2.X; x+=accuracy ){
for ( int z = p1.Z; z < p2.Z; z+=accuracy ){
//verbosestream << "[AMBIANCE] Position " << to_string(x) << ", " << to_string(y) << ", " << to_string(z) << std::endl;
MapNode n = m_env.getMap().getNodeNoEx(v3s16(x,y,z), &valid_pos);
ContentFeatures f = m_env.getGameDef()->getNodeDefManager()->get(n);
//MapNode n = m_env.getMap().getNodeNoEx(v3s16(x,y,z), &valid_pos);
cNode = getNodeName(v3s16(x,y,z));
//ContentFeatures f = m_env.getGameDef()->getNodeDefManager()->get(n);
//verbosestream << f.name << std::endl;
if ( valid_pos == true ){
if ( f.name == nodeName )
if ( cNode == nodeName )
nodeCount++;
} else {
verbosestream << "[AMBIANCE] Invalid position " << to_string(x) << ", " << to_string(y) << ", " << to_string(z) << std::endl;
//verbosestream << "[AMBIANCE] Invalid position " << to_string(x) << ", " << to_string(y) << ", " << to_string(z) << std::endl;
return 0;
}
if ( nodeCount > count )
return true;
}
}
}
return false;
//verbosestream << "[AMBIANCE] Node Count: " << to_string(nodeCount) << std::endl;
return nodeCount;
//return nodeCount;
}
std::string Ambiance::getNodeName(v3s16 pos){
@ -269,12 +352,26 @@ std::string Ambiance::getNodeName(v3s16 pos){
return f.name;
}
int Ambiance::getNodeId(v3s16 pos){
MapNode n = m_env.getMap().getNodeNoEx(pos);
return n.getContent();
}
void Ambiance::stopEnvironment(int env){
// not going to bother seeing if the sounds playing are part of a certain environment just yet, just stop all sounds
for ( m_sounds_it i = m_sounds_playing.begin(); i != m_sounds_playing.end(); i++ ){
m_sound->stopSound(i->second);
}
if ( m_background_sound != 0 ){
m_sound->stopSound(m_background_sound);
m_background_sound = 0;
}
if ( !a_env[env].on_stop.empty() ){
playSound(a_env[env].on_stop,1);
}
lastPlay = 0;
}

View File

@ -12,21 +12,28 @@
#include "sound.h"
#include "settings.h"
#include "sound_openal.h"
#include "nodedef.h"
class Ambiance
{
public:
Ambiance(ISoundManager *sound, ClientEnvironment &e);
void doAmbiance(float dtime);
void doAmbiance(float dtime, u32 tod);
private:
bool playSound(std::string name, float gain);
int nodesInRange(v3s16 pos, short searchRange, std::string nodeName);
bool nodesInRange(v3s16 pos, short searchRange, short searchAbove, short searchBelow, std::string nodeName, short accuracy, int count);
std::string getNodeName(v3s16 pos);
int getNodeId(v3s16 pos);
void stopEnvironment(int env);
int readEnvironment();
u32 m_timeOfDay;
ISoundManager *m_sound;
ClientEnvironment m_env;
int m_background_sound;
std::map<std::string, int> m_sounds_playing;
typedef std::map<std::string, int>::iterator m_sounds_it;
@ -38,10 +45,13 @@ private:
float startDelay;
float envDelay;
float tickDelay;
int currentEnv = 0;
int lastEnv;
float lastPlay;
int TOD;
int lastTOD;
struct env_sound {
std::string name;
@ -54,6 +64,7 @@ private:
int sound_count;
std::string on_start;
std::string on_stop;
std::string background_sound;
float next_sound_delay;
env_sound sounds[10];
bool on_start_played;
@ -65,15 +76,44 @@ private:
ENV_CAVE,
ENV_UNDERWATER,
ENV_INWATER,
ENV_MORNING,
ENV_DAY,
ENV_DUSK,
ENV_NIGHT
ENV_PLAINS,
ENV_PLAINS_NIGHT,
ENV_FOREST,
ENV_FOREST_NIGHT,
ENV_SNOW,
ENV_SNOW_NIGHT,
ENV_OCEAN,
ENV_DESERT,
ENV_DESERT_NIGHT,
ENV_JUNGLE,
ENV_JUNGLE_NIGHT
};
ambiance_environment a_env[8];
enum time_of_day {
MORNING,
DAY,
DUSK,
NIGHT
};
ambiance_environment a_env[15];
const std::string DIRT = "default:dirt";//m_env.getGameDef()->getNodeDefManager()->getId("default:dirt");
const std::string STONE = "default:stone";//m_env.getGameDef()->getNodeDefManager()->getId("default:stone");
const std::string GRASS = "default:dirt_with_grass";//m_env.getGameDef()->getNodeDefManager()->getId("default:dirt_with_grass");
const std::string TREE = "default:tree";//m_env.getGameDef()->getNodeDefManager()->getId("default:tree");
const std::string LEAVES = "default:leaves";//m_env.getGameDef()->getNodeDefManager()->getId("default:leaves");
const std::string WATER = "default:water_source";//m_env.getGameDef()->getNodeDefManager()->getId("default:water_source");
const std::string WATER_FLOWING = "default:water_flowing";//m_env.getGameDef()->getNodeDefManager()->getId("default:water_flowing");
const std::string SNOW = "default:snow";
const std::string DIRT_SNOW = "default:dirt_with_snow";
const std::string SAND = "default:sand";
const std::string DESERT_STONE = "default:desert_stone";
const std::string DESERT_SAND = "default:desert_sand";
const std::string JUNGLE_TREE = "default:jungletree";
const std::string JUNGLE_LEAVES = "default:jungleleaves";
const std::string JUNGLE_GRASS = "default:junglegrass";
int readEnvironment();
};
#endif /* SRC_AMBIANCE_H_ */

View File

@ -484,7 +484,7 @@ void Client::step(float dtime)
m_env.step(dtime);
if ( g_settings->getBool("ambiance") ){
m_ambiance->doAmbiance(dtime);
m_ambiance->doAmbiance(dtime,m_env.getTimeOfDay());
}
/*