mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 08:51:22 +00:00
38c148c0f8
Added missing bounds checks for layout script commands. Fixed baseq2 paths in non-KMQ2 implementation for alias script loading, Lazarus text box loading, and GameDirRelativePath()/SavegameDirRelativePath() functions.
1506 lines
52 KiB
C
1506 lines
52 KiB
C
#include "./g_local.h"
|
|
|
|
#ifdef DISABLE_FMOD
|
|
|
|
void PlayFootstep (edict_t *ent, footstep_t index) {}
|
|
void FootStep (edict_t *ent) {}
|
|
qboolean FMOD_Init ()
|
|
{
|
|
return false;
|
|
}
|
|
void FMOD_Shutdown () {}
|
|
void FMOD_UpdateListenerPos () {}
|
|
void FMOD_UpdateSpeakerPos (edict_t *speaker) {}
|
|
void FMOD_Stop () {}
|
|
void CheckEndMusic (edict_t *ent) {}
|
|
void CheckEndSample (edict_t *ent) {}
|
|
int FMOD_PlaySound (edict_t *ent)
|
|
{
|
|
return 0;
|
|
}
|
|
void FMOD_StopSound (edict_t *ent, qboolean free) {}
|
|
void target_playback_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) {}
|
|
void target_playback_fadeout (edict_t *ent) {}
|
|
void target_playback_fadein (edict_t *ent) {}
|
|
qboolean FMOD_IsPlaying (edict_t *ent)
|
|
{
|
|
return false;
|
|
}
|
|
void Use_Target_Playback (edict_t *ent, edict_t *other, edict_t *activator) {}
|
|
void target_playback_delayed_start (edict_t *ent) {}
|
|
void target_playback_delayed_restart (edict_t *ent) {}
|
|
void SP_target_playback (edict_t *ent) {}
|
|
#ifdef FMOD_FOOTSTEPS
|
|
void ReadTextureSurfaceAssignments () {}
|
|
#endif // FMOD_FOOTSTEPS
|
|
|
|
#else // DISABLE_FMOD
|
|
|
|
#include "fmod.h"
|
|
#include <windows.h>
|
|
|
|
#define SF_PLAYBACK_LOOP 1
|
|
#define SF_PLAYBACK_TOGGLE 2
|
|
#define SF_PLAYBACK_MUSIC 4 // Is set, mapper says this is "music" and won't be played if fmod_nomusic is set
|
|
#define SF_PLAYBACK_STARTON 8
|
|
#define SF_PLAYBACK_3D 16 // Position info is used
|
|
#define SF_PLAYBACK_MUSICFILE 64 // Internal use, used to distinguish .mod, .s3m, .xm files
|
|
#define SF_PLAYBACK_SAMPLE 128 // Used to distinguish samples from streams
|
|
#define SF_PLAYBACK_TURNED_OFF 256 // Internal use, set when a target_playback is TURNED OFF rather
|
|
// than simply reaching the end
|
|
|
|
HMODULE hFMOD=(HMODULE)NULL; // Handle of fmod.dll
|
|
|
|
#ifdef FMOD_FOOTSTEPS
|
|
qboolean qFMOD_Footsteps; // Set to false in SP_worldspawn for DM/coop
|
|
|
|
struct texsurf_s
|
|
{
|
|
int step_id;
|
|
char tex[16];
|
|
};
|
|
typedef struct texsurf_s texsurf_t;
|
|
#define MAX_TEX_SURF 256
|
|
texsurf_t tex_surf[MAX_TEX_SURF];
|
|
int num_texsurfs;
|
|
#endif // FMOD_FOOTSTEPS
|
|
|
|
/* Here's what Lazarus does at the end of SP_worldspawn:
|
|
|
|
if (deathmatch->value || coop->value)
|
|
qFMOD_Footsteps = false;
|
|
else if (world->effects & FX_WORLDSPAWN_STEPSOUNDS)
|
|
{
|
|
qFMOD_Footsteps = true;
|
|
FMOD_Init();
|
|
}
|
|
else
|
|
qFMOD_Footsteps = false;
|
|
|
|
You'll notice that we don't use FMOD to play any footstep sounds UNLESS a map effects flag is
|
|
set - the only good reason for this requirement is kinda complicated: 1) FMOD doesn't like
|
|
"s_primary 1" at all, and using that setting will foul up ALL sounds on some sound cards
|
|
whether any FMOD functions are used or not. 2) We want to precache footstep sounds for
|
|
performance reasons. However, we can't know at runtime whether any surfaces in the map
|
|
use new surface flags for footsteps. So.. we want to call FMOD_Init to load FMOD and
|
|
precache footsteps, but we DON'T want to do that unless we really need to so that players
|
|
who normally use "s_primary 1" can continue to do so.
|
|
*/
|
|
|
|
/* All of the following isn't strictly necessary. Rather than using LoadLibrary and
|
|
GetProcAddress for all the FMOD functions, you COULD just link to their import
|
|
library. However, that means that your DLL will fail to load if FMOD.DLL isn't
|
|
found. Doing it this way removes that problem. Note that you'll also need to
|
|
comment out all of the API definitions in FMOD.H if you use this method. */
|
|
|
|
typedef signed char (__stdcall *FMUSIC_FREESONG) (FMUSIC_MODULE *mod);
|
|
typedef int (__stdcall *FMUSIC_GETMASTERVOLUME) (FMUSIC_MODULE *mod);
|
|
typedef signed char (__stdcall *FMUSIC_ISPLAYING) (FMUSIC_MODULE *mod);
|
|
typedef FMUSIC_MODULE *(__stdcall *FMUSIC_LOADSONG) (const char *name);
|
|
typedef signed char (__stdcall *FMUSIC_SETMASTERVOLUME) (FMUSIC_MODULE *mod,int volume);
|
|
typedef signed char (__stdcall *FMUSIC_PLAYSONG) (FMUSIC_MODULE *mod);
|
|
typedef void (__stdcall *FMUSIC_STOPALLSONGS) ();
|
|
typedef signed char (__stdcall *FMUSIC_STOPSONG) (FMUSIC_MODULE *mod);
|
|
|
|
typedef void (__stdcall *FSOUND_3D_LISTENER_SETATTRIBUTES) (float *pos,float *vel,float fx,float fy,float fz,float tx,float ty,float tz);
|
|
typedef void (__stdcall *FSOUND_3D_LISTENER_SETDISTANCEFACTOR) (float scale);
|
|
typedef void (__stdcall *FSOUND_3D_LISTENER_SETDOPPLERFACTOR) (float scale);
|
|
typedef void (__stdcall *FSOUND_3D_LISTENER_SETROLLOFFFACTOR) (float scale);
|
|
typedef signed char (__stdcall *FSOUND_3D_SETATTRIBUTES) (int channel,float *pos,float *vel);
|
|
typedef void (__stdcall *FSOUND_3D_UPDATE) ();
|
|
typedef void (__stdcall *FSOUND_CLOSE) ();
|
|
typedef int (__stdcall *FSOUND_GETERROR) ();
|
|
typedef int (__stdcall *FSOUND_GETVOLUME) (int channel);
|
|
typedef signed char (__stdcall *FSOUND_INIT) (int mixrate,
|
|
int maxsoftwarechannels,
|
|
unsigned int flags );
|
|
typedef signed char (__stdcall *FSOUND_ISPLAYING) (int channel);
|
|
typedef int (__stdcall *FSOUND_PLAYSOUND3DATTRIB) (int channel,
|
|
FSOUND_SAMPLE *sptr,
|
|
int freq,
|
|
int vol,
|
|
int pan,
|
|
float *pos,
|
|
float *vel);
|
|
typedef signed char (__stdcall *FSOUND_REVERB_SETMIX) (int channel, float mix);
|
|
typedef void (__stdcall *FSOUND_SAMPLE_FREE) (FSOUND_SAMPLE *sptr);
|
|
typedef FSOUND_SAMPLE *(__stdcall *FSOUND_SAMPLE_LOAD) (int index,const char *name,unsigned int mode,int memlength);
|
|
typedef signed char (__stdcall *FSOUND_SAMPLE_SETMINMAXDISTANCE) (FSOUND_SAMPLE *sptr,float min,float max);
|
|
|
|
typedef signed char (__stdcall *FSOUND_SETBUFFERSIZE) (int len_ms);
|
|
typedef signed char (__stdcall *FSOUND_SETMIXER) (int mixer);
|
|
typedef signed char (__stdcall *FSOUND_SETOUTPUT) (int outputtype);
|
|
typedef signed char (__stdcall *FSOUND_SETVOLUME) (int channel, int volume);
|
|
typedef signed char (__stdcall *FSOUND_STOPSOUND) (int channel);
|
|
typedef signed char (__stdcall *FSOUND_STREAM_CLOSE) (FSOUND_STREAM *stream);
|
|
typedef int (__stdcall *FSOUND_STREAM_GETLENGTHMS) (FSOUND_STREAM *stream);
|
|
typedef FSOUND_STREAM *(__stdcall *FSOUND_STREAM_OPENFILE) (const char *filename,
|
|
unsigned int mode,
|
|
int memlength);
|
|
typedef int (__stdcall *FSOUND_STREAM_PLAY) (int channel, FSOUND_STREAM *stream);
|
|
typedef int (__stdcall *FSOUND_STREAM_PLAY3DATTRIB) (int channel,
|
|
FSOUND_STREAM *stream,
|
|
int freq,
|
|
int vol,
|
|
int pan,
|
|
float *pos,
|
|
float *vel );
|
|
typedef signed char (__stdcall *FSOUND_STREAM_SETENDCALLBACK) (FSOUND_STREAM *stream,
|
|
FSOUND_STREAMCALLBACK callback,
|
|
int userdata);
|
|
|
|
|
|
FMUSIC_FREESONG FMUSIC_FreeSong;
|
|
FMUSIC_GETMASTERVOLUME FMUSIC_GetMasterVolume;
|
|
FMUSIC_ISPLAYING FMUSIC_IsPlaying;
|
|
FMUSIC_LOADSONG FMUSIC_LoadSong;
|
|
FMUSIC_PLAYSONG FMUSIC_PlaySong;
|
|
FMUSIC_SETMASTERVOLUME FMUSIC_SetMasterVolume;
|
|
FMUSIC_STOPALLSONGS FMUSIC_StopAllSongs;
|
|
FMUSIC_STOPSONG FMUSIC_StopSong;
|
|
|
|
FSOUND_3D_LISTENER_SETATTRIBUTES FSOUND_3D_Listener_SetAttributes;
|
|
FSOUND_3D_LISTENER_SETDISTANCEFACTOR FSOUND_3D_Listener_SetDistanceFactor;
|
|
FSOUND_3D_LISTENER_SETDOPPLERFACTOR FSOUND_3D_Listener_SetDopplerFactor;
|
|
FSOUND_3D_LISTENER_SETROLLOFFFACTOR FSOUND_3D_Listener_SetRolloffFactor;
|
|
FSOUND_3D_SETATTRIBUTES FSOUND_3D_SetAttributes;
|
|
FSOUND_3D_UPDATE FSOUND_3D_Update;
|
|
FSOUND_CLOSE FSOUND_Close;
|
|
FSOUND_GETERROR FSOUND_GetError;
|
|
FSOUND_GETVOLUME FSOUND_GetVolume;
|
|
FSOUND_INIT FSOUND_Init;
|
|
FSOUND_ISPLAYING FSOUND_IsPlaying;
|
|
FSOUND_PLAYSOUND3DATTRIB FSOUND_PlaySound3DAttrib;
|
|
FSOUND_REVERB_SETMIX FSOUND_Reverb_SetMix;
|
|
FSOUND_SAMPLE_FREE FSOUND_Sample_Free;
|
|
FSOUND_SAMPLE_LOAD FSOUND_Sample_Load;
|
|
FSOUND_SAMPLE_SETMINMAXDISTANCE FSOUND_Sample_SetMinMaxDistance;
|
|
FSOUND_SETOUTPUT FSOUND_SetOutput;
|
|
FSOUND_SETVOLUME FSOUND_SetVolume;
|
|
FSOUND_STOPSOUND FSOUND_StopSound;
|
|
FSOUND_STREAM_CLOSE FSOUND_Stream_Close;
|
|
FSOUND_STREAM_GETLENGTHMS FSOUND_Stream_GetLengthMs;
|
|
FSOUND_STREAM_OPENFILE FSOUND_Stream_OpenFile;
|
|
FSOUND_STREAM_PLAY FSOUND_Stream_Play;
|
|
FSOUND_STREAM_PLAY3DATTRIB FSOUND_Stream_Play3DAttrib;
|
|
FSOUND_STREAM_SETENDCALLBACK FSOUND_Stream_SetEndCallback;
|
|
|
|
/* Lazarus currently has 44 footstep sounds. These sounds are precached to avoid
|
|
a barely noticeable hiccup when the sounds are first played. The #defines for the
|
|
Footstep[] indices are in q_shared.h */
|
|
|
|
#ifdef FMOD_FOOTSTEPS
|
|
FSOUND_SAMPLE *Footstep[44];
|
|
|
|
void PlayFootstep (edict_t *ent, footstep_t index)
|
|
{
|
|
|
|
if (!qFMOD_Footsteps)
|
|
{
|
|
if (!ent->waterlevel)
|
|
ent->s.event = EV_FOOTSTEP;
|
|
return;
|
|
}
|
|
|
|
if (index < 0)
|
|
ent->s.event = EV_FOOTSTEP;
|
|
else
|
|
{
|
|
if (hFMOD && Footstep[index])
|
|
{
|
|
//Knightmare- quieter if in thirdperson mode
|
|
if (ent->client && ent->client->chaseactive)
|
|
FSOUND_PlaySound3DAttrib(FSOUND_FREE, Footstep[index], -1, 64, -1, NULL, NULL );
|
|
else
|
|
FSOUND_PlaySound3DAttrib(FSOUND_FREE, Footstep[index], -1, 128, -1, NULL, NULL );
|
|
}
|
|
else
|
|
ent->s.event = EV_FOOTSTEP;
|
|
}
|
|
/* Mapper has the option of setting a worldspawn flag to generate a "player_noise"
|
|
entity when the player makes a footstep sound. Normally, monsters ignore footsteps. */
|
|
if (world->effects & FX_WORLDSPAWN_ALERTSOUNDS)
|
|
PlayerNoise(ent,ent->s.origin,PNOISE_SELF);
|
|
}
|
|
|
|
static char *FootFile (char *in)
|
|
{
|
|
static char filename[256];
|
|
static char prefix[256];
|
|
static int init=0;
|
|
|
|
if (!init)
|
|
{
|
|
cvar_t *basedir, *gamedir;
|
|
basedir = gi.cvar("basedir", "", 0);
|
|
gamedir = gi.cvar("gamedir", "", 0);
|
|
if (strlen(gamedir->string))
|
|
{
|
|
if (strstr(in, "mud")) // Knightmare- mud sounds are in different subdir
|
|
Com_sprintf (prefix, sizeof(prefix), "%s/%s/sound/mud/", basedir->string, gamedir->string);
|
|
else
|
|
Com_sprintf (prefix, sizeof(prefix), "%s/%s/sound/player/", basedir->string, gamedir->string);
|
|
}
|
|
else
|
|
{
|
|
if (strstr(in, "mud")) // Knightmare- mud sounds are in different subdir
|
|
Com_sprintf (prefix, sizeof(prefix), "%s/baseq2/sound/mud/", basedir->string);
|
|
else
|
|
Com_sprintf (prefix, sizeof(prefix), "%s/baseq2/sound/player/", basedir->string);
|
|
}
|
|
init = 1;
|
|
}
|
|
Com_sprintf (filename, sizeof(filename), "%s%s", prefix ,in);
|
|
return filename;
|
|
}
|
|
|
|
static void PrecacheFootsteps ()
|
|
{
|
|
int mode=FSOUND_LOOP_OFF | FSOUND_2D;
|
|
|
|
if (!hFMOD)
|
|
return;
|
|
//Knightmare added
|
|
Footstep[FOOTSTEP_WADE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wade1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WADE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wade2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WADE3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wade3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WADE4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wade4.wav"), mode, 0);
|
|
|
|
Footstep[FOOTSTEP_MUD_WADE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("wade_mud1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_MUD_WADE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("wade_mud2.wav"), mode, 0);
|
|
|
|
Footstep[FOOTSTEP_SLOSH1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_slosh1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SLOSH2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_slosh2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SLOSH3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_slosh3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SLOSH4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_slosh4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_LADDER1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ladder1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_LADDER2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ladder2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_LADDER3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ladder3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_LADDER4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ladder4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_METAL1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_metal1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_METAL2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_metal2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_METAL3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_metal3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_METAL4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_metal4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_DIRT1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_dirt1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_DIRT2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_dirt2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_DIRT3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_dirt3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_DIRT4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_dirt4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_VENT1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_duct1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_VENT2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_duct2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_VENT3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_duct3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_VENT4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_duct4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRATE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grate1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRATE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grate2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRATE3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grate3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRATE4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grate4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_TILE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_tile1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_TILE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_tile2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_TILE3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_tile3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_TILE4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_tile4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRASS1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grass1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRASS2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grass2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRASS3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grass3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRASS4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_grass4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SNOW1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_snow1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SNOW2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_snow2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SNOW3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_snow3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SNOW4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_snow4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_CARPET1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_carpet1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_CARPET2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_carpet2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_CARPET3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_carpet3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_CARPET4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_carpet4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_FORCE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_force1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_FORCE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_force2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_FORCE3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_force3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_FORCE4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_force4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRAVEL1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_gravel1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRAVEL2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_gravel2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRAVEL3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_gravel3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_GRAVEL4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_gravel4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_ICE1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ice1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_ICE2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ice2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_ICE3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ice3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_ICE4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_ice4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SAND1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_sand1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SAND2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_sand2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SAND3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_sand3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_SAND4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_sand4.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WOOD1] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wood1.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WOOD2] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wood2.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WOOD3] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wood3.wav"), mode, 0);
|
|
Footstep[FOOTSTEP_WOOD4] = FSOUND_Sample_Load(FSOUND_FREE,FootFile("pl_wood4.wav"), mode, 0);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
FootStep
|
|
|
|
Plays appropriate footstep sound depending on surface flags of the ground.
|
|
Since this is a replacement for plain Jane EV_FOOTSTEP, we already know
|
|
the player is definitely on the ground when this is called.
|
|
=================
|
|
*/
|
|
void FootStep (edict_t *ent)
|
|
{
|
|
static int iSkipStep = 0;
|
|
|
|
trace_t tr;
|
|
vec3_t end;
|
|
int r;
|
|
int surface;
|
|
|
|
r = (rand() & 1) + ent->client->leftfoot*2;
|
|
ent->client->leftfoot = 1 - ent->client->leftfoot;
|
|
|
|
if (qFMOD_Footsteps)
|
|
{
|
|
if ( (ent->waterlevel == 1) && (ent->watertype & (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)) )
|
|
{
|
|
// Slosh sounds
|
|
PlayFootstep(ent,FOOTSTEP_SLOSH1 + r);
|
|
return;
|
|
}
|
|
if ( (ent->waterlevel == 2) && (ent->watertype & (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)) )
|
|
{
|
|
// Wade sounds
|
|
if (iSkipStep == 0)
|
|
{
|
|
iSkipStep++;
|
|
return;
|
|
}
|
|
if (iSkipStep++ == 3)
|
|
iSkipStep = 0;
|
|
|
|
/*switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade3.wav"),1.0,ATTN_NORM,0); break;
|
|
}*/
|
|
//Knightmare- play wading sounds through FMOD
|
|
PlayFootstep (ent,FOOTSTEP_WADE1 + r);
|
|
|
|
if (world->effects & FX_WORLDSPAWN_ALERTSOUNDS)
|
|
PlayerNoise(ent,ent->s.origin,PNOISE_SELF);
|
|
return;
|
|
}
|
|
VectorCopy(ent->s.origin,end);
|
|
end[2] -= 64;
|
|
tr = gi.trace(ent->s.origin,NULL,NULL,end,ent,MASK_SOLID | MASK_WATER);
|
|
if (!tr.surface)
|
|
{
|
|
PlayFootstep(ent,-1);
|
|
return;
|
|
}
|
|
|
|
surface = tr.surface->flags & SURF_STEPMASK;
|
|
switch (surface)
|
|
{
|
|
case SURF_METAL:
|
|
PlayFootstep(ent,FOOTSTEP_METAL1 + r);
|
|
break;
|
|
case SURF_DIRT:
|
|
PlayFootstep(ent,FOOTSTEP_DIRT1 + r);
|
|
break;
|
|
case SURF_VENT:
|
|
PlayFootstep(ent,FOOTSTEP_VENT1 + r);
|
|
break;
|
|
case SURF_GRATE:
|
|
PlayFootstep(ent,FOOTSTEP_GRATE1 + r);
|
|
break;
|
|
case SURF_TILE:
|
|
PlayFootstep(ent,FOOTSTEP_TILE1 + r);
|
|
break;
|
|
case SURF_GRASS:
|
|
PlayFootstep(ent,FOOTSTEP_GRASS1 + r);
|
|
break;
|
|
case SURF_SNOW:
|
|
PlayFootstep(ent,FOOTSTEP_SNOW1 + r);
|
|
break;
|
|
case SURF_CARPET:
|
|
PlayFootstep(ent,FOOTSTEP_CARPET1 + r);
|
|
break;
|
|
case SURF_FORCE:
|
|
PlayFootstep(ent,FOOTSTEP_FORCE1 + r);
|
|
break;
|
|
case SURF_GRAVEL:
|
|
PlayFootstep(ent,FOOTSTEP_GRAVEL1 + r);
|
|
break;
|
|
case SURF_ICE:
|
|
PlayFootstep(ent,FOOTSTEP_ICE1 + r);
|
|
break;
|
|
case SURF_SAND:
|
|
PlayFootstep(ent,FOOTSTEP_SAND1 + r);
|
|
break;
|
|
case SURF_WOOD:
|
|
PlayFootstep(ent,FOOTSTEP_WOOD1 + r);
|
|
break;
|
|
//case SURF_STANDARD:
|
|
// PlayFootstep(ent,-1);
|
|
// break;
|
|
default:
|
|
if (footstep_sounds->value && num_texsurfs)
|
|
{
|
|
int i;
|
|
int step=-1;
|
|
for (i=0; i<num_texsurfs; i++)
|
|
{
|
|
if (strstr(tr.surface->name,tex_surf[i].tex))
|
|
{
|
|
if (!tex_surf[i].step_id)
|
|
{
|
|
step = -1;
|
|
// tr.surface->flags |= SURF_STANDARD;
|
|
}
|
|
else
|
|
{
|
|
step = 4*(tex_surf[i].step_id-1) + r;
|
|
tr.surface->flags |= (SURF_METAL << (tex_surf[i].step_id - 1));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
PlayFootstep(ent,step);
|
|
}
|
|
else
|
|
PlayFootstep(ent,-1);
|
|
}
|
|
}
|
|
else
|
|
{ // normal Q2 sound
|
|
// Knightmare- completely disable this in DM and COOP
|
|
// I don't want all these sounds loaded into the stock Q2 sound system, period.
|
|
if (!ent->waterlevel)
|
|
ent->s.event = EV_FOOTSTEP;
|
|
|
|
/*if ((ent->waterlevel == 1) && (ent->watertype & CONTENTS_WATER))
|
|
{
|
|
// Slosh sounds
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_slosh1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_slosh3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_slosh2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_slosh4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
if (world->effects & FX_WORLDSPAWN_ALERTSOUNDS)
|
|
PlayerNoise(ent,ent->s.origin,PNOISE_SELF);
|
|
return;
|
|
}
|
|
if ((ent->waterlevel == 2) && (ent->watertype & CONTENTS_WATER))
|
|
{
|
|
// Wade sounds
|
|
if (iSkipStep == 0)
|
|
{
|
|
iSkipStep++;
|
|
return;
|
|
}
|
|
if (iSkipStep++ == 3)
|
|
iSkipStep = 0;
|
|
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/wade3.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
if (world->effects & FX_WORLDSPAWN_ALERTSOUNDS)
|
|
PlayerNoise(ent,ent->s.origin,PNOISE_SELF);
|
|
return;
|
|
}
|
|
VectorCopy(ent->s.origin,end);
|
|
end[2] -= 32;
|
|
tr = gi.trace(ent->s.origin,NULL,NULL,end,ent,MASK_SOLID | MASK_WATER);
|
|
if (!tr.surface)
|
|
{
|
|
PlayFootstep(ent,-1);
|
|
return;
|
|
}
|
|
|
|
surface = tr.surface->flags & SURF_STEPMASK;
|
|
switch (tr.surface->flags)
|
|
{
|
|
case SURF_METAL:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_DIRT:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_VENT:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_GRATE:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_TILE:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_GRASS:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_SNOW:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_CARPET:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
case SURF_FORCE:
|
|
switch (r)
|
|
{
|
|
case 0: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force1.wav"),1.0,ATTN_NORM,0); break;
|
|
case 1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force3.wav"),1.0,ATTN_NORM,0); break;
|
|
case 2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force2.wav"),1.0,ATTN_NORM,0); break;
|
|
case 3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force4.wav"),1.0,ATTN_NORM,0); break;
|
|
}
|
|
break;
|
|
default:
|
|
if (footstep_sounds->value && num_texsurfs)
|
|
{
|
|
int i;
|
|
int step=-1;
|
|
for (i=0; i<num_texsurfs; i++)
|
|
{
|
|
if (strstr(tr.surface->name,tex_surf[i].tex))
|
|
{
|
|
if (!tex_surf[i].step_id)
|
|
step = -1;
|
|
else
|
|
step = 4*(tex_surf[i].step_id-1) + r;
|
|
break;
|
|
}
|
|
}
|
|
switch (step)
|
|
{
|
|
case FOOTSTEP_METAL1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_METAL2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_METAL3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_METAL4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_metal4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_DIRT1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_DIRT2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_DIRT3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_DIRT4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_dirt4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_VENT1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_VENT2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_VENT3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_VENT4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_duct4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRATE1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRATE2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRATE3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRATE4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grate4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_TILE1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_TILE2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_TILE3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_TILE4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_tile4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRASS1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRASS2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRASS3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_GRASS4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_grass4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_SNOW1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_SNOW2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_SNOW3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_SNOW4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_snow4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_CARPET1:gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_CARPET2:gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_CARPET3:gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_CARPET4:gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_carpet4.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_FORCE1: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force1.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_FORCE2: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force3.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_FORCE3: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force2.wav"),1.0,ATTN_NORM,0); break;
|
|
case FOOTSTEP_FORCE4: gi.sound(ent,CHAN_VOICE,gi.soundindex("player/pl_force4.wav"),1.0,ATTN_NORM,0); break;
|
|
default: ent->s.event = EV_FOOTSTEP;
|
|
}
|
|
}
|
|
else
|
|
ent->s.event = EV_FOOTSTEP;
|
|
}*/
|
|
if (world->effects & FX_WORLDSPAWN_ALERTSOUNDS)
|
|
PlayerNoise(ent,ent->s.origin,PNOISE_SELF);
|
|
}
|
|
}
|
|
|
|
#endif // FMOD footsteps
|
|
/* All other footstep-related code is in p_view.c. Short version: replace all
|
|
"ent->s.event = EV_FOOTSTEP" with a call to Footstep and check out G_SetClientEvent,
|
|
where water and ladder sounds are played. */
|
|
|
|
qboolean FMOD_Init ()
|
|
{
|
|
char dllname[MAX_QPATH];
|
|
|
|
if (!deathmatch)
|
|
deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
|
|
|
|
/* This is a Lazarus-specific cvar that overrides the decision to not use FMOD in
|
|
DM. Only reason to do this is if you want to use FMOD while playing against bots.
|
|
Don't ask me about the crazy name - this is what MD suggested :-) */
|
|
if (!packet_fmod_playback)
|
|
packet_fmod_playback = gi.cvar("packet_fmod_playback", "0", CVAR_SERVERINFO);
|
|
|
|
/* FMOD really really REALLY does not like "s_primary 1", particularly on better
|
|
sound cards. We tried all sorts of workarounds to no avail before settling on
|
|
bitching at the player and making it HIS fault. */
|
|
if (!s_primary)
|
|
s_primary = gi.cvar("s_primary", "0", 0);
|
|
if (s_primary->value)
|
|
{
|
|
gi.dprintf("target_playback requires s_primary be set to 0.\n"
|
|
"At the console type:\n"
|
|
"s_primary 0;sound_restart\n");
|
|
}
|
|
|
|
if (deathmatch->value && !packet_fmod_playback->value)
|
|
{
|
|
hFMOD = (HMODULE)(NULL);
|
|
return false;
|
|
}
|
|
GameDirRelativePath("fmod.dll", dllname, sizeof(dllname));
|
|
hFMOD = LoadLibrary(dllname);
|
|
if (hFMOD)
|
|
{
|
|
FMUSIC_FreeSong = (FMUSIC_FREESONG)GetProcAddress(hFMOD,"_FMUSIC_FreeSong@4");
|
|
FMUSIC_GetMasterVolume = (FMUSIC_GETMASTERVOLUME)GetProcAddress(hFMOD,"_FMUSIC_GetMasterVolume@4");
|
|
FMUSIC_IsPlaying = (FMUSIC_ISPLAYING)GetProcAddress(hFMOD,"_FMUSIC_IsPlaying@4");
|
|
FMUSIC_LoadSong = (FMUSIC_LOADSONG)GetProcAddress(hFMOD,"_FMUSIC_LoadSong@4");
|
|
FMUSIC_PlaySong = (FMUSIC_PLAYSONG)GetProcAddress(hFMOD,"_FMUSIC_PlaySong@4");
|
|
FMUSIC_SetMasterVolume = (FMUSIC_SETMASTERVOLUME)GetProcAddress(hFMOD,"_FMUSIC_SetMasterVolume@8");
|
|
FMUSIC_StopAllSongs = (FMUSIC_STOPALLSONGS)GetProcAddress(hFMOD,"_FMUSIC_StopAllSongs@0");
|
|
FMUSIC_StopSong = (FMUSIC_STOPSONG)GetProcAddress(hFMOD,"_FMUSIC_StopSong@4");
|
|
|
|
FSOUND_3D_Listener_SetAttributes = (FSOUND_3D_LISTENER_SETATTRIBUTES)GetProcAddress(hFMOD,"_FSOUND_3D_Listener_SetAttributes@32");
|
|
FSOUND_3D_Listener_SetDistanceFactor = (FSOUND_3D_LISTENER_SETDISTANCEFACTOR)GetProcAddress(hFMOD,"_FSOUND_3D_Listener_SetDistanceFactor@4");
|
|
FSOUND_3D_Listener_SetDopplerFactor = (FSOUND_3D_LISTENER_SETDOPPLERFACTOR)GetProcAddress(hFMOD,"_FSOUND_3D_Listener_SetDopplerFactor@4");
|
|
FSOUND_3D_Listener_SetRolloffFactor = (FSOUND_3D_LISTENER_SETROLLOFFFACTOR)GetProcAddress(hFMOD,"_FSOUND_3D_Listener_SetRolloffFactor@4");
|
|
FSOUND_3D_SetAttributes = (FSOUND_3D_SETATTRIBUTES)GetProcAddress(hFMOD,"_FSOUND_3D_SetAttributes@12");
|
|
FSOUND_3D_Update = (FSOUND_3D_UPDATE)GetProcAddress(hFMOD,"_FSOUND_3D_Update@0");
|
|
FSOUND_Close = (FSOUND_CLOSE)GetProcAddress(hFMOD,"_FSOUND_Close@0");
|
|
FSOUND_GetError = (FSOUND_GETERROR)GetProcAddress(hFMOD,"_FSOUND_GetError@0");
|
|
FSOUND_GetVolume = (FSOUND_GETVOLUME)GetProcAddress(hFMOD,"_FSOUND_GetVolume@4");
|
|
FSOUND_Init = (FSOUND_INIT)GetProcAddress(hFMOD,"_FSOUND_Init@12");
|
|
FSOUND_IsPlaying = (FSOUND_ISPLAYING)GetProcAddress(hFMOD,"_FSOUND_IsPlaying@4");
|
|
FSOUND_PlaySound3DAttrib = (FSOUND_PLAYSOUND3DATTRIB)GetProcAddress(hFMOD,"_FSOUND_PlaySound3DAttrib@28");
|
|
FSOUND_Reverb_SetMix = (FSOUND_REVERB_SETMIX)GetProcAddress(hFMOD,"_FSOUND_Reverb_SetMix@8");
|
|
FSOUND_Sample_Free = (FSOUND_SAMPLE_FREE)GetProcAddress(hFMOD,"_FSOUND_Sample_Free@4");
|
|
FSOUND_Sample_Load = (FSOUND_SAMPLE_LOAD)GetProcAddress(hFMOD,"_FSOUND_Sample_Load@16");
|
|
FSOUND_Sample_SetMinMaxDistance = (FSOUND_SAMPLE_SETMINMAXDISTANCE)GetProcAddress(hFMOD,"_FSOUND_Sample_SetMinMaxDistance@12");
|
|
|
|
FSOUND_SetOutput = (FSOUND_SETOUTPUT)GetProcAddress(hFMOD,"_FSOUND_SetOutput@4");
|
|
FSOUND_SetVolume = (FSOUND_SETVOLUME)GetProcAddress(hFMOD,"_FSOUND_SetVolume@8");
|
|
FSOUND_StopSound = (FSOUND_STOPSOUND)GetProcAddress(hFMOD,"_FSOUND_StopSound@4");
|
|
FSOUND_Stream_Close = (FSOUND_STREAM_CLOSE)GetProcAddress(hFMOD,"_FSOUND_Stream_Close@4");
|
|
FSOUND_Stream_GetLengthMs = (FSOUND_STREAM_GETLENGTHMS)GetProcAddress(hFMOD,"_FSOUND_Stream_GetLengthMs@4");
|
|
FSOUND_Stream_OpenFile = (FSOUND_STREAM_OPENFILE)GetProcAddress(hFMOD,"_FSOUND_Stream_OpenFile@12");
|
|
FSOUND_Stream_Play = (FSOUND_STREAM_PLAY)GetProcAddress(hFMOD,"_FSOUND_Stream_Play@8");
|
|
FSOUND_Stream_Play3DAttrib= (FSOUND_STREAM_PLAY3DATTRIB)GetProcAddress(hFMOD,"_FSOUND_Stream_Play3DAttrib@28");
|
|
FSOUND_Stream_SetEndCallback = (FSOUND_STREAM_SETENDCALLBACK)GetProcAddress(hFMOD,"_FSOUND_Stream_SetEndCallback@12");
|
|
|
|
if (!FSOUND_Init(44100, 32, 0))
|
|
{
|
|
gi.dprintf("FSOUND_Init failed, error code=%d\n",FSOUND_GetError());
|
|
FSOUND_Close();
|
|
FreeLibrary(hFMOD);
|
|
hFMOD = (HMODULE)(-1);
|
|
return false;
|
|
}
|
|
FSOUND_3D_Listener_SetRolloffFactor(world->attenuation);
|
|
FSOUND_3D_Listener_SetDopplerFactor(world->moveinfo.distance);
|
|
#ifdef FMOD_FOOTSTEPS
|
|
|
|
if (qFMOD_Footsteps)
|
|
PrecacheFootsteps();
|
|
#endif
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* FMOD_Shutdown is called by ShutdownGame and also by our goofy
|
|
"sound_restart" console command (which I don't recommend duplicating). */
|
|
|
|
void FMOD_Shutdown ()
|
|
{
|
|
if (hFMOD)
|
|
{
|
|
FMOD_Stop(); // stops all target_playback sounds
|
|
FSOUND_Close();
|
|
FreeLibrary(hFMOD);
|
|
hFMOD = (HMODULE)NULL;
|
|
}
|
|
}
|
|
|
|
/*======================================================================================
|
|
|
|
Everything below this point is related to target_playback. Don't want target_playback?
|
|
Then you're done :-)
|
|
|
|
Add these to the edict_s structure in g_local.h
|
|
|
|
// FMOD
|
|
int *stream; // Actually a FSOUND_STREAM * or FMUSIC_MODULE *
|
|
int channel;
|
|
|
|
Only other real change is in WriteLevel. The purpose of the mess below is
|
|
to restart a target_playback that was playing when the player left a level
|
|
if he returns to the same level. The linkcount business is used in
|
|
target_playback_delayed_restart to postpone playback until the player is
|
|
conscious - initial version didn't do this and it was disconcerting to
|
|
players to have music crank up while the level was loading.
|
|
|
|
// write out all the entities
|
|
for (i=0 ; i<globals.num_edicts ; i++)
|
|
{
|
|
ent = &g_edicts[i];
|
|
if (!ent->inuse)
|
|
continue;
|
|
if (!Q_stricmp(ent->classname,"target_playback"))
|
|
{
|
|
edict_t e;
|
|
memcpy(&e,ent,sizeof(edict_t));
|
|
if (FMOD_IsPlaying(ent))
|
|
{
|
|
e.think = target_playback_delayed_restart;
|
|
e.nextthink = level.time + 1.0;
|
|
// A misuse of groundentity_linkcount, but
|
|
// maybe nobody is watching.
|
|
e.groundentity_linkcount = g_edicts[1].linkcount;
|
|
}
|
|
else
|
|
{
|
|
e.think = NULL;
|
|
e.nextthink = 0;
|
|
}
|
|
e.stream = NULL;
|
|
fwrite (&i, sizeof(i), 1, f);
|
|
WriteEdict (f, &e);
|
|
}
|
|
else
|
|
{
|
|
fwrite (&i, sizeof(i), 1, f);
|
|
WriteEdict (f, ent);
|
|
}
|
|
}
|
|
|
|
=======================================================================================*/
|
|
|
|
/* FMOD_UpdateListenerPos is called every frame from G_RunFrame, but ONLY if the
|
|
map contains 3D sounds. Add this to the end of G_RunFrame:
|
|
|
|
if ( (level.num_3D_sounds > 0) && (game.maxclients == 1))
|
|
FMOD_UpdateListenerPos();
|
|
|
|
level.num_3D_sounds is incremented in SP_target_playback for 3D sounds and
|
|
decremented if a 3D target_playback "dies".
|
|
|
|
*/
|
|
void FMOD_UpdateListenerPos ()
|
|
{
|
|
vec3_t pos, vel, forward, up;
|
|
edict_t *player = &g_edicts[1];
|
|
|
|
if (!player || !player->inuse)
|
|
return;
|
|
|
|
if (!hFMOD) return;
|
|
|
|
AngleVectors(player->s.angles,forward,NULL,up);
|
|
VectorSet(pos,player->s.origin[1],player->s.origin[2],player->s.origin[0]);
|
|
VectorSet(vel,player->velocity[1],player->velocity[2],player->velocity[0]);
|
|
VectorScale(pos,0.025,pos);
|
|
VectorScale(vel,0.025,vel);
|
|
FSOUND_3D_Listener_SetAttributes(pos,vel,-forward[1],forward[2],-forward[0],-up[1],up[2],-up[0]);
|
|
FSOUND_3D_Update();
|
|
}
|
|
|
|
/* FMOD_UpdateSpeakerPos is called whenever a 3D target_playback moves. Only way to
|
|
move a target_playback in Lazarus currently is to set it to "movewith" a train.
|
|
Lazarus uses 40 Q2 units/meter scale factor (that's where the 0.025 below comes
|
|
in). FMOD *does* allow you to set a scale factor that supposedly allows you to
|
|
use whatever units you want rather than multiplying position and velocity every
|
|
time, but I found that it screws up the attenuation with distance features. */
|
|
|
|
void FMOD_UpdateSpeakerPos (edict_t *speaker)
|
|
{
|
|
vec3_t pos, vel;
|
|
|
|
if (!hFMOD) return;
|
|
|
|
if (!speaker->stream)
|
|
return;
|
|
|
|
VectorSet(pos,speaker->s.origin[1],speaker->s.origin[2],speaker->s.origin[0]);
|
|
VectorSet(vel,speaker->velocity[1],speaker->velocity[2],speaker->velocity[0]);
|
|
VectorScale(pos,0.025,pos);
|
|
VectorScale(vel,0.025,vel);
|
|
FSOUND_3D_SetAttributes(speaker->channel,pos,vel);
|
|
}
|
|
|
|
/* FMOD_Stop stops all playback, but doesn't kill FMOD. It is called by
|
|
FMOD_Shutdown and use_target_changelevel. */
|
|
|
|
void FMOD_Stop ()
|
|
{
|
|
if (hFMOD)
|
|
{
|
|
edict_t *e;
|
|
int i;
|
|
|
|
for (i=game.maxclients+1; i<globals.num_edicts; i++)
|
|
{
|
|
// Stop all playback. Make DAMN SURE "stream" is never
|
|
// used by any entity other than target_playback, or
|
|
// this will break for sure.
|
|
e = &g_edicts[i];
|
|
if (!e->inuse)
|
|
continue;
|
|
if (!e->stream)
|
|
continue;
|
|
if (e->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
{
|
|
if (FMUSIC_IsPlaying((FMUSIC_MODULE *)e->stream))
|
|
FMUSIC_StopSong ((FMUSIC_MODULE *)e->stream);
|
|
FMUSIC_FreeSong ((FMUSIC_MODULE *)e->stream);
|
|
}
|
|
else if (e->spawnflags & SF_PLAYBACK_SAMPLE)
|
|
{
|
|
FSOUND_StopSound(e->channel);
|
|
FSOUND_Sample_Free((FSOUND_SAMPLE *)e->stream);
|
|
}
|
|
else
|
|
FSOUND_Stream_Close((FSOUND_STREAM *)e->stream);
|
|
e->stream = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Music files don't have a "duration", or at least not one that you can have
|
|
reported by FMOD. So if you want to ramp them down, loop them, or do other
|
|
effects at the end of a song you'll have to have the music-playing
|
|
target_playback "think" with CheckEndMusic. */
|
|
|
|
void CheckEndMusic (edict_t *ent)
|
|
{
|
|
if (!ent->inuse)
|
|
return;
|
|
if (!ent->stream)
|
|
return;
|
|
if (!(ent->spawnflags & SF_PLAYBACK_MUSICFILE))
|
|
return;
|
|
|
|
if (FMUSIC_IsPlaying((FMUSIC_MODULE *)ent->stream))
|
|
ent->nextthink = level.time + 1.0;
|
|
else
|
|
{
|
|
if (!(ent->spawnflags & SF_PLAYBACK_TURNED_OFF))
|
|
{
|
|
if (ent->spawnflags & SF_PLAYBACK_LOOP)
|
|
{
|
|
// We didn't turn it off, so crank it back up
|
|
FMOD_PlaySound(ent);
|
|
return;
|
|
}
|
|
if (ent->target)
|
|
{
|
|
char *save_message;
|
|
save_message = ent->message;
|
|
ent->message = NULL;
|
|
G_UseTargets(ent, ent->activator);
|
|
ent->message = save_message;
|
|
}
|
|
}
|
|
FMUSIC_FreeSong ((FMUSIC_MODULE *)ent->stream);
|
|
ent->stream = NULL;
|
|
if (!ent->count)
|
|
G_FreeEdict(ent);
|
|
}
|
|
}
|
|
|
|
void CheckEndSample (edict_t *ent)
|
|
{
|
|
if (!ent->inuse)
|
|
return;
|
|
if (!ent->stream)
|
|
return;
|
|
if (FSOUND_IsPlaying(ent->channel))
|
|
ent->nextthink = level.time + 1.0;
|
|
else
|
|
{
|
|
if (!(ent->spawnflags & SF_PLAYBACK_TURNED_OFF))
|
|
{
|
|
if (ent->target)
|
|
{
|
|
char *save_message;
|
|
save_message = ent->message;
|
|
ent->message = NULL;
|
|
G_UseTargets(ent, ent->activator);
|
|
ent->message = save_message;
|
|
}
|
|
}
|
|
FSOUND_StopSound(ent->channel);
|
|
FSOUND_Sample_Free((FSOUND_SAMPLE *)ent->stream);
|
|
ent->stream = NULL;
|
|
if (!ent->count)
|
|
G_FreeEdict(ent);
|
|
}
|
|
}
|
|
|
|
static signed char EndStream (FSOUND_STREAM *stream,void *buff,int len,int param)
|
|
{
|
|
edict_t *e;
|
|
|
|
e = (edict_t *)param;
|
|
if (!e)
|
|
return TRUE;
|
|
if (!e->inuse)
|
|
return TRUE;
|
|
|
|
if (!(e->spawnflags & SF_PLAYBACK_TURNED_OFF))
|
|
{
|
|
if (e->target)
|
|
{
|
|
char *save_message;
|
|
save_message = e->message;
|
|
e->message = NULL;
|
|
G_UseTargets(e, e->activator);
|
|
e->message = save_message;
|
|
}
|
|
}
|
|
FSOUND_Stream_Close(stream);
|
|
e->stream = NULL;
|
|
if (!e->count)
|
|
G_FreeEdict(e);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int FMOD_PlaySound (edict_t *ent)
|
|
{
|
|
int mode;
|
|
|
|
if (!hFMOD)
|
|
FMOD_Init();
|
|
|
|
if (!hFMOD)
|
|
{
|
|
gi.dprintf("FMOD.DLL not loaded\n");
|
|
return 0;
|
|
}
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
{
|
|
ent->stream = (int *)FMUSIC_LoadSong(ent->message);
|
|
if (ent->stream)
|
|
{
|
|
FMUSIC_SetMasterVolume((FMUSIC_MODULE *)ent->stream,(int)(ent->volume));
|
|
if ( FMUSIC_PlaySong((FMUSIC_MODULE *)ent->stream) )
|
|
{
|
|
ent->think = CheckEndMusic;
|
|
ent->nextthink = level.time + 1.0;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FMUSIC_PlaySong failed on %s\n",ent->message);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FMUSIC_LoadSong failed on %s\n",ent->message);
|
|
return 0;
|
|
}
|
|
}
|
|
else if (ent->spawnflags & SF_PLAYBACK_SAMPLE)
|
|
{
|
|
if (!ent->stream)
|
|
{
|
|
if (ent->spawnflags & SF_PLAYBACK_LOOP)
|
|
mode = FSOUND_LOOP_NORMAL;
|
|
else
|
|
mode = FSOUND_LOOP_OFF;
|
|
|
|
if (!(ent->spawnflags & SF_PLAYBACK_3D))
|
|
mode |= FSOUND_2D;
|
|
|
|
ent->stream = (int *)FSOUND_Sample_Load(FSOUND_FREE,ent->message, mode, 0);
|
|
}
|
|
if (ent->stream)
|
|
{
|
|
int volume;
|
|
|
|
if (ent->fadein > 0)
|
|
volume = 0;
|
|
else
|
|
volume = (int)(ent->volume);
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_3D)
|
|
{
|
|
vec3_t pos;
|
|
|
|
VectorSet(pos,ent->s.origin[1],ent->s.origin[2],ent->s.origin[0]);
|
|
VectorScale(pos,0.025,pos);
|
|
ent->channel = FSOUND_PlaySound3DAttrib(FSOUND_FREE, (FSOUND_SAMPLE *)ent->stream, -1, volume, -1, pos, NULL );
|
|
FSOUND_Sample_SetMinMaxDistance( (FSOUND_SAMPLE *)ent->stream, ent->moveinfo.distance, 1000000000.0f);
|
|
FSOUND_Reverb_SetMix(ent->channel,1.0f);
|
|
}
|
|
else
|
|
{
|
|
ent->channel = FSOUND_PlaySound3DAttrib(FSOUND_FREE, (FSOUND_SAMPLE *)ent->stream, -1, volume, -1, NULL, NULL );
|
|
FSOUND_Reverb_SetMix(ent->channel,1.0f);
|
|
}
|
|
|
|
if (ent->channel >= 0)
|
|
{
|
|
ent->spawnflags &= ~SF_PLAYBACK_TURNED_OFF;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FSOUND_PlaySound3DAttrib failed on %s\n",ent->message);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FSOUND_Sample_Load failed on %s\n",ent->message);
|
|
ent->channel = -1;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ent->spawnflags & SF_PLAYBACK_LOOP)
|
|
mode = FSOUND_LOOP_NORMAL;
|
|
else
|
|
mode = FSOUND_LOOP_OFF;
|
|
|
|
// ??? Don't use FSOUND_HW3D because A3D cards screw up???
|
|
|
|
if (!(ent->spawnflags & SF_PLAYBACK_3D))
|
|
mode |= FSOUND_2D;
|
|
|
|
ent->stream = (int *)FSOUND_Stream_OpenFile(ent->message, mode, 0);
|
|
if (ent->stream)
|
|
{
|
|
int volume;
|
|
|
|
if (ent->fadein > 0)
|
|
volume = 0;
|
|
else
|
|
volume = (int)(ent->volume);
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_3D)
|
|
{
|
|
vec3_t pos;
|
|
|
|
VectorSet(pos,ent->s.origin[1],ent->s.origin[2],ent->s.origin[0]);
|
|
VectorScale(pos,0.025,pos);
|
|
ent->channel = FSOUND_Stream_Play3DAttrib(FSOUND_FREE, (FSOUND_STREAM *)ent->stream, -1, volume, -1, pos, NULL );
|
|
FSOUND_Reverb_SetMix(ent->channel,1.0f);
|
|
}
|
|
else
|
|
{
|
|
ent->channel = FSOUND_Stream_Play3DAttrib(FSOUND_FREE, (FSOUND_STREAM *)ent->stream, -1, volume, -1, NULL, NULL );
|
|
FSOUND_Reverb_SetMix(ent->channel,1.0f);
|
|
}
|
|
|
|
if (ent->channel >= 0)
|
|
{
|
|
ent->spawnflags &= ~SF_PLAYBACK_TURNED_OFF;
|
|
FSOUND_Stream_SetEndCallback((FSOUND_STREAM *)ent->stream,EndStream,(int)ent);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FSOUND_Stream_Play3DAttrib failed on %s\n",ent->message);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("FSOUND_Stream_OpenFile failed on %s\n",ent->message);
|
|
ent->channel = -1;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FMOD_StopSound (edict_t *ent, qboolean free)
|
|
{
|
|
if (!hFMOD)
|
|
return;
|
|
|
|
ent->spawnflags |= SF_PLAYBACK_TURNED_OFF;
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
{
|
|
if (FMUSIC_IsPlaying((FMUSIC_MODULE *)ent->stream))
|
|
FMUSIC_StopSong ((FMUSIC_MODULE *)ent->stream);
|
|
if (free)
|
|
{
|
|
FMUSIC_FreeSong ((FMUSIC_MODULE *)ent->stream);
|
|
ent->stream = NULL;
|
|
}
|
|
}
|
|
else if (ent->spawnflags & SF_PLAYBACK_SAMPLE)
|
|
{
|
|
if (FSOUND_IsPlaying(ent->channel))
|
|
FSOUND_StopSound(ent->channel);
|
|
ent->channel = -1;
|
|
if (free)
|
|
{
|
|
FSOUND_Sample_Free((FSOUND_SAMPLE *)ent->stream);
|
|
ent->stream = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FSOUND_IsPlaying(ent->channel))
|
|
FSOUND_StopSound(ent->channel);
|
|
ent->channel = -1;
|
|
if (free)
|
|
{
|
|
FSOUND_Stream_Close((FSOUND_STREAM *)ent->stream);
|
|
ent->stream = NULL;
|
|
}
|
|
}
|
|
|
|
if (!ent->count)
|
|
G_FreeEdict(ent);
|
|
}
|
|
|
|
void target_playback_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
if (!hFMOD)
|
|
return;
|
|
|
|
// if it's 3D, decrement level 3D count for efficiency
|
|
if (self->spawnflags & SF_PLAYBACK_3D)
|
|
level.num_3D_sounds--;
|
|
|
|
self->count = 0;
|
|
FMOD_StopSound(self,true);
|
|
}
|
|
|
|
void target_playback_fadeout (edict_t *ent)
|
|
{
|
|
int volume;
|
|
|
|
if (!ent->stream)
|
|
return;
|
|
|
|
if (ent->fadeout <= 0) // should never have come here?
|
|
return;
|
|
|
|
if (level.time - ent->timestamp < ent->fadeout)
|
|
{
|
|
volume = (int)(ent->density * (1.0 - (level.time-ent->timestamp)/ent->fadeout));
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
FMUSIC_SetMasterVolume((FMUSIC_MODULE *)ent->stream,volume);
|
|
else
|
|
FSOUND_SetVolume(ent->channel,volume);
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
}
|
|
}
|
|
|
|
void target_playback_fadein (edict_t *ent)
|
|
{
|
|
int volume;
|
|
|
|
if (!ent->stream)
|
|
return;
|
|
|
|
if (ent->fadein <= 0) // should never have come here?
|
|
return;
|
|
|
|
if (level.time > ent->timestamp + ent->fadein)
|
|
return;
|
|
|
|
volume = (int)(ent->volume*(level.time - ent->timestamp)/ent->fadein);
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
FMUSIC_SetMasterVolume((FMUSIC_MODULE *)ent->stream,volume);
|
|
else
|
|
{
|
|
if (!FSOUND_SetVolume(ent->channel,volume))
|
|
gi.dprintf("FSOUND_SetVolume failed, error code=%d, channel=%d\n",FSOUND_GetError(),ent->channel);
|
|
}
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
}
|
|
|
|
qboolean FMOD_IsPlaying (edict_t *ent)
|
|
{
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
{
|
|
if (ent->stream)
|
|
return FMUSIC_IsPlaying((FMUSIC_MODULE *)ent->stream);
|
|
else
|
|
return false;
|
|
}
|
|
else if (ent->channel >= 0)
|
|
{
|
|
return FSOUND_IsPlaying(ent->channel);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Use_Target_Playback (edict_t *ent, edict_t *other, edict_t *activator)
|
|
{
|
|
vec3_t pos = {0, 0, 0};
|
|
vec3_t vel = {0, 0, 0};
|
|
int volume = 255;
|
|
|
|
if (fmod_nomusic->value && (ent->spawnflags & SF_PLAYBACK_MUSIC))
|
|
return;
|
|
|
|
if (s_primary->value)
|
|
{
|
|
gi.dprintf("target_playback requires s_primary be set to 0.\n"
|
|
"At the console type:\n"
|
|
"s_primary 0;sound_restart\n");
|
|
return;
|
|
}
|
|
|
|
if (!ent->count)
|
|
{
|
|
if (ent->stream)
|
|
FMOD_StopSound(ent,true);
|
|
else
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
|
|
if (FMOD_IsPlaying(ent))
|
|
{
|
|
if (ent->spawnflags & (SF_PLAYBACK_LOOP | SF_PLAYBACK_TOGGLE))
|
|
{
|
|
if (ent->fadeout > 0)
|
|
{
|
|
if (ent->spawnflags & SF_PLAYBACK_MUSICFILE)
|
|
ent->density = FMUSIC_GetMasterVolume((FMUSIC_MODULE *)ent->stream);
|
|
else
|
|
ent->density = FSOUND_GetVolume(ent->channel);
|
|
ent->timestamp = level.time;
|
|
ent->think = target_playback_fadeout;
|
|
ent->think(ent);
|
|
}
|
|
else
|
|
{
|
|
FMOD_StopSound (ent, ((ent->spawnflags & SF_PLAYBACK_SAMPLE) ? false : true ));
|
|
ent->think = NULL;
|
|
ent->nextthink = 0;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Not toggled - just turn it off then restart it below
|
|
FMOD_StopSound (ent, ((ent->spawnflags & SF_PLAYBACK_SAMPLE) ? false : true ));
|
|
ent->think = NULL;
|
|
ent->nextthink = 0;
|
|
}
|
|
}
|
|
|
|
if ( !FMOD_PlaySound(ent) )
|
|
return;
|
|
|
|
ent->count--;
|
|
ent->timestamp = level.time;
|
|
ent->activator = activator;
|
|
if (ent->fadein > 0)
|
|
{
|
|
ent->think = target_playback_fadein;
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
}
|
|
}
|
|
|
|
void target_playback_delayed_start (edict_t *ent)
|
|
{
|
|
if (!g_edicts[1].linkcount || (ent->groundentity_linkcount == g_edicts[1].linkcount))
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
else
|
|
ent->use(ent,world,world);
|
|
}
|
|
|
|
void target_playback_delayed_restart (edict_t *ent)
|
|
{
|
|
if (!g_edicts[1].linkcount || (ent->groundentity_linkcount == g_edicts[1].linkcount))
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
else
|
|
{
|
|
ent->think = target_playback_delayed_start;
|
|
ent->nextthink = level.time + 2.0;
|
|
}
|
|
}
|
|
|
|
void SP_target_playback (edict_t *ent)
|
|
{
|
|
char filename[_MAX_PATH];
|
|
|
|
if (!hFMOD)
|
|
FMOD_Init();
|
|
|
|
if (!hFMOD)
|
|
{
|
|
gi.dprintf("fmod.dll not loaded, cannot use target_playback.\n");
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
if (!st.noise)
|
|
{
|
|
gi.dprintf("target_playback with no noise set at %s\n", vtos(ent->s.origin));
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
GameDirRelativePath(st.noise, filename, sizeof(filename));
|
|
ent->message = gi.TagMalloc(strlen(filename)+1,TAG_LEVEL);
|
|
strcpy(ent->message, filename);
|
|
|
|
if (ent->fadein < 0)
|
|
ent->fadein = 0;
|
|
if (ent->fadeout < 0)
|
|
ent->fadeout = 0;
|
|
|
|
strlwr(ent->message);
|
|
if ( strstr(ent->message,".mod") ||
|
|
strstr(ent->message,".s3m") ||
|
|
strstr(ent->message,".xm") ||
|
|
strstr(ent->message,".mid") )
|
|
ent->spawnflags |= SF_PLAYBACK_MUSICFILE;
|
|
|
|
if (!ent->volume)
|
|
ent->volume = 1.0;
|
|
ent->volume *= 255;
|
|
if (!ent->count)
|
|
ent->count = -1;
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_3D)
|
|
{
|
|
if (!strstr(ent->message,".mp3"))
|
|
ent->spawnflags |= SF_PLAYBACK_SAMPLE;
|
|
level.num_3D_sounds++;
|
|
|
|
if (st.distance)
|
|
ent->moveinfo.distance = st.distance * 0.025f;
|
|
else
|
|
ent->moveinfo.distance = 5.0f;
|
|
}
|
|
else
|
|
ent->spawnflags &= ~SF_PLAYBACK_SAMPLE;
|
|
|
|
ent->use = Use_Target_Playback;
|
|
ent->die = target_playback_die;
|
|
|
|
if (ent->spawnflags & SF_PLAYBACK_STARTON)
|
|
{
|
|
ent->think = target_playback_delayed_start;
|
|
ent->nextthink = level.time + 1.0;
|
|
}
|
|
|
|
if (ent->movewith)
|
|
ent->movetype = MOVETYPE_PUSH;
|
|
else
|
|
ent->movetype = MOVETYPE_NONE;
|
|
gi.linkentity (ent);
|
|
|
|
ent->stream = NULL;
|
|
ent->channel = -1;
|
|
if (ent->spawnflags & SF_PLAYBACK_SAMPLE)
|
|
{
|
|
// precache sound to prevent stutter when it finally IS played
|
|
int mode;
|
|
if (ent->spawnflags & SF_PLAYBACK_LOOP)
|
|
mode = FSOUND_LOOP_NORMAL;
|
|
else
|
|
mode = FSOUND_LOOP_OFF;
|
|
|
|
if (!(ent->spawnflags & SF_PLAYBACK_3D))
|
|
mode |= FSOUND_2D;
|
|
|
|
ent->stream = (int *)FSOUND_Sample_Load(FSOUND_FREE,ent->message, mode, 0);
|
|
}
|
|
}
|
|
|
|
#ifdef FMOD_FOOTSTEPS
|
|
void ReadTextureSurfaceAssignments ()
|
|
{
|
|
cvar_t *basedir, *gamedir;
|
|
char filename[256];
|
|
FILE *f;
|
|
char line[80];
|
|
|
|
num_texsurfs = 0;
|
|
|
|
basedir = gi.cvar("basedir", "", 0);
|
|
gamedir = gi.cvar("gamedir", "", 0);
|
|
Com_strcpy(filename, sizeof(filename), basedir->string);
|
|
if (strlen(gamedir->string))
|
|
{
|
|
Com_strcat(filename, sizeof(filename), "\\");
|
|
Com_strcat(filename, sizeof(filename), gamedir->string);
|
|
}
|
|
Com_strcat(filename, sizeof(filename), "\\texsurfs.txt");
|
|
f = fopen(filename,"rt");
|
|
if (!f)
|
|
return;
|
|
|
|
while (fgets(line, sizeof(line), f) && num_texsurfs < MAX_TEX_SURF)
|
|
{
|
|
sscanf(line,"%d %s",&tex_surf[num_texsurfs].step_id,tex_surf[num_texsurfs].tex);
|
|
// gi.dprintf("%d %s\n",tex_surf[num_texsurfs].step_id,tex_surf[num_texsurfs].tex);
|
|
num_texsurfs++;
|
|
}
|
|
fclose(f);
|
|
}
|
|
#endif // FMOD_FOOTSTEPS
|
|
|
|
#endif // DISABLE_FMOD
|