Add event manager and use it to trigger sounds
authorPerttu Ahola <celeron55@gmail.com>
Fri, 23 Mar 2012 18:23:03 +0000 (20:23 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 24 Mar 2012 02:24:26 +0000 (04:24 +0200)
15 files changed:
games/mesetint/mods/default/init.lua
src/camera.cpp
src/client.cpp
src/client.h
src/event.h [new file with mode: 0644]
src/event_manager.h [new file with mode: 0644]
src/game.cpp
src/gamedef.h
src/nodedef.cpp
src/nodedef.h
src/player.cpp
src/scriptapi.cpp
src/server.cpp
src/server.h
src/sound.h

index c850597ba9b0b23a0b4b32a058c233e43920c8dc..0041e3588b962ea0c6008fd7925251768329c233 100644 (file)
@@ -654,6 +654,10 @@ minetest.register_node("default:dirt_with_grass", {
        is_ground_content = true,
        groups = {crumbly=3},
        drop = 'default:dirt',
+       sounds = {
+               --footstep = "default_grass_footstep",
+               footstep = {name="default_grass_footstep", gain=0.5},
+       },
 })
 
 minetest.register_node("default:dirt_with_grass_footsteps", {
index 8dad8dc63e59d7c7ec99414c7237cb073d9a6de0..fada476085dabe4368f8d4f9bdd2bf5c3798428d 100644 (file)
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "noise.h" // easeCurve
 #include "gamedef.h"
 #include "sound.h"
+#include "event.h"
 
 Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
                IGameDef *gamedef):
@@ -177,8 +178,10 @@ void Camera::step(f32 dtime)
                        bool step = (was == 0 ||
                                        (was < 0.5f && m_view_bobbing_anim >= 0.5f) ||
                                        (was > 0.5f && m_view_bobbing_anim <= 0.5f));
-                       if(step)
-                               m_gamedef->sound()->playSound("default_grass_walk", false, 1.0);
+                       if(step){
+                               MtEvent *e = new SimpleTriggerEvent("ViewBobbingStep");
+                               m_gamedef->event()->put(e);
+                       }
                }
        }
 
@@ -190,7 +193,8 @@ void Camera::step(f32 dtime)
                {
                        m_digging_anim = 0;
                        m_digging_button = -1;
-                       m_gamedef->sound()->playSound("dig", false, 1.0);
+                       MtEvent *e = new SimpleTriggerEvent("CameraDig");
+                       m_gamedef->event()->put(e);
                }
        }
 }
index cb6d2075ec017796fc621514947752cf25f5758a..d8fb4eb772e23dc8932151280ed700ac62496550 100644 (file)
@@ -226,12 +226,14 @@ Client::Client(
                IWritableTextureSource *tsrc,
                IWritableItemDefManager *itemdef,
                IWritableNodeDefManager *nodedef,
-               ISoundManager *sound
+               ISoundManager *sound,
+               MtEventManager *event
 ):
        m_tsrc(tsrc),
        m_itemdef(itemdef),
        m_nodedef(nodedef),
        m_sound(sound),
+       m_event(event),
        m_mesh_update_thread(this),
        m_env(
                new ClientMap(this, this, control,
@@ -2330,4 +2332,8 @@ ISoundManager* Client::getSoundManager()
 {
        return m_sound;
 }
+MtEventManager* Client::getEventManager()
+{
+       return m_event;
+}
 
index 2a1681e92e9225ab100bd58281fe5cc3293d4877..13b36106c9f18e606874a34d9fc4580ad5a16b09 100644 (file)
@@ -44,6 +44,7 @@ class IWritableNodeDefManager;
 //class IWritableCraftDefManager;
 class ClientEnvironment;
 struct MapDrawControl;
+class MtEventManager;
 
 class ClientNotReadyException : public BaseException
 {
@@ -175,7 +176,8 @@ public:
                        IWritableTextureSource *tsrc,
                        IWritableItemDefManager *itemdef,
                        IWritableNodeDefManager *nodedef,
-                       ISoundManager *sound
+                       ISoundManager *sound,
+                       MtEventManager *event
        );
        
        ~Client();
@@ -308,6 +310,7 @@ public:
        virtual ITextureSource* getTextureSource();
        virtual u16 allocateUnknownNodeId(const std::string &name);
        virtual ISoundManager* getSoundManager();
+       virtual MtEventManager* getEventManager();
 
 private:
        
@@ -335,6 +338,8 @@ private:
        IWritableItemDefManager *m_itemdef;
        IWritableNodeDefManager *m_nodedef;
        ISoundManager *m_sound;
+       MtEventManager *m_event;
+
        MeshUpdateThread m_mesh_update_thread;
        ClientEnvironment m_env;
        con::Connection m_con;
diff --git a/src/event.h b/src/event.h
new file mode 100644 (file)
index 0000000..032cb23
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef EVENT_HEADER
+#define EVENT_HEADER
+
+class MtEvent
+{
+public:
+       virtual ~MtEvent(){};
+       //virtual MtEvent* clone(){ return new IEvent; }
+       virtual const char* getType() const = 0;
+
+       MtEvent* checkIs(const std::string &type)
+       {
+               if(type == getType())
+                       return this;
+               return NULL;
+       }
+};
+
+// An event with no parameters and customizable name
+class SimpleTriggerEvent: public MtEvent
+{
+       const char *type;
+public:
+       SimpleTriggerEvent(const char *type):
+               type(type)
+       {}
+       const char* getType() const
+       {return type;}
+};
+
+class MtEventReceiver
+{
+public:
+       virtual ~MtEventReceiver(){};
+       virtual void onEvent(MtEvent *e) = 0;
+};
+
+typedef void (*event_receive_func)(MtEvent *e, void *data);
+
+class MtEventManager
+{
+public:
+       virtual ~MtEventManager(){};
+       virtual void put(MtEvent *e) = 0;
+       virtual void reg(const char *type, event_receive_func f, void *data) = 0;
+       // If data==NULL, every occurence of f is deregistered.
+       virtual void dereg(const char *type, event_receive_func f, void *data) = 0;
+       virtual void reg(MtEventReceiver *r, const char *type) = 0;
+       virtual void dereg(MtEventReceiver *r, const char *type) = 0;
+};
+
+#endif
+
diff --git a/src/event_manager.h b/src/event_manager.h
new file mode 100644 (file)
index 0000000..b33d5a2
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef EVENT_MANAGER_HEADER
+#define EVENT_MANAGER_HEADER
+
+#include "event.h"
+#include <list>
+#include <map>
+
+class EventManager: public MtEventManager
+{
+       static void receiverReceive(MtEvent *e, void *data)
+       {
+               MtEventReceiver *r = (MtEventReceiver*)data;
+               r->onEvent(e);
+       }
+       struct FuncSpec{
+               event_receive_func f;
+               void *d;
+               FuncSpec(event_receive_func f, void *d):
+                       f(f), d(d)
+               {}
+       };
+       struct Dest{
+               std::list<FuncSpec> funcs;
+       };
+       std::map<std::string, Dest> m_dest;
+
+public:
+       ~EventManager()
+       {
+       }
+       void put(MtEvent *e)
+       {
+               std::map<std::string, Dest>::iterator i = m_dest.find(e->getType());
+               if(i != m_dest.end()){
+                       std::list<FuncSpec> &funcs = i->second.funcs;
+                       for(std::list<FuncSpec>::iterator i = funcs.begin();
+                                       i != funcs.end(); i++){
+                               (*(i->f))(e, i->d);
+                       }
+               }
+               delete e;
+       }
+       void reg(const char *type, event_receive_func f, void *data)
+       {
+               std::map<std::string, Dest>::iterator i = m_dest.find(type);
+               if(i != m_dest.end()){
+                       i->second.funcs.push_back(FuncSpec(f, data));
+               } else{
+                       std::list<FuncSpec> funcs;
+                       Dest dest;
+                       dest.funcs.push_back(FuncSpec(f, data));
+                       m_dest[type] = dest;
+               }
+       }
+       void dereg(const char *type, event_receive_func f, void *data)
+       {
+               if(type != NULL){
+                       std::map<std::string, Dest>::iterator i = m_dest.find(type);
+                       if(i != m_dest.end()){
+                               std::list<FuncSpec> &funcs = i->second.funcs;
+                               std::list<FuncSpec>::iterator i = funcs.begin();
+                               while(i != funcs.end()){
+                                       bool remove = (i->f == f && (!data || i->d == data));
+                                       if(remove)
+                                               funcs.erase(i++);
+                                       else
+                                               i++;
+                               }
+                       }
+               } else{
+                       for(std::map<std::string, Dest>::iterator
+                                       i = m_dest.begin(); i != m_dest.end(); i++){
+                               std::list<FuncSpec> &funcs = i->second.funcs;
+                               std::list<FuncSpec>::iterator i = funcs.begin();
+                               while(i != funcs.end()){
+                                       bool remove = (i->f == f && (!data || i->d == data));
+                                       if(remove)
+                                               funcs.erase(i++);
+                                       else
+                                               i++;
+                               }
+                       }
+               }
+       }
+       void reg(MtEventReceiver *r, const char *type)
+       {
+               reg(type, EventManager::receiverReceive, r);
+       }
+       void dereg(MtEventReceiver *r, const char *type)
+       {
+               dereg(type, EventManager::receiverReceive, r);
+       }
+};
+
+#endif
+
index 1b24df59bd8b3ccf8f087d43acc95e0d8df9c537..4c9442c00a65a3a01138a0619ab1d6a2a603f6b7 100644 (file)
@@ -59,6 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #if USE_AUDIO
        #include "sound_openal.h"
 #endif
+#include "event_manager.h"
 #include <list>
 
 /*
@@ -779,6 +780,58 @@ public:
        }
 };
 
+class SoundMaker
+{
+public:
+       ISoundManager *m_sound;
+
+       SimpleSoundSpec m_player_step_sound;
+       float m_player_step_timer;
+
+       SoundMaker(ISoundManager *sound):
+               m_sound(sound),
+               m_player_step_sound("default_grass_walk"),
+               m_player_step_timer(0)
+       {
+       }
+
+       void playPlayerStep()
+       {
+               if(m_player_step_timer <= 0 && m_player_step_sound.exists()){
+                       m_player_step_timer = 0.03;
+                       m_sound->playSound(m_player_step_sound, false);
+               }
+       }
+
+       static void viewBobbingStep(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker*)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerRegainGround(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker*)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerJump(MtEvent *e, void *data)
+       {
+       }
+
+       void registerReceiver(MtEventManager *mgr)
+       {
+               mgr->reg("ViewBobbingStep", SoundMaker::viewBobbingStep, this);
+               mgr->reg("PlayerRegainGround", SoundMaker::playerRegainGround, this);
+               mgr->reg("PlayerJump", SoundMaker::playerJump, this);
+       }
+
+       void step(float dtime)
+       {
+               m_player_step_timer -= dtime;
+       }
+};
+
 void the_game(
        bool &kill,
        bool random_input,
@@ -841,10 +894,19 @@ void the_game(
                sound = &dummySoundManager;
                sound_is_dummy = true;
        }
+
+       // Event manager
+       EventManager eventmgr;
+
+       // Sound maker
+       SoundMaker soundmaker(sound);
+       soundmaker.registerReceiver(&eventmgr);
        
        // Test sounds
-       sound->loadSound("default_grass_walk", porting::path_share + DIR_DELIM
+       sound->loadSound("default_grass_footstep", porting::path_share + DIR_DELIM
                        + "sounds" + DIR_DELIM + "default_grass_walk3_mono.ogg");
+       sound->loadSound("default_grass_footstep", porting::path_share + DIR_DELIM
+                       + "sounds" + DIR_DELIM + "default_grass_walk4_mono.ogg");
        //sound->playSound("default_grass_walk", false, 1.0);
        //sound->playSoundAt("default_grass_walk", true, 1.0, v3f(0,10,0)*BS);
 
@@ -879,7 +941,7 @@ void the_game(
        MapDrawControl draw_control;
 
        Client client(device, playername.c_str(), password, draw_control,
-                       tsrc, itemdef, nodedef, sound);
+                       tsrc, itemdef, nodedef, sound, &eventmgr);
        
        // Client acts as our GameDef
        IGameDef *gamedef = &client;
@@ -1257,7 +1319,7 @@ void the_game(
                if(object_hit_delay_timer >= 0)
                        object_hit_delay_timer -= dtime;
                time_from_last_punch += dtime;
-
+               
                g_profiler->add("Elapsed time", dtime);
                g_profiler->avg("FPS", 1./dtime);
 
@@ -1954,6 +2016,17 @@ void the_game(
                                camera.getCameraNode()->getTarget(),
                                camera.getCameraNode()->getUpVector());
 
+               /*
+                       Update sound maker
+               */
+               {
+                       soundmaker.step(dtime);
+                       
+                       ClientMap &map = client.getEnv().getClientMap();
+                       MapNode n = map.getNodeNoEx(player->getStandingNodePos());
+                       soundmaker.m_player_step_sound = nodedef->get(n).sound_footstep;
+               }
+
                /*
                        Calculate what block is the crosshair pointing to
                */
index 91bcc0e6594bbe1cc46d1b397fe00a81b0c1804d..3b5ad5caeeadfc60f5788ca4c0b77d035f27db41 100644 (file)
@@ -28,6 +28,7 @@ class INodeDefManager;
 class ICraftDefManager;
 class ITextureSource;
 class ISoundManager;
+class MtEventManager;
 
 /*
        An interface for fetching game-global definitions like tool and
@@ -47,17 +48,19 @@ public:
        // pointers in other threads than main thread will make things explode.
        virtual ITextureSource* getTextureSource()=0;
        
-       virtual ISoundManager* getSoundManager()=0;
-       
        // Used for keeping track of names/ids of unknown nodes
        virtual u16 allocateUnknownNodeId(const std::string &name)=0;
 
+       virtual ISoundManager* getSoundManager()=0;
+       virtual MtEventManager* getEventManager()=0;
+       
        // Shorthands
        IItemDefManager* idef(){return getItemDefManager();}
        INodeDefManager* ndef(){return getNodeDefManager();}
        ICraftDefManager* cdef(){return getCraftDefManager();}
        ITextureSource* tsrc(){return getTextureSource();}
        ISoundManager* sound(){return getSoundManager();}
+       MtEventManager* event(){return getEventManager();}
 };
 
 #endif
index f1946830f3700afb94ccd8d271fa44f2ee83b45c..2a21136bf58b966538fb8976eaf794d507091f75 100644 (file)
@@ -78,6 +78,22 @@ void MaterialSpec::deSerialize(std::istream &is)
        backface_culling = readU8(is);
 }
 
+/*
+       SimpleSoundSpec serialization
+*/
+
+static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
+               std::ostream &os)
+{
+       os<<serializeString(ss.name);
+       writeF1000(os, ss.gain);
+}
+static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
+{
+       ss.name = deSerializeString(is);
+       ss.gain = readF1000(is);
+}
+
 /*
        ContentFeatures
 */
@@ -139,6 +155,7 @@ void ContentFeatures::reset()
        selection_box = NodeBox();
        legacy_facedir_simple = false;
        legacy_wallmounted = false;
+       sound_footstep = SimpleSoundSpec();
 }
 
 void ContentFeatures::serialize(std::ostream &os)
@@ -185,6 +202,7 @@ void ContentFeatures::serialize(std::ostream &os)
        selection_box.serialize(os);
        writeU8(os, legacy_facedir_simple);
        writeU8(os, legacy_wallmounted);
+       serializeSimpleSoundSpec(sound_footstep, os);
 }
 
 void ContentFeatures::deSerialize(std::istream &is)
@@ -236,6 +254,9 @@ void ContentFeatures::deSerialize(std::istream &is)
        selection_box.deSerialize(is);
        legacy_facedir_simple = readU8(is);
        legacy_wallmounted = readU8(is);
+       try{
+               deSerializeSimpleSoundSpec(sound_footstep, is);
+       }catch(SerializationError &e) {};
 }
 
 /*
index 2842b81e727204c606950c000ed92e73a5c87a05..3a0d0675fee076f2515c6e29514436b6d8305916 100644 (file)
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef NODEDEF_HEADER
 #define NODEDEF_HEADER
 
-#include "common_irrlicht.h"
+#include "irrlichttypes.h"
 #include <string>
 #include <iostream>
 #include <map>
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tile.h"
 #endif
 #include "itemgroup.h"
+#include "sound.h" // SimpleSoundSpec
 class IItemDefManager;
 class ITextureSource;
 class IGameDef;
@@ -200,6 +201,9 @@ struct ContentFeatures
        // Set to true if wall_mounted used to be set to true
        bool legacy_wallmounted;
 
+       // Sound properties
+       SimpleSoundSpec sound_footstep;
+
        /*
                Methods
        */
index 48d2c2907abebac43b1cd9607ae5d0fa9211cf92..0d4a1cb695c05553fb9c21c7b8ac2273f7122475 100644 (file)
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "collision.h"
 #include "environment.h"
 #include "gamedef.h"
+#include "event.h"
 
 Player::Player(IGameDef *gamedef):
        touching_ground(false),
@@ -367,6 +368,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
 
                Player is allowed to jump when this is true.
        */
+       bool touching_ground_was = touching_ground;
        touching_ground = false;
 
        /*std::cout<<"Checking collisions for ("
@@ -608,6 +610,11 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                        collision_info->push_back(info);
                }
        }
+
+       if(!touching_ground_was && touching_ground){
+               MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
+               m_gamedef->event()->put(e);
+       }
 }
 
 void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
@@ -723,6 +730,9 @@ void LocalPlayer::applyControl(float dtime)
                        {
                                speed.Y = 6.5*BS;
                                setSpeed(speed);
+                               
+                               MtEvent *e = new SimpleTriggerEvent("PlayerJump");
+                               m_gamedef->event()->put(e);
                        }
                }
                // Use the oscillating value for getting out of water
index 27ab2950be7c404446e605cc79f8f967d97f270d..79da15c494044679382a606efac1f20286e937d6 100644 (file)
@@ -807,6 +807,25 @@ static void push_pointed_thing(lua_State *L, const PointedThing& pointed)
        }
 }
 
+/*
+       SimpleSoundSpec
+*/
+
+static SimpleSoundSpec read_soundspec(lua_State *L, int index)
+{
+       if(index < 0)
+               index = lua_gettop(L) + 1 + index;
+       SimpleSoundSpec spec;
+       if(lua_isnil(L, index)){
+       } else if(lua_istable(L, index)){
+               getstringfield(L, index, "name", spec.name);
+               getfloatfield(L, index, "gain", spec.gain);
+       } else if(lua_isstring(L, index)){
+               spec.name = lua_tostring(L, index);
+       }
+       return spec;
+}
+
 /*
        ItemDefinition
 */
@@ -1038,6 +1057,15 @@ static ContentFeatures read_content_features(lua_State *L, int index)
        getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
        // Set to true if wall_mounted used to be set to true
        getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
+       
+       // Sound table
+       lua_getfield(L, index, "sounds");
+       if(lua_istable(L, -1)){
+               lua_getfield(L, -1, "footstep");
+               f.sound_footstep = read_soundspec(L, -1);
+               lua_pop(L, 1);
+       }
+       lua_pop(L, 1);
 
        return f;
 }
index d762f2688d0d80dd458512ded1938065ca494cda..e781f1284984c6151edef2ddb51695d0ec60d45d 100644 (file)
@@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tool.h"
 #include "utility_string.h"
 #include "sound.h" // dummySoundManager
+#include "event_manager.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -853,6 +854,7 @@ Server::Server(
        m_itemdef(createItemDefManager()),
        m_nodedef(createNodeDefManager()),
        m_craftdef(createCraftDefManager()),
+       m_event(new EventManager()),
        m_thread(this),
        m_emergethread(this),
        m_time_of_day_send_timer(0),
@@ -1064,10 +1066,10 @@ Server::~Server()
                        delete i.getNode()->getValue();
                }
        }
-
-       // Delete Environment
+       
+       // Delete things in the reverse order of creation
        delete m_env;
-
+       delete m_event;
        delete m_itemdef;
        delete m_nodedef;
        delete m_craftdef;
@@ -4275,6 +4277,10 @@ ISoundManager* Server::getSoundManager()
 {
        return &dummySoundManager;
 }
+MtEventManager* Server::getEventManager()
+{
+       return m_event;
+}
 
 IWritableItemDefManager* Server::getWritableItemDefManager()
 {
index cdedd06d89aec7c5714b01cfb2b9b3ce48f290f7..3baeb433df261079ab811f5c3b909789085bf523 100644 (file)
@@ -40,6 +40,7 @@ typedef struct lua_State lua_State;
 class IWritableItemDefManager;
 class IWritableNodeDefManager;
 class IWritableCraftDefManager;
+class EventManager;
 
 class ServerError : public std::exception
 {
@@ -514,6 +515,7 @@ public:
        virtual ITextureSource* getTextureSource();
        virtual u16 allocateUnknownNodeId(const std::string &name);
        virtual ISoundManager* getSoundManager();
+       virtual MtEventManager* getEventManager();
        
        IWritableItemDefManager* getWritableItemDefManager();
        IWritableNodeDefManager* getWritableNodeDefManager();
@@ -684,6 +686,9 @@ private:
        // Craft definition manager
        IWritableCraftDefManager *m_craftdef;
        
+       // Event manager
+       EventManager *m_event;
+       
        // Mods
        core::list<ModSpec> m_mods;
        
index 72764345e641ae2eb8c1fc268b303320075d6971..6363d614eb21df0e82e4e22c5a3c875680227a54 100644 (file)
@@ -33,6 +33,18 @@ public:
                        std::set<std::vector<char> > &dst_datas) = 0;
 };
 
+struct SimpleSoundSpec
+{
+       std::string name;
+       float gain;
+       SimpleSoundSpec(std::string name="", float gain=1.0):
+               name(name),
+               gain(gain)
+       {}
+       bool exists() {return name != "";}
+       // Serialization intentionally left out
+};
+
 class ISoundManager
 {
 public:
@@ -47,6 +59,7 @@ public:
                        const std::vector<char> &filedata) = 0;
 
        virtual void updateListener(v3f pos, v3f vel, v3f at, v3f up) = 0;
+
        // playSound functions return -1 on failure, otherwise a handle to the
        // sound
        virtual int playSound(const std::string &name, bool loop,
@@ -54,6 +67,11 @@ public:
        virtual int playSoundAt(const std::string &name, bool loop,
                        float volume, v3f pos) = 0;
        virtual void stopSound(int sound) = 0;
+
+       int playSound(const SimpleSoundSpec &spec, bool loop)
+               { return playSound(spec.name, loop, spec.gain); }
+       int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos)
+               { return playSoundAt(spec.name, loop, spec.gain, pos); }
 };
 
 class DummySoundManager: public ISoundManager