Fix "no remove aqua speed" bug when player leaves the water
[ryzomcore.git] / nel / src / sound / context_sound.cpp
blobc03a1cc4f495e962957d3ee2b4cd3f1335965ad5
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdsound.h"
23 #include "nel/sound/context_sound.h"
24 #include "nel/sound/sound_bank.h"
26 using namespace std;
27 using namespace NLMISC;
31 namespace NLSOUND {
34 //CContextSound test;
37 /// Constructor
38 CContextSound::CContextSound()
39 : _ContextSounds(0)
42 /// Destructor
43 CContextSound::~CContextSound()
45 if (_ContextSounds != 0)
46 delete _ContextSounds;
49 void CContextSound::serial(NLMISC::IStream &s)
51 CSound::serial(s);
52 s.serial(_PatternName);
54 if (s.isReading())
56 if (_ContextSounds)
57 delete _ContextSounds;
62 /// Load the sound parameters from georges' form
63 void CContextSound::importForm(const std::string& filename, NLGEORGES::UFormElm& formRoot)
65 NLGEORGES::UFormElm *psoundType;
66 std::string dfnName;
68 // some basic checking.
69 formRoot.getNodeByName(&psoundType, ".SoundType");
70 nlassert(psoundType != NULL);
71 psoundType->getDfnName(dfnName);
72 nlassert(dfnName == "context_sound.dfn");
74 // Call the base class
75 CSound::importForm(filename, formRoot);
77 // Read the pattern name
78 formRoot.getValueByName(_PatternName, ".SoundType.PatternName");
81 /// Return true if cone is meaningful
82 bool CContextSound::isDetailed() const
84 return false;
87 float CContextSound::getMaxDistance() const
89 if (_ContextSounds == 0)
91 const_cast<CContextSound*>(this)->init();
92 if (_ContextSounds == 0)
94 // invalid state
95 return 0;
98 return _ContextSounds->getMaxDistance();;
101 /// Return the length of the sound in ms
102 uint32 CContextSound::getDuration()
104 std::vector<std::pair<std::string, CSound*> > sounds;
105 getSubSoundList(sounds);
107 uint32 duration = 0;
109 std::vector<std::pair<std::string, CSound*> >::iterator first(sounds.begin()), last(sounds.end());
110 for (; first != last; ++first)
112 duration = std::max(duration, first->second->getDuration());
114 return duration;
117 /// Used by the george sound plugin to check sound recursion (ie sound 'toto' use sound 'titi' witch also use sound 'toto' ...).
118 void CContextSound::getSubSoundList(std::vector<std::pair<std::string, CSound*> > &subsounds) const
120 if (_ContextSounds == 0)
122 const_cast<CContextSound*>(this)->init();
125 if (_ContextSounds)
127 _ContextSounds->getSoundList(subsounds);
131 CSound *CContextSound::getContextSound(CSoundContext &context)
133 if (_ContextSounds == 0)
135 // need to init the sound container.
136 init();
138 if (_ContextSounds == 0)
139 return 0;
142 if (_Random > 1)
144 // compute the random value.
145 uint32 r;
148 r = rand()%_Random;
149 } while (r == context.PreviousRandom);
151 context.PreviousRandom = r;
153 return _ContextSounds->getSound(context, r);
155 else
156 return _ContextSounds->getSound(context, 0);
161 void CContextSound::init()
163 uint nbJoker = 0;
164 uint contextArgIndex[SoundContextNbArgs];
165 bool useRandom = false;
166 bool parseArg = false;
167 _BaseName.clear();
169 //nldebug("Init the context sound %s", _PatternName.c_str());
171 string::iterator first(_PatternName.begin()), last(_PatternName.end());
172 // 1st loop until the first joker
173 for(; first != last && *first != '%'; ++first)
174 _BaseName += *first;
176 // 2nd loop, now we read the context arg index for each joker.
177 std::string index;
178 for (; first != last; ++first)
180 if (parseArg)
182 if (isdigit(int(*first)))
184 index += *first;
186 else if (!index.empty())
188 if (useRandom)
190 fromString(index, _Random);
192 else
194 nlassertex(nbJoker < SoundContextNbArgs, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
195 fromString(index, contextArgIndex[nbJoker++]);
196 parseArg = false;
197 index.clear();
200 else if (*first == 'r')
202 nlassertex(useRandom == false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
203 useRandom = true;
206 else if (*first == '%')
208 nlassertex(useRandom == false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
209 parseArg = true;
213 // read the last char...
214 if (!index.empty())
216 if (useRandom)
218 fromString(index, _Random);
220 else
222 nlassertex(nbJoker < SoundContextNbArgs, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
223 fromString(index, contextArgIndex[nbJoker++]);
224 parseArg = false;
228 if (_ContextSounds != 0)
229 delete _ContextSounds;
231 // A little macro to make life easier (LM stand for Local Macro)
232 #define LM_CASE_CONTAINER_CREATOR(size) case (size):\
233 if (useRandom)\
234 _ContextSounds = new CContextSoundContainer<(size), true>;\
235 else\
236 _ContextSounds = new CContextSoundContainer<(size), false>;\
237 break;
239 // ok, now instantiate the correct container
240 switch (nbJoker)
242 LM_CASE_CONTAINER_CREATOR(0)
243 LM_CASE_CONTAINER_CREATOR(1)
244 LM_CASE_CONTAINER_CREATOR(2)
245 LM_CASE_CONTAINER_CREATOR(3)
246 LM_CASE_CONTAINER_CREATOR(4)
247 LM_CASE_CONTAINER_CREATOR(5)
248 LM_CASE_CONTAINER_CREATOR(6)
249 LM_CASE_CONTAINER_CREATOR(7)
250 LM_CASE_CONTAINER_CREATOR(8)
251 LM_CASE_CONTAINER_CREATOR(9)
252 LM_CASE_CONTAINER_CREATOR(10)
253 default:
254 nlwarning("Unsuported number of context argument in context sound '%s'!", CStringMapper::unmap(_Name).c_str());
255 return;
257 // cleanup macro
258 #undef LM_CASE_CONTAINER_CREATOR
260 _ContextSounds->init(contextArgIndex);
262 // ok, we have the container, now fill it with the sound
264 std::vector<NLMISC::TStringId> allSounds;
265 // CSoundBank::getSoundNames(allSounds);
266 CAudioMixerUser::instance()->getSoundNames(allSounds);
268 std::vector<NLMISC::TStringId>::iterator first(allSounds.begin()), last(allSounds.end());
269 for (; first != last; ++first)
271 const std::string &soundName = CStringMapper::unmap(*first);
272 if (soundName.size() > _BaseName.size())
274 uint i;
275 for (i=0; i<_BaseName.size(); ++i)
277 if (soundName[i] != _BaseName[i])
278 break;
280 if (i == _BaseName.size())
282 // The base name is ok, check that the next char is a digit (avoid conflit if some
283 // sound have a longeur base name with same beginning)
284 if (soundName[i] >= '0' && soundName[i] <= '9')
285 _ContextSounds->addSound(CAudioMixerUser::instance()->getSoundId(*first), _BaseName);
294 } // NLSOUND