1 #include "pch.h"
2 #include "par.h"
3 #include "car.h"
4 #include "cardefs.h"
5 #include "configfile.h"
6 #include "collision_world.h"
7 #include "tracksurface.h"
8 #include "configfile.h"
9 #include "settings.h"
10 #include "../ogre/CGame.h" // replay
11 #include "../ogre/CarModel.h" // camera pos
12 #include "../ogre/FollowCamera.h" // camera pos
13 #include "../ogre/common/Def_Str.h"
14 #include "../ogre/common/data/SceneXml.h"
15 #include "../ogre/common/CScene.h"
16 #include "../ogre/common/GraphView.h"
17 #include "../ogre/common/Axes.h"
18 #include "../network/protocol.hpp"
19 #include "tobullet.h"
20 #include "game.h"
21 #include "../ogre/SplitScreen.h" // num plr
22 #include "../sound/SoundMgr.h"
23 #include "../sound/SoundBase.h"
24 #include "../sound/SoundBaseMgr.h"
25 #include <OgreCamera.h>
26 using namespace std;
27 using namespace Ogre;
28
29
30 // Load
31 //--------------------------------------------------------------------------------------------------------------------------
LoadSounds(const std::string & carpath)32 bool CAR::LoadSounds(const std::string & carpath)
33 {
34 Ogre::Timer ti;
35 bool ss = pApp->pSet->game.local_players > 1;
36 CARsounds& s = sounds;
37
38 SoundMgr* snd = pGame->snd;
39 const string& eng = dynamics.engine.sound_name;
40 s.engine = snd->createInstance(eng,0); s.engine->set2D(ss);
41 s.engine->setEngine(true); s.engine->start();
42
43 int i; float fw = numWheels;
44 for (i = 0; i < numWheels; ++i) // tires
45 {
46 s.asphalt[i] = snd->createInstance("asphalt", 0); s.asphalt[i]->set2D(ss);
47 s.grass[i] = snd->createInstance("grass", 0);
48 s.grass[i]->seek(float(i)/fw); s.grass[i]->set2D(ss);
49 s.gravel[i] = snd->createInstance("gravel", 0);
50 s.gravel[i]->seek(float(i)/fw); s.gravel[i]->set2D(ss);
51 }
52 for (i = 0; i < numWheels; ++i)
53 {
54 s.bump[i] = snd->createInstance("bump"+toStr(i%4), 0); s.bump[i]->set2D(ss);
55 s.bump[i]->seek(float(i)/fw);
56 }
57
58 for (i = 0; i < Ncrashsounds; ++i) // crashes
59 { string cn = "crash/"; int n=i+1; cn += toStr(n/10)+toStr(n%10);
60 s.crash[i] = snd->createInstance(cn, 0); s.crash[i]->set2D(ss);
61 }
62 s.scrap = snd->createInstance("crash/scrap", 0); s.scrap->set2D(ss);
63 s.screech = snd->createInstance("crash/screech",0); s.screech->set2D(ss);
64
65 s.wind = snd->createInstance("wind", 0); s.wind->set2D(ss);
66 s.boost = snd->createInstance("boost", 0); s.boost->set2D(ss);
67
68 for (i = 0; i < Nwatersounds; ++i) // fluids
69 { s.water[i] = snd->createInstance("water"+toStr(i+1), 0); s.water[i]->set2D(ss); }
70
71 s.mud = snd->createInstance("mud1", 0); s.mud->set2D(ss);
72 s.mud_cont = snd->createInstance("mud_cont", 0); s.mud_cont->set2D(ss);
73 s.water_cont = snd->createInstance("water_cont", 0); s.water_cont->set2D(ss);
74
75 LogO("::: Time car Sounds: "/*+carpath+" "*/+ fToStr(ti.getMilliseconds(),0,3) +" ms");
76 return true;
77 }
78
79 // ctor
CARsounds()80 CAR::CARsounds::CARsounds()
81 :fluidHitOld(0), whMudSpin(0.f)
82 {
83 int i;
84 crashtime.resize(Ncrashsounds);
85 for (int i=0; i < Ncrashsounds; ++i)
86 crashtime[i] = 0.f;
87
88 engine = 0;
89 SetNumWheels(4);
90 for (i = 0; i < 4; ++i) // tires
91 { asphalt[i] = 0; grass[i] = 0; gravel[i] = 0; bump[i] = 0; }
92
93 crash.resize(Ncrashsounds);
94 for (i = 0; i < Ncrashsounds; ++i) // crashes
95 crash[i] = 0;
96
97 scrap = 0; screech = 0;
98 wind = 0; boost = 0;
99
100 water.resize(Nwatersounds);
101 for (i = 0; i < Nwatersounds; ++i) // fluids
102 water[i] = 0;
103
104 mud = 0; mud_cont = 0; water_cont = 0;
105 }
106
SetNumWheels(int n)107 void CAR::CARsounds::SetNumWheels(int n)
108 {
109 asphalt.resize(n); grass.resize(n); gravel.resize(n); bump.resize(n);
110 bumptime.resize(n); bumpvol.resize(n);
111 for (int i=0; i < n; ++i)
112 { bumpvol[i]=0.f; bumptime[i] = 5.f; }
113 }
114
Destroy()115 void CAR::CARsounds::Destroy()
116 {
117 delete engine;
118 int i;
119 for (i = 0; i < gravel.size(); ++i) // tires
120 {
121 delete asphalt[i];
122 delete grass[i];
123 delete gravel[i];
124 delete bump[i];
125 }
126
127 for (i = 0; i < Ncrashsounds; ++i) // crashes
128 delete crash[i];
129
130 delete scrap; delete screech;
131
132 delete wind; delete boost;
133
134 for (i = 0; i < Nwatersounds; ++i) // fluids
135 delete water[i];
136
137 delete mud; delete mud_cont; delete water_cont;
138 }
139
140
141 //--------------------------------------------------------------------------------------------------------------------------
UpdateSounds(float dt)142 void CAR::UpdateSounds(float dt)
143 {
144 // get data //
145 // note: Damage is updated here
146 bool bSound = !pGame->snd->isDisabled();
147 CARsounds& s = sounds;
148
149 float rpm, throttle, speed, dynVel; bool hitp = false;
150 MATHVECTOR<float,3> pos, engPos, whPos[MAX_WHEELS], hitPos; // car, engine, wheels pos
151 QUATERNION<float> rot;
152 TRACKSURFACE::TYPE surfType[MAX_WHEELS];
153 float squeal[MAX_WHEELS],whVel[MAX_WHEELS], suspVel[MAX_WHEELS],suspDisp[MAX_WHEELS];
154 float whH_all = 0.f; bool mud = false;
155 float fHitForce = 0.f, boostVal = 0.f, fCarScrap = 0.f, fCarScreech = 0.f;
156
157 bool dmg = pSet->game.damage_type > 0, reduced = pSet->game.damage_type==1;
158 bool terminal = dynamics.fDamage >= 100.f;
159 float fDmg = pApp->scn->sc->damageMul;
160
161 /// replay play ------------------------------------------
162 if (pApp->bRplPlay)
163 { dmg = false;
164
165 #ifdef DEBUG
166 assert(id < pApp->frm.size());
167 #endif
168 const ReplayFrame2& fr = pApp->frm[id];
169 pos = fr.pos; rot = fr.rot; rpm = fr.rpm;
170 throttle = fr.throttle /255.f; boostVal = fr.fboost /255.f;
171 dynamics.fDamage = fr.damage /255.f*100.f; //dmg read
172
173 MATHVECTOR<float,3> offset = dynamics.engine.GetPosition();
174 rot.RotateVector(offset);
175 engPos = offset + pos;
176
177 speed = fr.speed; dynVel = fr.dynVel;
178 s.whMudSpin = fr.get(b_fluid) ? fr.whMudSpin : 0.f;
179
180 if (fr.get(b_scrap))
181 {
182 const RScrap& sc = fr.scrap[0];
183 fCarScrap = sc.fScrap; fCarScreech = sc.fScreech;
184 }
185
186 hitp = fr.get(b_hit);
187 if (hitp)
188 {
189 const RHit& h = fr.hit[0];
190 fHitForce = h.fHitForce;
191 hitPos[0] = h.vHitPos.x; hitPos[1] = -h.vHitPos.z; hitPos[2] = h.vHitPos.y;
192 }
193
194 int w, ww = fr.wheels.size();
195 for (w=0; w < ww; ++w)
196 {
197 const RWheel& wh = fr.wheels[w];
198 whPos[w] = wh.pos;
199 surfType[w] = (TRACKSURFACE::TYPE)wh.surfType;
200 squeal[w] = wh.squeal; whVel[w] = wh.whVel;
201 suspVel[w] = wh.suspVel; suspDisp[w] = wh.suspDisp;
202 // fluids
203 if (wh.whP >= 0) // solid no snd
204 whH_all += wh.whH;
205 if (wh.whP >= 1) mud = true;
206 }
207 }
208 else /// game ------------------------------------------
209 {
210 pos = dynamics.GetPosition(); rot = dynamics.GetOrientation();
211 rpm = GetEngineRPM();
212 throttle = dynamics.GetThrottle();
213 engPos = dynamics.GetEnginePosition();
214 speed = GetSpeed();
215 dynVel = dynamics.GetVelocity().Magnitude();
216 fHitForce = dynamics.fHitForce; hitp = true;
217 hitPos[0] = dynamics.vHitPos.x; hitPos[1] = -dynamics.vHitPos.z; hitPos[2] = dynamics.vHitPos.y;
218 boostVal = dynamics.boostVal;
219
220 for (int w=0; w < numWheels; ++w)
221 {
222 WHEEL_POSITION wp = WHEEL_POSITION(w);
223 whPos[w] = dynamics.GetWheelPosition(wp);
224
225 const TRACKSURFACE* surface = dynamics.GetWheelContact(wp).GetSurfacePtr();
226 surfType[w] = !surface ? TRACKSURFACE::NONE : surface->type;
227 // squeal
228 squeal[w] = GetTireSquealAmount(wp);
229 whVel[w] = dynamics.GetWheelVelocity(wp).Magnitude();
230 // susp
231 suspVel[w] = dynamics.GetSuspension(wp).GetVelocity();
232 suspDisp[w] = dynamics.GetSuspension(wp).GetDisplacementPercent();
233 // fluids
234 if (dynamics.whP[w] >= 0) // solid no snd
235 whH_all += dynamics.whH[w];
236 if (dynamics.whP[w] >= 1) mud = true;
237 }
238
239 // wheels in mud, spinning intensity
240 float mudSpin = 0.f;
241 for (int w=0; w < numWheels; ++w)
242 {
243 float vel = std::abs(dynamics.wheel[w].GetAngularVelocity());
244 if (vel <= 30.f) continue;
245 if (dynamics.whP[w] == 2)
246 mudSpin += dynamics.whH[w] * std::min(80.f, 1.5f * vel) / 80.f;
247 else if (dynamics.whP[w] == 1)
248 mudSpin += dynamics.whH[w] * std::min(160.f, 3.f * vel) / 80.f;
249 }
250 s.whMudSpin = mudSpin * 0.5f;
251
252 // car scrap, screech
253 float gain = std::min(1.f, dynamics.fCarScrap);
254 if (dynamics.fCarScrap > 0.f)
255 { dynamics.fCarScrap -= (-gain * 0.8f + 1.2f)* dt;
256 if (dynamics.fCarScrap < 0.f) dynamics.fCarScrap = 0.f;
257 }
258 fCarScrap = gain;
259
260 /// <><> Damage <><>
261 if (dmg && !terminal)
262 if (reduced)
263 dynamics.fDamage += fDmg * fCarScrap * dt * dynamics.fHitDmgA * gPar.dmgFromScrap;
264 else // normal
265 dynamics.fDamage += fDmg * fCarScrap * dt * dynamics.fHitDmgA * gPar.dmgFromScrap2;
266
267 gain = std::min(1.f, dynamics.fCarScreech);
268 if (dynamics.fCarScreech > 0.f)
269 { dynamics.fCarScreech -= 3.f * dt;
270 if (dynamics.fCarScreech < 0.f) dynamics.fCarScreech = 0.f;
271 }
272 fCarScreech = gain;
273 }
274
275 // engine pos //todo: vel..
276 Vector3 ep, ev = Vector3::ZERO;
277 ep = Axes::toOgre(engPos);
278
279
280 //)) update sounds
281 if (bSound)
282 { /**/
283
284 /// engine ====
285 float gain = 1.f;
286
287 if (dynamics.vtype >= V_Spaceship)
288 {
289 s.engine->setPitch(1.f);
290 gain = throttle;
291 }else
292 { // car
293 gain = throttle * 0.5 + 0.5;
294 s.engine->setPitch(rpm);
295 }
296 s.engine->setPosition(ep, ev);
297 s.engine->setGain(gain * dynamics.engine_vol_mul * pSet->vol_engine);
298
299
300 /// tires oooo
301 for (int i = 0; i < numWheels; ++i)
302 {
303 Vector3 wh; wh = Axes::toOgre(whPos[i]);
304
305 float maxgain = 0.6f, pitchvar = 0.4f, pmul = 1.f;
306
307 Sound* snd = s.gravel[i];
308 switch (surfType[i])
309 {
310 case TRACKSURFACE::ASPHALT: snd = s.asphalt[i]; maxgain = 0.4f; pitchvar = 0.40f; pmul = 0.8f; break;
311 case TRACKSURFACE::GRASS: snd = s.grass[i]; maxgain = 0.7f; pitchvar = 0.25f; break;
312 case TRACKSURFACE::GRAVEL: snd = s.gravel[i]; maxgain = 0.7f; break;
313 case TRACKSURFACE::CONCRETE: snd = s.asphalt[i]; maxgain = 0.5f; pitchvar = 0.25f; pmul = 0.7f; break;
314 case TRACKSURFACE::SAND: snd = s.grass[i]; maxgain = 0.5f; pitchvar = 0.25f; break;
315 case TRACKSURFACE::NONE:
316 default: snd = s.asphalt[i]; maxgain = 0.0f; break;
317 }
318 /// todo: more,sounds.. sand,snow,grass-new,mud..
319 // todo: sum slip, spin, stop tire sounds
320
321 float pitch = std::min(1.f, std::max(0.f, (whVel[i]-5.0f)*0.1f ));
322 pitch = (1.f - pitch) * pitchvar;
323 pitch = pitch + (1.f - pitchvar);
324 pitch = std::min(2.f, std::max(0.25f, pitch ));
325
326 snd->setPosition(wh, ev);
327 snd->setGain(squeal[i]*maxgain * pSet->vol_tires);
328 snd->setPitch(pitch * pmul);
329 // mute others
330 if (snd != s.asphalt[i]) s.asphalt[i]->setGain(0.f);
331 if (snd != s.grass[i]) s.grass[i]->setGain(0.f);
332 if (snd != s.gravel[i]) s.gravel[i]->setGain(0.f);
333
334
335 // susp bump ~~~
336 if (dynamics.vtype == V_Car)
337 {
338 suspbump[i].Update(suspVel[i], suspDisp[i], dt);
339 if (suspbump[i].JustSettled())
340 {
341 float bumpsize = suspbump[i].GetTotalBumpSize();
342 float gain = bumpsize * speed * 0.2f; //par
343 gain = std::max(0.f, std::min(1.2f, gain));
344
345 if (gain > 0.2f && //!tirebump[i]->isAudible() &&
346 (gain > s.bumpvol[i] || s.bumptime[i] > 0.22f))
347 {
348 s.bumpvol[i] = gain;
349 s.bumptime[i] = 0.f;
350 //tirebump[i]->start();
351 //LogO("bump "+toStr(i)+" "+fToStr(gain));
352 }
353 }
354 s.bump[i]->setPosition(wh, ev); //par gain, time fade
355 float gain = 0.5f + 0.7f*s.bumpvol[i] - s.bumptime[i]*(2.f+2.f*s.bumpvol[i]);
356 gain = std::max(0.f, std::min(1.0f, gain));
357
358 s.bump[i]->setGain(gain * pSet->vol_susp);
359 if (s.bumptime[i] < 5.f)
360 s.bumptime[i] += dt;
361 }
362 }
363
364
365 // wind ----
366 gain = dynVel;
367 if (dynamics.vtype == V_Spaceship) gain *= 0.7f;
368 //if (dynamics.sphere) gain *= 0.9f;
369 if (gain < 0.f) gain = -gain;
370 gain *= 0.02f; gain *= gain;
371 if (gain > 1.f) gain = 1.f;
372
373 s.wind->setGain(gain * pSet->vol_env);
374 s.wind->setPosition(ep, ev);
375
376 // boost
377 s.boost->setGain(boostVal * 0.55f * pSet->vol_engine);
378 s.boost->setPosition(ep, ev); //back?-
379
380
381 // fluids - hit ~~~~
382 bool fluidHit = whH_all > 1.f;
383 //LogO(toStr(whH_all) + " v "+ toStr(dynVel));
384
385 if (fluidHit && !s.fluidHitOld)
386 //if (dynVel > 10.f && whH_all > 1.f && )
387 {
388 int i = std::min(Nwatersounds-1, (int)(dynVel / 15.f));
389 float gain = std::min(3.0f, 0.3f + dynVel / 30.f);
390 Sound* snd = /*mud ? s.mud : */s.water[i];
391
392 //LogO("fluid hit i"+toStr(i)+" g"+toStr(gain)+" "+(mud?"mud":"wtr"));
393 if (!snd->isAudible())
394 {
395 snd->setGain(gain * pSet->vol_fl_splash * (mud ? 0.6f : 1.f));
396 snd->setPosition(ep, ev);
397 snd->start();
398 }
399
400 if (s.mud) { Sound* snd = s.mud;
401 if (!snd->isAudible())
402 {
403 snd->setGain(gain * pSet->vol_fl_splash);
404 snd->setPosition(ep, ev);
405 snd->start();
406 } }
407 }
408 s.fluidHitOld = fluidHit;
409
410 // fluids - continuous
411 float velM = mud && whH_all > 0.1f ?
412 s.whMudSpin * 2.5f : 0.f;
413 s.mud_cont->setGain(std::min(1.f, velM) * pSet->vol_fl_cont * 0.85f);
414 s.mud_cont->setPitch(std::max(0.7f, std::min(/*3.f*/2.f, velM * 0.35f)));
415 s.mud_cont->setPosition(ep, ev);
416
417 float velW = !mud && whH_all > 0.1f && whH_all < 3.9f ?
418 dynVel / 30.f : 0.f;
419 s.water_cont->setGain(std::min(1.f, velW * 1.5f) * pSet->vol_fl_cont);
420 s.water_cont->setPitch(std::max(0.7f, std::min(1.3f, velW)));
421 s.water_cont->setPosition(ep, ev);
422 }
423 //)) sounds
424
425
426 // crash ----
427 Vector3 hp; hp = Axes::toOgre(hitPos);
428 {
429 crashdetection2.Update(-fHitForce, dt);
430 crashdetection2.deceltrigger = 1.f;
431 float crashdecel2 = crashdetection2.GetMaxDecel();
432 dynamics.fHitForce3 = crashdecel2 / 30.f;
433
434 if (crashdecel2 > 0)
435 {
436 float gain = 0.9f;
437
438 int f = crashdecel2 / 30.f * Ncrashsounds;
439 int i = std::max(1, std::min(Ncrashsounds-1, f));
440 //LogO("crash: "+toStr(i));
441
442 if (s.crashtime[i] > /*ti*/0.4f) //!crashsound.isAudible())
443 {
444 if (bSound)
445 {
446 s.crash[i]->setGain(gain * pSet->vol_car_crash);
447 if (hitp)
448 s.crash[i]->setPosition(hp, ev);
449 s.crash[i]->start();
450 }
451 s.crashtime[i] = 0.f;
452
453 /// <><> Damage <><>
454 if (dmg && !terminal)
455 if (reduced)
456 dynamics.fDamage += fDmg * crashdecel2 * dynamics.fHitDmgA * gPar.dmgFromHit;
457 else // normal
458 { float f = std::min(1.f, crashdecel2 / 30.f);
459 f = powf(f, gPar.dmgPow2);
460 dynamics.fDamage += fDmg * crashdecel2 * dynamics.fHitDmgA * gPar.dmgFromHit2 * f;
461 }
462 }
463 //LogO("Car Snd: " + toStr(crashdecel));// + " force " + toStr(hit.force)
464 }
465 }
466 // time played
467 for (int i=0; i < Ncrashsounds; ++i)
468 if (s.crashtime[i] < 5.f)
469 s.crashtime[i] += dt;
470
471
472 // crash scrap and screech
473 if (bSound)
474 {
475 s.scrap->setGain(fCarScrap * pSet->vol_car_scrap);
476 if (hitp)
477 s.scrap->setPosition(hp, ev);
478
479 s.screech->setGain(fCarScreech * pSet->vol_car_scrap * 0.6f);
480 if (hitp)
481 s.screech->setPosition(hp, ev);
482 }
483
484
485 /// <><> Damage <><>
486 if (dmg)
487 if (dynamics.fDamage > 100.f) dynamics.fDamage = 100.f;
488 }
489