mirror of
https://github.com/thug1src/thug.git
synced 2024-12-02 12:56:45 +00:00
936 lines
29 KiB
C++
936 lines
29 KiB
C++
/*
|
|
This is just a database for arrays of skater sounds on different terrains.
|
|
|
|
For each type of sound in sounds.h (like grind, land, slide, wheel roll, etc...)
|
|
there is an array of sounds to play, one for each possible terrain type.
|
|
|
|
A terrain type of zero indicates that the sound is the default (for surfaces not
|
|
defined in the list).
|
|
*/
|
|
|
|
|
|
#include <string.h>
|
|
#include <core/defines.h>
|
|
|
|
#include <gel/scripting/script.h>
|
|
#include <gel/scripting/struct.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/symboltable.h>
|
|
#include <gel/scripting/utils.h>
|
|
#include <gel/net/server/netserv.h>
|
|
#include <gel/net/client/netclnt.h>
|
|
#include <gel/environment/terrain.h>
|
|
#include <gel/soundfx/soundfx.h>
|
|
|
|
#include <sk/gamenet/gamenet.h>
|
|
#include <sys/config/config.h>
|
|
#include <sys/replay/replay.h>
|
|
|
|
|
|
|
|
namespace Env
|
|
{
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
bool CTerrainManager::s_terrain_loaded[ vNUM_TERRAIN_TYPES ];
|
|
#endif __NOPT_ASSERT__
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
ETerrainType CTerrainManager::sGetTerrainFromChecksum(uint32 checksum)
|
|
{
|
|
switch (checksum)
|
|
{
|
|
case 0x64967688: // TERRAIN_DEFAULT
|
|
return vTERRAIN_DEFAULT;
|
|
|
|
case 0x9b37fa90: // TERRAIN_CONCSMOOTH
|
|
return vTERRAIN_CONCSMOOTH;
|
|
|
|
case 0x9383172: // TERRAIN_CONCROUGH
|
|
return vTERRAIN_CONCROUGH;
|
|
|
|
case 0xa9ecf4e9: // TERRAIN_METALSMOOTH
|
|
return vTERRAIN_METALSMOOTH;
|
|
|
|
case 0xa5aab5e: // TERRAIN_METALROUGH
|
|
return vTERRAIN_METALROUGH;
|
|
|
|
case 0x67af2cb5: // TERRAIN_METALCORRUGATED
|
|
return vTERRAIN_METALCORRUGATED;
|
|
|
|
case 0x1134b31a: // TERRAIN_METALGRATING
|
|
return vTERRAIN_METALGRATING;
|
|
|
|
case 0xd814ef41: // TERRAIN_METALTIN
|
|
return vTERRAIN_METALTIN;
|
|
|
|
case 0x39075ea5: // TERRAIN_WOOD
|
|
return vTERRAIN_WOOD;
|
|
|
|
case 0x3afca53f: // TERRAIN_WOODMASONITE
|
|
return vTERRAIN_WOODMASONITE;
|
|
|
|
case 0x6651a5d0: // TERRAIN_WOODPLYWOOD
|
|
return vTERRAIN_WOODPLYWOOD;
|
|
|
|
case 0xd11a620d: // TERRAIN_WOODFLIMSY
|
|
return vTERRAIN_WOODFLIMSY;
|
|
|
|
case 0xd3e04021: // TERRAIN_WOODSHINGLE
|
|
return vTERRAIN_WOODSHINGLE;
|
|
|
|
case 0x866b2b83: // TERRAIN_WOODPIER
|
|
return vTERRAIN_WOODPIER;
|
|
|
|
case 0x3d5a952c: // TERRAIN_BRICK
|
|
return vTERRAIN_BRICK;
|
|
|
|
case 0x7315eeac: // TERRAIN_TILE
|
|
return vTERRAIN_TILE;
|
|
|
|
case 0x6aa69ead: // TERRAIN_ASPHALT
|
|
return vTERRAIN_ASPHALT;
|
|
|
|
case 0x32d3fc0a: // TERRAIN_ROCK
|
|
return vTERRAIN_ROCK;
|
|
|
|
case 0x67f6ee4c: // TERRAIN_GRAVEL
|
|
return vTERRAIN_GRAVEL;
|
|
|
|
case 0x103bb3b8: // TERRAIN_SIDEWALK
|
|
return vTERRAIN_SIDEWALK;
|
|
|
|
case 0xa207c1e3: // TERRAIN_GRASS
|
|
return vTERRAIN_GRASS;
|
|
|
|
case 0x802c8f14: // TERRAIN_GRASSDRIED
|
|
return vTERRAIN_GRASSDRIED;
|
|
|
|
case 0x9dfda61e: // TERRAIN_DIRT
|
|
return vTERRAIN_DIRT;
|
|
|
|
case 0xd748f9b7: // TERRAIN_DIRTPACKED
|
|
return vTERRAIN_DIRTPACKED;
|
|
|
|
case 0xf1394aca: // TERRAIN_WATER
|
|
return vTERRAIN_WATER;
|
|
|
|
case 0x5e354fef: // TERRAIN_ICE
|
|
return vTERRAIN_ICE;
|
|
|
|
case 0x3319e21b: // TERRAIN_SNOW
|
|
return vTERRAIN_SNOW;
|
|
|
|
case 0xa5e0d5b9: // TERRAIN_SAND
|
|
return vTERRAIN_SAND;
|
|
|
|
case 0x6362cc4f: // TERRAIN_PLEXIGLASS
|
|
return vTERRAIN_PLEXIGLASS;
|
|
|
|
case 0x66987ee0: // TERRAIN_FIBERGLASS
|
|
return vTERRAIN_FIBERGLASS;
|
|
|
|
case 0x8e6a5d9d: // TERRAIN_CARPET
|
|
return vTERRAIN_CARPET;
|
|
|
|
case 0x2ee8ef42: // TERRAIN_CONVEYOR
|
|
return vTERRAIN_CONVEYOR;
|
|
|
|
case 0xbe7c0e6e: // TERRAIN_CHAINLINK
|
|
return vTERRAIN_CHAINLINK;
|
|
|
|
case 0x14259681: // TERRAIN_METALFUTURE
|
|
return vTERRAIN_METALFUTURE;
|
|
|
|
case 0xbb1ac0d4: // TERRAIN_GENERIC1
|
|
return vTERRAIN_GENERIC1;
|
|
|
|
case 0x2213916e: // TERRAIN_GENERIC2
|
|
return vTERRAIN_GENERIC2;
|
|
|
|
case 0x83b85f36: // TERRAIN_WHEELS
|
|
return vTERRAIN_WHEELS;
|
|
|
|
case 0x22dd3d51: // TERRAIN_WETCONC
|
|
return vTERRAIN_WETCONC;
|
|
|
|
case 0xfa298f50: // TERRAIN_METALFENCE
|
|
return vTERRAIN_METALFENCE;
|
|
|
|
case 0x69803ba4: // TERRAIN_GRINDTRAIN
|
|
return vTERRAIN_GRINDTRAIN;
|
|
|
|
case 0xed035a39: // TERRAIN_GRINDROPE
|
|
return vTERRAIN_GRINDROPE;
|
|
|
|
case 0xec66b43b: // TERRAIN_GRINDWIRE
|
|
return vTERRAIN_GRINDWIRE;
|
|
|
|
case CRCC(0x3884f029,"TERRAIN_GRINDCONC"):
|
|
return vTERRAIN_GRINDCONC;
|
|
|
|
case CRCC(0x92a2112a,"TERRAIN_GRINDROUNDMETALPOLE"):
|
|
return vTERRAIN_GRINDROUNDMETALPOLE;
|
|
|
|
case CRCC(0xd7e88122,"TERRAIN_GRINDCHAINLINK"):
|
|
return vTERRAIN_GRINDCHAINLINK;
|
|
|
|
case CRCC(0xf5842bce,"TERRAIN_GRINDMETAL"):
|
|
return vTERRAIN_GRINDMETAL;
|
|
|
|
case CRCC(0xffc0b5e,"TERRAIN_GRINDWOODRAILING"):
|
|
return vTERRAIN_GRINDWOODRAILING;
|
|
|
|
case CRCC(0x8aadc3d0,"TERRAIN_GRINDWOODLOG"):
|
|
return vTERRAIN_GRINDWOODLOG;
|
|
|
|
case CRCC(0x60809403,"TERRAIN_GRINDWOOD"):
|
|
return vTERRAIN_GRINDWOOD;
|
|
|
|
case CRCC(0xf862cfe0,"TERRAIN_GRINDPLASTIC"):
|
|
return vTERRAIN_GRINDPLASTIC;
|
|
|
|
case CRCC(0x2bb33575,"TERRAIN_GRINDELECTRICWIRE"):
|
|
return vTERRAIN_GRINDELECTRICWIRE;
|
|
|
|
case CRCC(0x110f1bd3,"TERRAIN_GRINDCABLE"):
|
|
return vTERRAIN_GRINDCABLE;
|
|
|
|
case CRCC(0x84e4c7cd,"TERRAIN_GRINDCHAIN"):
|
|
return vTERRAIN_GRINDCHAIN;
|
|
|
|
case CRCC(0x3f1c35c5,"TERRAIN_GRINDPLASTICBARRIER"):
|
|
return vTERRAIN_GRINDPLASTICBARRIER;
|
|
|
|
case CRCC(0x6c4a1c6a,"TERRAIN_GRINDNEONLIGHT"):
|
|
return vTERRAIN_GRINDNEONLIGHT;
|
|
|
|
case CRCC(0xcaf52d56,"TERRAIN_GRINDGLASSMONSTER"):
|
|
return vTERRAIN_GRINDGLASSMONSTER;
|
|
|
|
case CRCC(0x8da017a8,"TERRAIN_GRINDBANYONTREE"):
|
|
return vTERRAIN_GRINDBANYONTREE;
|
|
|
|
case CRCC(0x7825b83c,"TERRAIN_GRINDBRASSRAIL"):
|
|
return vTERRAIN_GRINDBRASSRAIL;
|
|
|
|
case CRCC(0x5ce9c824,"TERRAIN_GRINDCATWALK"):
|
|
return vTERRAIN_GRINDCATWALK;
|
|
|
|
case CRCC(0x66ab4005,"TERRAIN_GRINDTANKTURRET"):
|
|
return vTERRAIN_GRINDTANKTURRET;
|
|
|
|
case 0x24dca61: // TERRAIN_MEATALSMOOTH // old typo that still exists
|
|
Dbg_Message("Metal is not spelled 'Meatal'");
|
|
default:
|
|
Dbg_MsgAssert(0, ("Unknown terrain checksum %x\n", checksum));
|
|
return vTERRAIN_DEFAULT;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
ETerrainActionType CTerrainManager::sGetActionFromChecksum(uint32 checksum)
|
|
{
|
|
switch (checksum)
|
|
{
|
|
case 0xcaebd8e: // TA_ROLL
|
|
return vTABLE_WHEELROLL;
|
|
|
|
case 0x7e5d9202: // TA_GRIND
|
|
return vTABLE_GRIND;
|
|
|
|
case 0xc0669dd5: // TA_OLLIE
|
|
return vTABLE_JUMP;
|
|
|
|
case 0x8a1b5a98: // TA_LAND
|
|
return vTABLE_LAND;
|
|
|
|
case 0xf0e51d30: // TA_BONK
|
|
return vTABLE_BONK;
|
|
|
|
case 0x6ac1023d: // TA_GRINDJUMP
|
|
return vTABLE_GRINDJUMP;
|
|
|
|
case 0x6572d1f3: // TA_GRINDLAND
|
|
return vTABLE_GRINDLAND;
|
|
|
|
case 0xd6135bf0: // TA_SLIDE
|
|
return vTABLE_SLIDE;
|
|
|
|
case 0x6e27388f: // TA_SLIDEJUMP
|
|
return vTABLE_SLIDEJUMP;
|
|
|
|
case 0x6194eb41: // TA_SLIDELAND
|
|
return vTABLE_SLIDELAND;
|
|
|
|
case 0x20744cde: // TA_REVERT
|
|
return vTABLE_CESS;
|
|
|
|
default:
|
|
Dbg_MsgAssert(0, ("Unknown terrain action checksum %x\n", checksum));
|
|
return vTABLE_WHEELROLL;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
uint32 CTerrainManager::s_get_action_checksum(ETerrainActionType action)
|
|
{
|
|
switch (action)
|
|
{
|
|
case vTABLE_WHEELROLL:
|
|
return 0xcaebd8e; // TA_ROLL
|
|
|
|
case vTABLE_GRIND:
|
|
return 0x7e5d9202; // TA_GRIND
|
|
|
|
case vTABLE_JUMP:
|
|
return 0xc0669dd5; // TA_OLLIE
|
|
|
|
case vTABLE_LAND:
|
|
return 0x8a1b5a98; // TA_LAND
|
|
|
|
case vTABLE_BONK:
|
|
return 0xf0e51d30; // TA_BONK
|
|
|
|
case vTABLE_GRINDJUMP:
|
|
return 0x6ac1023d; // TA_GRINDJUMP
|
|
|
|
case vTABLE_GRINDLAND:
|
|
return 0x6572d1f3; // TA_GRINDLAND
|
|
|
|
case vTABLE_SLIDE:
|
|
return 0xd6135bf0; // TA_SLIDE
|
|
|
|
case vTABLE_SLIDEJUMP:
|
|
return 0x6e27388f; // TA_SLIDEJUMP
|
|
|
|
case vTABLE_SLIDELAND:
|
|
return 0x6194eb41; // TA_SLIDELAND
|
|
|
|
case vTABLE_CESS:
|
|
return 0x20744cde; // TA_REVERT
|
|
|
|
default:
|
|
Dbg_MsgAssert(0, ("Unknown terrain action %d\n", action));
|
|
return 0xcaebd8e; // TA_ROLL
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool CTerrainManager::s_get_terrain_actions_struct(ETerrainType terrain, Script::CStruct *p_actions)
|
|
{
|
|
Dbg_MsgAssert(p_actions, ("s_get_terrain_actions_struct given NULL CStruct"));
|
|
|
|
Script::CStruct *p_default_actions = NULL;
|
|
Script::CStruct *p_terrain_actions = NULL;
|
|
Script::CStruct *p_level_default_actions = NULL;
|
|
Script::CStruct *p_level_terrain_actions = NULL;
|
|
|
|
uint32 terrain_checksum;
|
|
ETerrainType terrain_type;
|
|
|
|
// Search Default Terrain array first
|
|
Script::CArray *pDefaultTerrainArray = Script::GetArray(CRCD(0x1c2c4218,"standard_terrain"));
|
|
Dbg_MsgAssert(pDefaultTerrainArray, ("standard_terrain not found"));
|
|
|
|
for (uint i = 0; (!p_default_actions || !p_terrain_actions) && i < pDefaultTerrainArray->GetSize(); i++)
|
|
{
|
|
// Get next terrain struct
|
|
Script::CStruct *pTerrainStruct = pDefaultTerrainArray->GetStructure(i);
|
|
Dbg_MsgAssert(pTerrainStruct, ("terrain array not made of structures"));
|
|
|
|
pTerrainStruct->GetChecksum(CRCD(0x3789ac4e,"Terrain"), &terrain_checksum, Script::ASSERT);
|
|
terrain_type = sGetTerrainFromChecksum(terrain_checksum);
|
|
|
|
if (terrain_type == vTERRAIN_DEFAULT)
|
|
{
|
|
pTerrainStruct->GetStructure(CRCD(0x5c969c50,"SoundActions"), &p_default_actions);
|
|
//Dbg_Message("Found default terrain:");
|
|
//Script::PrintContents(p_default_actions);
|
|
}
|
|
else if (terrain_type == terrain)
|
|
{
|
|
pTerrainStruct->GetStructure(CRCD(0x5c969c50,"SoundActions"), &p_terrain_actions);
|
|
//Dbg_Message("Found terrain:");
|
|
//Script::PrintContents(p_terrain_actions);
|
|
}
|
|
|
|
if (p_default_actions && p_terrain_actions)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Search Level Terrain array
|
|
Script::CArray *pLevelTerrainArray = Script::GetArray(CRCD(0x96218951,"level_terrain"));
|
|
if (pLevelTerrainArray)
|
|
{
|
|
for (uint i = 0; i < pLevelTerrainArray->GetSize(); i++)
|
|
{
|
|
// Get next terrain struct
|
|
Script::CStruct *pTerrainStruct = pLevelTerrainArray->GetStructure(i);
|
|
Dbg_MsgAssert(pTerrainStruct, ("terrain array not made of structures"));
|
|
|
|
pTerrainStruct->GetChecksum(CRCD(0x3789ac4e,"Terrain"), &terrain_checksum, Script::ASSERT);
|
|
terrain_type = sGetTerrainFromChecksum(terrain_checksum);
|
|
|
|
if (terrain_type == vTERRAIN_DEFAULT)
|
|
{
|
|
pTerrainStruct->GetStructure(CRCD(0x5c969c50,"SoundActions"), &p_level_default_actions);
|
|
} else if (terrain_type == terrain)
|
|
{
|
|
pTerrainStruct->GetStructure(CRCD(0x5c969c50,"SoundActions"), &p_level_terrain_actions);
|
|
}
|
|
|
|
if (p_level_default_actions && p_level_terrain_actions)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Combine them together
|
|
*p_actions = *p_default_actions;
|
|
|
|
if (p_level_default_actions)
|
|
{
|
|
*p_actions += *p_level_default_actions;
|
|
}
|
|
|
|
if (p_terrain_actions)
|
|
{
|
|
*p_actions += *p_terrain_actions;
|
|
}
|
|
|
|
if (p_level_terrain_actions)
|
|
{
|
|
*p_actions += *p_level_terrain_actions;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Script::CStruct * CTerrainManager::s_choose_sound_action(Script::CStruct *p_sound_action_struct)
|
|
{
|
|
Script::CStruct* p_sound;
|
|
|
|
// soundAction is a single stucture, so just use it
|
|
if (p_sound_action_struct->GetStructure(CRCD(0x25f654c8, "soundAction"), &p_sound))
|
|
{
|
|
Dbg_MsgAssert(!p_sound->ContainsComponentNamed(CRCD(0xdbc4c4db, "chance")),
|
|
("A sound may only include a chance parameter when it is an element of a random-choice list of sounds"));
|
|
return p_sound;
|
|
}
|
|
|
|
// soundAction is an array of structures, so choose one randomly based on their given chances
|
|
Script::CArray* p_random_indexed_sound_array;
|
|
p_sound_action_struct->GetArray(CRCD(0x25f654c8, "soundAction"), &p_random_indexed_sound_array, Script::ASSERT);
|
|
|
|
int total_chance = 0;
|
|
for (int sound_idx = p_random_indexed_sound_array->GetSize(); sound_idx--; )
|
|
{
|
|
p_sound = p_random_indexed_sound_array->GetStructure(sound_idx);
|
|
|
|
int chance;
|
|
p_sound->GetInteger(CRCD(0xdbc4c4db, "chance"), &chance, Script::ASSERT);
|
|
|
|
total_chance += chance;
|
|
}
|
|
|
|
int choice = Mth::Rnd(total_chance);
|
|
|
|
for (int sound_idx = p_random_indexed_sound_array->GetSize(); sound_idx--; )
|
|
{
|
|
p_sound = p_random_indexed_sound_array->GetStructure(sound_idx);
|
|
|
|
int chance;
|
|
p_sound->GetInteger(CRCD(0xdbc4c4db, "chance"), &chance, Script::ASSERT);
|
|
|
|
choice -= chance;
|
|
if (choice < 0)
|
|
{
|
|
return p_sound;
|
|
}
|
|
}
|
|
|
|
Dbg_Assert(false);
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Script::CStruct * CTerrainManager::s_get_action_sound_struct(Script::CStruct *p_actions, ETerrainActionType action, float soundChoice)
|
|
{
|
|
Dbg_MsgAssert(p_actions, ("s_get_action_sound_struct given NULL action CStruct"));
|
|
|
|
Script::CStruct *p_sound;
|
|
|
|
uint32 checksum = s_get_action_checksum(action);
|
|
|
|
// sound is a single sound structure, so just use it
|
|
if (p_actions->GetStructure(checksum, &p_sound))
|
|
{
|
|
return p_sound;
|
|
}
|
|
|
|
// sound is an array of structures, one of which must be choosen depending upon speed
|
|
Script::CArray* p_float_indexed_sound_array;
|
|
p_actions->GetArray(checksum, &p_float_indexed_sound_array, Script::ASSERT);
|
|
|
|
// check to insure that the final structure in the array has no useUpTo parameter and thus operates as a default choice
|
|
Dbg_MsgAssert(!p_float_indexed_sound_array->GetStructure(p_float_indexed_sound_array->GetSize() - 1)->ContainsComponentNamed(CRCD(0x9ee9a09a, "useUpTo")),
|
|
("Final sound in a speed-indexed sound list must not include useUpTo"));
|
|
|
|
for (uint32 sound_action_idx = 0; sound_action_idx < p_float_indexed_sound_array->GetSize(); sound_action_idx++)
|
|
{
|
|
// each structure contains a useUpTo parameter which is checked against speed in turn; if found to be larger
|
|
// than speed, the sound is used; a structure lacking useUpTo is always used
|
|
Script::CStruct* p_sound_action_struct = p_float_indexed_sound_array->GetStructure(sound_action_idx);
|
|
|
|
float up_to_speed;
|
|
if (!p_sound_action_struct->GetFloat(CRCD(0x9ee9a09a, "useUpTo"), &up_to_speed))
|
|
{
|
|
Dbg_MsgAssert(sound_action_idx == p_float_indexed_sound_array->GetSize() - 1,
|
|
("Only the final sound in a float-indexed sound list may fail to include useUpTo"));
|
|
return s_choose_sound_action(p_sound_action_struct);
|
|
}
|
|
|
|
if (soundChoice <= up_to_speed)
|
|
{
|
|
return s_choose_sound_action(p_sound_action_struct);
|
|
}
|
|
}
|
|
|
|
Dbg_Assert(false);
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool CTerrainManager::s_get_sound_info(Script::CStruct *p_sound, STerrainSoundInfo *p_info)
|
|
{
|
|
Dbg_MsgAssert(p_info, ("s_get_sound_info given NULL STerrainSoundInfo"));
|
|
|
|
// Set defaults
|
|
p_info->mp_soundName = NULL;
|
|
p_info->m_soundChecksum = 0;
|
|
p_info->m_maxPitch = 100.0f;
|
|
p_info->m_minPitch = 100.0f;
|
|
p_info->m_maxVol = 100.0f;
|
|
p_info->m_minVol = 0.0f;
|
|
p_info->m_loadPitch = 100.0f;
|
|
p_info->m_loadVol = 100.0f;
|
|
|
|
p_sound->GetString( CRCD(0x7713c7b,"sound"), &p_info->mp_soundName );
|
|
if ( !p_info->mp_soundName )
|
|
{
|
|
Dbg_MsgAssert(0, ( "Need the name of a sound in s_get_sound_info" ));
|
|
return false;
|
|
}
|
|
|
|
// Calculate checksum
|
|
const char *pNameMinusPath = p_info->mp_soundName;
|
|
int stringLength = strlen( p_info->mp_soundName );
|
|
for( int i = 0; i < stringLength; i++ )
|
|
{
|
|
if(( p_info->mp_soundName[i] == '\\' ) || ( p_info->mp_soundName[i] == '/' ))
|
|
pNameMinusPath = &p_info->mp_soundName[i + 1];
|
|
}
|
|
|
|
p_info->m_soundChecksum = Script::GenerateCRC( pNameMinusPath );
|
|
|
|
p_sound->GetFloat( CRCD(0xfa3e14c5,"maxPitch"), &p_info->m_maxPitch );
|
|
p_sound->GetFloat( CRCD(0x1c5ebb24,"minPitch"), &p_info->m_minPitch );
|
|
|
|
p_sound->GetFloat( CRCD(0x693daaf,"maxVol"), &p_info->m_maxVol );
|
|
p_sound->GetFloat( CRCD(0x4391992d,"minVol"), &p_info->m_minVol );
|
|
|
|
p_sound->GetFloat( CRCD(0xf573682f,"loadPitch"), &p_info->m_loadPitch );
|
|
p_sound->GetFloat( CRCD(0x312ccbcf,"loadVol"), &p_info->m_loadVol );
|
|
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CTerrainManager::s_load_action_sound( Script::CStruct* p_sound )
|
|
{
|
|
Dbg_MsgAssert(p_sound, ("s_load_action_sound given NULL sound CStruct"));
|
|
|
|
STerrainSoundInfo soundInfo;
|
|
#ifdef __NOPT_ASSERT__
|
|
bool result =
|
|
#endif
|
|
s_get_sound_info(p_sound, &soundInfo);
|
|
Dbg_Assert(result);
|
|
|
|
Sfx::CSfxManager::Instance()->LoadSound( soundInfo.mp_soundName, 0, 0.0f, soundInfo.m_loadPitch, soundInfo.m_loadVol );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CTerrainManager::s_load_action_sound_struct( Script::CStruct* p_actions, ETerrainActionType action )
|
|
{
|
|
Dbg_MsgAssert(p_actions, ("s_load_action_sound_struct given NULL action CStruct"));
|
|
|
|
Script::CStruct *p_sound;
|
|
|
|
uint32 checksum = s_get_action_checksum(action);
|
|
|
|
// sound is a single sound structure, so just load it
|
|
if (p_actions->GetStructure(checksum, &p_sound))
|
|
{
|
|
s_load_action_sound(p_sound);
|
|
return;
|
|
}
|
|
|
|
// sound is an array of sound structures, all of which must be loaded
|
|
Script::CArray* p_float_indexed_sound_array;
|
|
p_actions->GetArray(checksum, &p_float_indexed_sound_array, Script::ASSERT);
|
|
|
|
for (uint32 i = 0; i < p_float_indexed_sound_array->GetSize(); i++)
|
|
{
|
|
Script::CStruct* p_sound_action_struct = p_float_indexed_sound_array->GetStructure(i);
|
|
|
|
// this entry is a single sound structure, so just load it
|
|
if (p_sound_action_struct->GetStructure(CRCD(0x25f654c8, "soundAction"), &p_sound))
|
|
{
|
|
s_load_action_sound(p_sound);
|
|
continue;
|
|
}
|
|
|
|
// this entry is an array of sounds, all of which must be loaded
|
|
Script::CArray* p_random_indexed_sound_array;
|
|
p_sound_action_struct->GetArray(CRCD(0x25f654c8, "soundAction"), &p_random_indexed_sound_array, Script::ASSERT);
|
|
|
|
for (uint32 j = 0; j < p_random_indexed_sound_array->GetSize(); j++)
|
|
{
|
|
p_sound = p_random_indexed_sound_array->GetStructure(j);
|
|
s_load_action_sound(p_sound);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
void CTerrainManager::s_check_terrain_loaded(ETerrainType terrain)
|
|
{
|
|
// Garrett: Comment the assert back in when the new plugin is released (on or after 2/20/03)
|
|
if (!s_terrain_loaded[terrain])
|
|
{
|
|
// Dbg_Message("****** ERROR: Trying to use terrain %d, which isn't loaded ******", terrain);
|
|
}
|
|
// Dbg_MsgAssert(s_terrain_loaded[terrain], ("****** ERROR: Trying to use terrain %d, which isn't loaded ******", terrain));
|
|
}
|
|
#endif __NOPT_ASSERT__
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CTerrainManager::sReset()
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
// Clear terrain loaded array
|
|
for (int i = 0; i < vNUM_TERRAIN_TYPES; i++)
|
|
{
|
|
s_terrain_loaded[i] = false;
|
|
}
|
|
#endif __NOPT_ASSERT__
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool CTerrainManager::sGetTerrainSoundInfo( STerrainSoundInfo *p_info, ETerrainType terrain,
|
|
ETerrainActionType action, float soundChoice )
|
|
{
|
|
bool result = false;
|
|
|
|
if (Sfx::NoSoundPlease()) return false;
|
|
|
|
Dbg_MsgAssert((terrain >= 0) && (terrain < vNUM_TERRAIN_TYPES), ("Terrain type out of range"));
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
// Check that terrain is loaded
|
|
s_check_terrain_loaded(terrain);
|
|
#endif __NOPT_ASSERT__
|
|
|
|
Dbg_MsgAssert(p_info, ("sGetTerrainSoundInfo given NULL STerrainSoundInfo"));
|
|
|
|
// Allocate new script structure for combining data
|
|
Script::CStruct *p_actions = new Script::CStruct;
|
|
Script::CStruct *p_sound;
|
|
|
|
if (s_get_terrain_actions_struct(terrain, p_actions))
|
|
{
|
|
p_sound = s_get_action_sound_struct(p_actions, action, soundChoice);
|
|
if (p_sound)
|
|
{
|
|
//Dbg_Message("Extracted sound:");
|
|
//Script::PrintContents(p_sound);
|
|
|
|
result = s_get_sound_info(p_sound, p_info);
|
|
}
|
|
}
|
|
|
|
// Done with script data
|
|
delete p_actions;
|
|
|
|
return result;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool CTerrainManager::sLoadTerrainSounds( ETerrainType terrain )
|
|
{
|
|
if (Sfx::NoSoundPlease()) return false;
|
|
|
|
Dbg_MsgAssert((terrain >= 0) && (terrain < vNUM_TERRAIN_TYPES), ("Terrain type out of range"));
|
|
|
|
Script::CStruct *p_actions = new Script::CStruct;
|
|
|
|
// Sfx::CSfxManager * sfx_manager = Sfx::CSfxManager::Instance();
|
|
// Dbg_Assert(sfx_manager);
|
|
|
|
if (s_get_terrain_actions_struct(terrain, p_actions))
|
|
{
|
|
// Go through each action
|
|
for (int action_idx = 0; action_idx < vNUM_ACTION_TYPES; action_idx++)
|
|
{
|
|
s_load_action_sound_struct(p_actions, (ETerrainActionType) action_idx);
|
|
}
|
|
}
|
|
|
|
// Done with script data
|
|
delete p_actions;
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
// Mark terrain loaded
|
|
s_terrain_loaded[terrain] = true;
|
|
#endif __NOPT_ASSERT__
|
|
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CTerrainManager::sPlaySound( ETerrainActionType action, ETerrainType terrain, const Mth::Vector &pos,
|
|
float volPercent, float pitchPercent, float soundChoice, bool propogate )
|
|
{
|
|
if (Sfx::NoSoundPlease()) return;
|
|
|
|
Dbg_MsgAssert((terrain >= 0) && (terrain < vNUM_TERRAIN_TYPES), ("Terrain type out of range"));
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
// Check that terrain is loaded
|
|
s_check_terrain_loaded(terrain);
|
|
#endif __NOPT_ASSERT__
|
|
|
|
// need to write pitch as well
|
|
// Replay::WriteSkaterSoundEffect(action,terrain,pos,volPercent);
|
|
|
|
Sfx::CSfxManager * sfx_manager = Sfx::CSfxManager::Instance();
|
|
GameNet::Manager * gamenet_manager = GameNet::Manager::Instance();
|
|
|
|
STerrainSoundInfo soundInfo;
|
|
bool found = sGetTerrainSoundInfo( &soundInfo, terrain, action, soundChoice );
|
|
|
|
if ( !found )
|
|
{
|
|
// no sounds are supposed to be played for this surface on this transition:
|
|
return;
|
|
}
|
|
|
|
if( propogate )
|
|
{
|
|
Net::Client* client;
|
|
GameNet::MsgPlaySound msg;
|
|
Net::MsgDesc msg_desc;
|
|
|
|
client = gamenet_manager->GetClient( 0 );
|
|
Dbg_Assert( client );
|
|
|
|
msg.m_WhichArray = (char) action;
|
|
msg.m_SurfaceFlag = (char) terrain;
|
|
msg.m_Pos[0] = (short) pos[X];
|
|
msg.m_Pos[1] = (short) pos[Y];
|
|
msg.m_Pos[2] = (short) pos[Z];
|
|
msg.m_VolPercent = (char) volPercent;
|
|
msg.m_PitchPercent = (char) pitchPercent;
|
|
msg.m_SoundChoice = (char) soundChoice;
|
|
|
|
msg_desc.m_Data = &msg;
|
|
msg_desc.m_Length = sizeof( GameNet::MsgPlaySound );
|
|
msg_desc.m_Id = GameNet::MSG_ID_PLAY_SOUND;
|
|
client->EnqueueMessageToServer( &msg_desc );
|
|
}
|
|
|
|
Sfx::sVolume vol;
|
|
sfx_manager->SetVolumeFromPos( &vol, pos, sfx_manager->GetDropoffDist( soundInfo.m_soundChecksum ));
|
|
|
|
// Adjust volume according to speed.
|
|
volPercent = sGetVolPercent( &soundInfo, volPercent );
|
|
vol.PercentageAdjustment( volPercent );
|
|
|
|
if (vol.IsSilent()) return;
|
|
|
|
pitchPercent = sGetPitchPercent( &soundInfo, pitchPercent );
|
|
|
|
sfx_manager->PlaySound( soundInfo.m_soundChecksum, &vol, pitchPercent, 0, NULL, soundInfo.mp_soundName );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// set the volume according to the range specified by the designers...
|
|
float CTerrainManager::sGetVolPercent( STerrainSoundInfo *pInfo, float volPercent, bool clipToMaxVol )
|
|
{
|
|
|
|
Dbg_MsgAssert(pInfo, ("pInfo set to NULL."));
|
|
|
|
if ( !( ( pInfo->m_minVol == 0.0f ) && ( pInfo->m_maxVol == 100.0f ) ) )
|
|
{
|
|
volPercent = ( pInfo->m_minVol + PERCENT( ( pInfo->m_maxVol - pInfo->m_minVol ), volPercent ) );
|
|
}
|
|
|
|
if ( clipToMaxVol )
|
|
{
|
|
if ( volPercent > pInfo->m_maxVol )
|
|
volPercent = pInfo->m_maxVol;
|
|
}
|
|
return ( volPercent );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
float CTerrainManager::sGetPitchPercent( STerrainSoundInfo *pInfo, float pitchPercent, bool clipToMaxPitch )
|
|
{
|
|
|
|
Dbg_MsgAssert(pInfo, ("pInfo set to NULL."));
|
|
|
|
if ( !( ( pInfo->m_minPitch == 0.0f ) && ( pInfo->m_maxPitch == 100.0f ) ) )
|
|
{
|
|
pitchPercent = ( pInfo->m_minPitch + PERCENT( ( pInfo->m_maxPitch - pInfo->m_minPitch ), pitchPercent ) );
|
|
}
|
|
|
|
if ( clipToMaxPitch )
|
|
{
|
|
if ( pitchPercent > pInfo->m_maxPitch )
|
|
pitchPercent = pInfo->m_maxPitch;
|
|
}
|
|
return ( pitchPercent );
|
|
}
|
|
|
|
#if 0
|
|
// Sound FX for the level...
|
|
/* The surface flag indicates which surface the skater is currently on (grass, cement, wood, metal)
|
|
whichSound is the checksum from the name of the looping sound (should be loaded using LoadSound
|
|
in the script file for each level)
|
|
whichArray indicates whether this sound belongs in the list of wheels rolling sounds, or
|
|
grinding sounds, etc...
|
|
*/
|
|
void CSk3SfxManager::SetSkaterSoundInfo( int surfaceFlag, uint32 whichSound, int whichArray,
|
|
float maxPitch, float minPitch, float maxVol, float minVol )
|
|
{
|
|
|
|
if (Sfx::NoSoundPlease()) return;
|
|
|
|
// must initialize PInfo!
|
|
int i;
|
|
Sfx::CSfxManager * sfx_manager = Sfx::CSfxManager::Instance();
|
|
|
|
if ( NULL == sfx_manager->GetWaveTableIndex( whichSound ) )
|
|
{
|
|
Dbg_MsgAssert( 0,( "Terrain sound not loaded! surface %d sound %s checksum %d soundType %d",
|
|
surfaceFlag, Script::FindChecksumName( whichSound ), whichSound, whichArray ));
|
|
return;
|
|
}
|
|
int numEntries = mNumEntries[ whichArray ];
|
|
SkaterSoundInfo *pArray = mSoundArray[ whichArray ];
|
|
SkaterSoundInfo *pInfo = NULL;
|
|
|
|
for ( i = 0; i < numEntries; i++ )
|
|
{
|
|
if ( pArray[ i ].surfaceFlag == surfaceFlag )
|
|
{
|
|
Dbg_Message( "Re-defining soundtype %d for surfaceFlag %d", whichArray, surfaceFlag );
|
|
pInfo = &pArray[ i ];
|
|
break;
|
|
}
|
|
}
|
|
if ( !pInfo )
|
|
{
|
|
pInfo = &pArray[ mNumEntries[ whichArray ] ];
|
|
mNumEntries[ whichArray ] += 1;
|
|
Dbg_MsgAssert( mNumEntries[ whichArray ] < vMAX_NUM_ENTRIES,( "Array too small type %d. Increase MAX_NUM_ENTRIES.", whichArray ));
|
|
}
|
|
|
|
Dbg_MsgAssert( pInfo,( "Please fire Matt immediately after kicking him in the nuts." ));
|
|
|
|
// surfaceFlag of zero will be used for the default
|
|
pInfo->surfaceFlag = surfaceFlag;
|
|
// if soundChecksum is zero, no sound will play on this surface.
|
|
pInfo->soundChecksum = whichSound;
|
|
pInfo->maxPitch = maxPitch;
|
|
pInfo->minPitch = minPitch;
|
|
pInfo->maxVol = maxVol;
|
|
pInfo->minVol = minVol;
|
|
|
|
} // end of SetSkaterSoundInfo( )
|
|
|
|
#endif
|
|
|
|
} // namespace Env
|