/*============================================================================= Name : SoundEvent.c Purpose : Sound Event processor Created 7/24/1997 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include "SoundEventPrivate.h" #include "SoundEvent.h" #include "gun.h" #include "matrix.h" #include "select.h" #include "GenericInterceptor.h" #include "SalCapCorvette.h" #include "render.h" #include "singleplayer.h" #define DIRECTSOUND 1 #define SE_MAX_STRIKECRAFT 10 #define SE_MAX_CAPITALSHIPS 6 #define SE_MAX_MOSHIPS 3 #define SFX_MAX_STRIKEENGINES 5 #define SFX_MAX_CAPENGINES 3 /*============================================================================= Tweaks =============================================================================*/ scriptEntry SoundeventTweaks[] = { makeEntry(SFX_VOL_FACTOR,scriptSetReal32CB), makeEntry(SFX_MAX_ENGINES,scriptSetSdwordCB), makeEntry(SFX_MIN_CAPSHIPS,scriptSetSdwordCB), makeEntry(SFX_AMBIENT_VOLUME,scriptSetSdwordCB), makeEntry(SFX_NIS_MAX_ENGINES,scriptSetSdwordCB), makeEntry(SFX_NIS_MIN_CAPSHIPS,scriptSetSdwordCB), makeEntry(SFX_MAX_ENGINE_RANGE,scriptSetReal32CB), makeEntry(SFX_CAPSHIPS_ALWAYS_ON,scriptSetBool), makeEntry(SFX_MAX_AMBIENT,scriptSetSdwordCB), makeEntry(SFX_FLOAT_VELOCITY,scriptSetReal32CB), makeEntry(SFX_NIS_FLOAT_VELOCITY,scriptSetReal32CB), makeEntry(SFX_MIN_PERCEPTABLE_VOL, scriptSetReal32CB), makeEntry(SFX_HYPERSPACE_VOLUME,scriptSetSwordCB), makeEntry(SFX_DAMAGERATIO_LIGHT,scriptSetReal32CB), makeEntry(SFX_DAMAGERATIO_MEDIUM,scriptSetReal32CB), makeEntry(SFX_DAMAGERATIO_HEAVY,scriptSetReal32CB), makeEntry(SFX_DAMAGERATIO_ENABLE,scriptSetBool), makeEntry(SFX_CARDIOD_FACTOR,scriptSetReal32CB), makeEntry(SFX_CARDIOD_MIN,scriptSetReal32CB), makeEntry(FIGHTER_VELOCITY_LOWPITCH,scriptSetReal32CB), makeEntry(FIGHTER_VELOCITY_HIGHPITCH,scriptSetReal32CB), makeEntry(FIGHTER_VELOCITY_SCALE,scriptSetReal32CB), makeEntry(CORVETTE_VELOCITY_LOWPITCH,scriptSetReal32CB), makeEntry(CORVETTE_VELOCITY_HIGHPITCH,scriptSetReal32CB), makeEntry(CORVETTE_VELOCITY_SCALE,scriptSetReal32CB), makeEntry(FIGHTER_DOPPLER_SCALE,scriptSetReal32CB), makeEntry(FIGHTER_DOPPLER_LOW,scriptSetSdwordCB), makeEntry(FIGHTER_DOPPLER_HIGH,scriptSetSwordCB), makeEntry(FIGHTER_DOPPLER_USEVELOCITY,scriptSetBool), makeEntry(CORVETTE_DOPPLER_SCALE,scriptSetReal32CB), makeEntry(CORVETTE_DOPPLER_LOW,scriptSetSwordCB), makeEntry(CORVETTE_DOPPLER_HIGH,scriptSetSwordCB), makeEntry(CORVETTE_DOPPLER_USEVELOCITY,scriptSetBool), makeEntry(SPEECH_VOL_FACTOR,scriptSetReal32CB), makeEntry(SPEECH_VOL_LOW,scriptSetSwordCB), makeEntry(SPEECH_VOL_MAX,scriptSetSwordCB), makeEntry(SPEECH_NOISE_FACTOR,scriptSetReal32CB), makeEntry(SPEECH_NOISE_LOW,scriptSetReal32CB), makeEntry(SPEECH_NOISE_HIGH,scriptSetReal32CB), makeEntry(SPEECH_FILTER_LOW,scriptSetUdwordCB), makeEntry(SPEECH_FILTER_HIGH,scriptSetUdwordCB), makeEntry(SPEECH_BREAK_THRESHOLD,scriptSetReal32CB), makeEntry(SPEECH_BREAK_RATE_FACTOR,scriptSetReal32CB), makeEntry(SPEECH_BREAK_RATE_LOW,scriptSetUdwordCB), makeEntry(SPEECH_BREAK_RATE_HIGH,scriptSetUdwordCB), makeEntry(SPEECH_BREAK_LENGTH_FACTOR,scriptSetReal32CB), makeEntry(SPEECH_BREAK_LENGTH_LOW,scriptSetUdwordCB), makeEntry(SPEECH_BREAK_LENGTH_HIGH,scriptSetUdwordCB), makeEntry(SPEECH_CAPSHIP_CHATTER_RANGE,scriptSetReal32CB), makeEntry(SPEECH_CAPSHIP_CHATTER_TIME,scriptSetSdwordCB), makeEntry(SPEECH_COMBAT_CHATTER_RANGE,scriptSetReal32CB), makeEntry(SPEECH_COMBAT_CHATTER_TIME,scriptSetSdwordCB), makeEntry(SPEECH_MOSHIP_WARNING_TIME,scriptSetReal32CB), makeEntry(SPEECH_WARNING_TIME,scriptSetReal32CB), makeEntry(SPEECH_DISOBEY_FORCEDATTACK,scriptSetReal32CB), makeEntry(SPEECH_MIN_PERCEPTABLE_VOL,scriptSetReal32CB), makeEntry(SPEECH_AMBIENT_LEVEL,scriptSetReal32CB), makeEntry(SPEECH_AMBIENT_ENABLE,scriptSetBool), makeEntry(SPEECH_STIKEDAMAGE_MULT,scriptSetReal32CB), makeEntry(SPEECH_CAPDAMAGE_MULT,scriptSetReal32CB), makeEntry(SPEECH_SINGLEPLAYER_RATIO, scriptSetReal32CB), makeEntry(SPEECH_STATUS_RATIO, scriptSetReal32CB), makeEntry(SPEECH_CHATTER_RATIO, scriptSetReal32CB), makeEntry(MUSIC_DISTANCE_SILENT,scriptSetReal32CB), makeEntry(MUSIC_DISTANCE_MAX,scriptSetReal32CB), makeEntry(MUSIC_MAXGAME_VOL,scriptSetReal32CB), makeEntry(MUSIC_MINACTIVE_VOL,scriptSetReal32CB), makeEntry(MUSIC_MININACTIVE_VOL,scriptSetReal32CB), makeEntry(MUSIC_SENSORS_VOL,scriptSetReal32CB), makeEntry(MUSIC_MANAGERS_VOL,scriptSetReal32CB), makeEntry(MUSIC_TUTORIAL_VOL,scriptSetReal32CB), makeEntry(MUSIC_FADE_TIME,scriptSetReal32CB), makeEntry(MUSIC_MAXBATTLE_VOL,scriptSetReal32CB), makeEntry(MUSIC_MINBATTLE_VOL,scriptSetReal32CB), makeEntry(RANDOM_AMBIENCE_MINFREQ,scriptSetReal32CB), makeEntry(RANDOM_AMBIENCE_ADDRANDOM,scriptSetSdwordCB), endEntry }; /*============================================================================= Private Data =============================================================================*/ sword soundeventinited = FALSE; ubyte *bankLoadAddress; sdword ambienthandle = SOUND_DEFAULT; bool soundpaused = FALSE; /* new banks */ ubyte *GunBank; ubyte *ShipBank; ubyte *SpecialEffectBank; ubyte *UIBank; /* SFX lookup tables */ SFXLUT *GunEventsLUT; SFXLUT *ShipCmnEventsLUT; SFXLUT *ShipEventsLUT; SFXLUT *DerelictEventsLUT; SFXLUT *SpecEffectEventsLUT; SFXLUT *SpecExpEventsLUT; SFXLUT *SpecHitEventsLUT; SFXLUT *UIEventsLUT; TABLELUT *VolumeLUT; real32 *VolumeFloatLUT; TABLELUT *RangeLUT; real32 *RangeFloatLUT; FREQUENCYLUT *FrequencyLUT; real32 *FreqLUT; real32 DefaultEQ[SOUND_EQ_SIZE]; real32 MasterEQ[SOUND_EQ_SIZE] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; extern HWND ghMainWindow; extern bool nisIsRunning; MCI_OPEN_PARMS MCIOpen; // MCI_OPEN structure real32 cardiod[CARDIOD_POINTS]; real32 volSpeech = 1.0f; real32 volMusic = 1.0f; real32 volSFX = 1.0f; real32 volNIS = 1.0f; bool bVolMusicNoFade = FALSE; bool bActorOn[4] = {TRUE, TRUE, TRUE, TRUE}; bool bCommandsOn = TRUE; bool bStatusOn = TRUE; bool bChatterOn = TRUE; sdword actorFlagsEnabled = (ACTOR_PILOT_FLAG | ACTOR_FLEETCOMMAND_FLAG | ACTOR_FLEETINTEL_FLAG | ACTOR_TRADERS_FLAG | ACTOR_PIRATES2_FLAG | ACTOR_ALLSHIPSENEMY_FLAG | ACTOR_AMBASSADOR_FLAG | ACTOR_NARRATOR_FLAG | ACTOR_DEFECTOR_FLAG | ACTOR_GENERAL_FLAG | ACTOR_EMPEROR_FLAG | ACTOR_KHARSELIM_FLAG); // used for calculating the music volume real32 nearestShipDistance = 0.0f; real32 musicVolFactor = 0.0f; real32 battleMusicVolFactor = 0.0f; bool nearestShipMoving = FALSE; real32 musicInactiveFactor = 0.0f; // used for figuring out which engines to play Ship *strike[SE_MAX_STRIKECRAFT]; Ship *capships[SE_MAX_CAPITALSHIPS]; Ship *moships[SE_MAX_MOSHIPS]; sdword numMoships; extern sdword streamhandle[]; extern sdword speechfilehandle; extern SENTENCELUT *SentenceLUT; sdword SEselectsentence(sdword actor, sdword event, sdword variable, sdword setvariation, sdword **pOffsets, udword *pDuration); void SEinitHandles(void); /*============================================================================= Functions =============================================================================*/ /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ sdword GetPatch(SFXLUT *lut, sdword object, sdword event) { sdword numvars; sdword index; if (lut == NULL) { return (SOUND_ERR); } if (object > lut->numobjects) { return (SOUND_ERR); } index = (object * lut->numevents * (lut->numvariations + 1)) + ((event & SFX_Event_Mask) * (lut->numvariations + 1)); numvars = lut->lookup[index]; if (numvars <= 1) { return (index + 1); } return (index + 1 + (ranRandom(RAN_SoundGameThread) % numvars)); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void SEinitcardiod(void) { sdword i; for (i = 0; i < CARDIOD_POINTS; i++) { cardiod[i] = (1.0f + (real32)cos((CARDIOD_POINTS - i) / PI_UNDER_180)) * SFX_CARDIOD_FACTOR; if (cardiod[i] < SFX_CARDIOD_MIN) { cardiod[i] = SFX_CARDIOD_MIN; } } } /*----------------------------------------------------------------------------- Name : SEupdateNISvol Description : updates the NIS master volume scalar to the maximum of SFX, Speech or Music volumes. Inputs : none Outputs : none Return : void -----------------------------------------------------------------------------*/ void SEupdateNISvol(void) { volNIS = 1.0f; #if 0 if (volSpeech > volMusic) { if (volSpeech > volSFX) { volNIS = volSpeech; } else { volNIS = volSFX; } } else if (volMusic > volSFX) { volNIS = volMusic; } else { volNIS = volSFX; } if (volNIS < 0.5f) { volNIS = 0.5f; } #endif } /*----------------------------------------------------------------------------- Name : SEsetVol Description : ensures that the volume scalar is between 0.0 and 1.0 Inputs : level: this is the level to attempt to set the volume to Outputs : Return : a volume between 0.0 and 1.0 -----------------------------------------------------------------------------*/ real32 SEsetVol(real32 level) { real32 vol; if ((level >= 0.0f) && (level <= 1.0f)) { vol = level; } else if (level < 0.0f) { vol = 0.0f; } else if (level > 1.0f) { vol = 1.0f; } return (vol); } /*----------------------------------------------------------------------------- Name : soundEventGetVolume Description : returns the current volume settings Inputs : 3 pointers to hold the current volume settings Outputs : sfxvol: current volume for sound effects speechvol: current volume for the speech musicvol: current volume for the music Return : void -----------------------------------------------------------------------------*/ void soundEventGetVolume(real32 *sfxvol, real32 *speechvol, real32 *musicvol) { *sfxvol = volSFX; *speechvol = volSpeech; *musicvol = volMusic; } /*----------------------------------------------------------------------------- Name : soundEventSFXVol Description : sets the current sound effects volume, this function should only be called in the NIS or animatic code since it scales the input level by the NIS volume scalar. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventSFXVol(real32 level) { volSFX = SEsetVol(level) * volNIS; } /*----------------------------------------------------------------------------- Name : soundEventSFXMasterVol Description : sets the current sound effects master volume, also resets the NIS volume scalar. This should be called by the front end. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventSFXMasterVol(real32 level) { volSFX = SEsetVol(level); SEupdateNISvol(); } /*----------------------------------------------------------------------------- Name : soundEventSpeechVol Description : sets the current speech volume, this function should only be called in the NIS or animatic code since it scales the input level by the NIS volume scalar. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventSpeechVol(real32 level) { volSpeech = SEsetVol(level) * volNIS; } /*----------------------------------------------------------------------------- Name : soundEventSpeechMasterVol Description : sets the current speech master volume, also resets the NIS volume scalar. This should be called by the front end. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventSpeechMasterVol(real32 level) { volSpeech = SEsetVol(level); SEupdateNISvol(); } /*----------------------------------------------------------------------------- Name : soundEventMusicVol Description : sets the current music volume, this function should only be called in the NIS or animatic code since it scales the input level by the NIS volume scalar. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventMusicVol(real32 level) { volMusic = SEsetVol(level * volNIS); } /*----------------------------------------------------------------------------- Name : soundEventMusicMasterVol Description : sets the current music master volume, also resets the NIS volume scalar. This should be called by the front end. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventMusicMasterVol(real32 level) { volMusic = SEsetVol(level); SEupdateNISvol(); } /*----------------------------------------------------------------------------- Name : soundEventMusicVolNOW Description : sets the current music volume and ignores the volume fading code so the volume change happens immediatly. This function should only be called in the NIS or animatic code since it scales the input level by the NIS volume scalar. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventMusicVolNOW(real32 level) { soundEventMusicVol(level); bVolMusicNoFade = TRUE; } /*----------------------------------------------------------------------------- Name : soundEventMusicMasterVolNOW Description : sets the current music master volume, also resets the NIS volume scalar. This ignores the volume fading code and sets the volume immediatley. This should be called by the front end. Inputs : level: volume to attempt to set Outputs : none Return : void -----------------------------------------------------------------------------*/ void soundEventMusicMasterVolNOW(real32 level) { volMusic = SEsetVol(level); bVolMusicNoFade = TRUE; SEupdateNISvol(); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventMasterEQ(real32 *pmasterEQ) { sdword i; for (i = 0; i < SOUND_EQ_SIZE; i++) { MasterEQ[i] = *pmasterEQ++; } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventSetActor(sdword actornum, bool bOn) { if ((actornum > 0) && (actornum < 4)) { bActorOn[actornum] = bOn; } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventVocalSettings(bool bCommands, bool bStatus, bool bChatter) { bCommandsOn = bCommands; bStatusOn = bStatus; bChatterOn = bChatter; } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventHearActor(sdword actornum) { udword duration; sdword *phraseoffsets; if ((actornum > 0) && (actornum < 4)) { if (SEselectsentence(actornum, (COMM_Selection & SPEECH_EVENT_MASK), 0, 0, &phraseoffsets, &duration) > 0) { soundstreamqueuePatch(streamhandle[actornum], speechfilehandle, *phraseoffsets++, SOUND_FLAGS_QUEUESTREAM, (sword)(SOUND_VOL_MAX * volSpeech), SOUND_PAN_CENTER, SOUND_MONO, SentenceLUT->compbitrate[actornum], NULL, NULL, NULL, NULL, 0, 0.0f, 0.0f, actornum, COMM_Selection, FALSE); } } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventSetActorFlag(sdword actorflag, bool bOn) { if (bOn) { bitSet(actorFlagsEnabled, actorflag); } else { bitClear(actorFlagsEnabled, actorflag); } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void SEprecalcVolTables(void) { sdword i, j, index; /* do some precalculations on the volume and range tables, saves a divide, compare, 2 [] and 2 subtractions for every volume update */ for (j = 0; j < (VolumeLUT->rows * VolumeLUT->columns); j += VolumeLUT->columns) { RangeFloatLUT[j] = 1.0f / (real32)RangeLUT->lookup[j]; VolumeFloatLUT[j] = (real32)(SOUND_VOL_MAX - VolumeLUT->lookup[j]); for (i = 1; i < RangeLUT->columns; i++) { VolumeFloatLUT[j+i] = (real32)(VolumeLUT->lookup[j+i-1] - VolumeLUT->lookup[j+i]); RangeFloatLUT[j+i] = 1.0f / (real32)(RangeLUT->lookup[j+i] - RangeLUT->lookup[j+i-1]); } } /* do some precalcs on the Frequency table, saves a compare, [], addition and 2 subtractions for every SEequalize */ for (j = 0; j < FrequencyLUT->columns; j++) { FreqLUT[j] = DefaultEQ[j] - FrequencyLUT->lookup[j]; for (i = 1; i < FrequencyLUT->rows; i++) { index = i * FrequencyLUT->columns + j; FreqLUT[index] = FrequencyLUT->lookup[(i-1) * FrequencyLUT->columns + j] - FrequencyLUT->lookup[index]; } } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : -----------------------------------------------------------------------------*/ void soundEventInit(void) { #if SOUND #if DIRECTSOUND char loadfile[100]; sdword i, size; if (!enableSFX && !enableSpeech) { return; } if (soundinit(ghMainWindow, useWaveout) == SOUND_ERR) { enableSFX = FALSE; enableSpeech = FALSE; } for (i = 0; i < SOUND_EQ_SIZE; i++) { DefaultEQ[i] = 1.0f; } // used for calculating music volume in the game musicVolFactor = (MUSIC_MAXGAME_VOL - MUSIC_MINACTIVE_VOL) / (MUSIC_DISTANCE_MAX - MUSIC_DISTANCE_SILENT); musicInactiveFactor = (MUSIC_MAXGAME_VOL - MUSIC_MININACTIVE_VOL) / (MUSIC_DISTANCE_MAX - MUSIC_DISTANCE_SILENT); battleMusicVolFactor = (MUSIC_MAXBATTLE_VOL - MUSIC_MINBATTLE_VOL) / (MUSIC_DISTANCE_MAX - MUSIC_DISTANCE_SILENT); /* LOAD volume curves */ strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Volume.lut"); size = fileLoadAlloc(loadfile, &VolumeLUT, NonVolatile); VolumeFloatLUT = memAlloc(size, "Volume Table", NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Range.lut"); size = fileLoadAlloc(loadfile, &RangeLUT, NonVolatile); RangeFloatLUT = memAlloc(size, "Range Table", NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Frequency.lut"); size = fileLoadAlloc(loadfile, &FrequencyLUT, NonVolatile); FreqLUT = memAlloc(size, "Frequency Table", NonVolatile); /* do some pre-calculations on the volume, range and frequency tables */ SEprecalcVolTables(); /* initialze the cardiod lookup table */ SEinitcardiod(); SEinitHandles(); if (enableSFX) { SEloadbank(); } #if SPEECH if (enableSpeech) { if (speechEventInit() != SOUND_OK) { enableSpeech = FALSE; } } #endif soundeventinited = TRUE; #endif #endif } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventClose(void) { #if SOUND #if DIRECTSOUND if (!enableSFX && !enableSpeech) { return; } soundrestore(); if (enableSFX || enableSpeech) { memFree(VolumeLUT); memFree(RangeLUT); memFree(FrequencyLUT); memFree(VolumeFloatLUT); memFree(RangeFloatLUT); memFree(FreqLUT); } if (enableSFX) { memFree(GunEventsLUT); memFree(ShipCmnEventsLUT); memFree(ShipEventsLUT); memFree(DerelictEventsLUT); // memFree(SpecEffectEventsLUT); memFree(SpecExpEventsLUT); memFree(SpecHitEventsLUT); memFree(UIEventsLUT); memFree(GunBank); memFree(ShipBank); memFree(SpecialEffectBank); memFree(UIBank); } if (enableSpeech) { speechEventClose(); } #endif #endif } void soundEventShutdown(void) { if (enableSFX || enableSpeech) soundclose(); // sounddeactivate(TRUE); // soundrestore(); } void soundEventRestart(void) { if (enableSFX || enableSpeech) { soundreinit(ghMainWindow); soundEventPlayMusic(SOUND_FRONTEND_TRACK); } // sounddeactivate(FALSE); // if (soundinit(ghMainWindow, useWaveout) == SOUND_ERR) // { // enableSFX = FALSE; // enableSpeech = FALSE; // } // soundpause(FALSE); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventReset(void) { soundstopall(SOUND_FADE_STOPALL); } void soundEventStopSFX(real32 fadetime) { Ship *ship; Derelict *pDerelict; Node *objnode = universe.RenderList.tail; if (enableSFX) { soundstopallSFX(fadetime, FALSE); while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); if (ship->objtype == OBJ_DerelictType) { pDerelict = (Derelict *)ship; soundEventDerelictRemove(pDerelict); } else if (ship->objtype == OBJ_ShipType) { soundEventShipRemove(ship); } objnode = objnode->prev; } } } void soundEventPause(bool bPause) { if (!soundeventinited) { return; } if (bPause != soundpaused) { soundpaused = bPause; soundpause(bPause); if (bPause) { /* clean up the speech queue */ speechEventCleanup(); } } } void soundEventReloadVolumes(void) { void *tempLUT; char loadfile[100]; if (!enableSFX) { return; } /* LOAD volume curves */ strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Volume.lut"); fileLoadAlloc(loadfile, &tempLUT, NonVolatile); memFree(VolumeLUT); VolumeLUT = (TABLELUT *)tempLUT; strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Range.lut"); fileLoadAlloc(loadfile, &tempLUT, NonVolatile); memFree(RangeLUT); RangeLUT = (TABLELUT *)tempLUT; strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Frequency.lut"); fileLoadAlloc(loadfile, &tempLUT, NonVolatile); memFree(FrequencyLUT); FrequencyLUT = (FREQUENCYLUT *)tempLUT; /* do some pre-calculations on the volume, range and frequency tables */ SEprecalcVolTables(); } #if 0 void soundEventUpdateNew(void) { if (!soundeventinited || (objnode == NULL)) { return; } // if (nisIsRunning) // { // return; // } while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); if (ship->objtype != OBJ_ShipType) { goto nextship; } if (ship->shiptype >= Drone) { goto nextship; } shipclass = ship->staticinfo->shipclass; nextship: objnode = objnode->prev; } soundupdate(); } #endif #if 1 /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventUpdate(void) { #if SOUND Node *objnode = universe.RenderList.tail; Ship *ship; ShipClass shipclass; sword vol; sword pan; real32 dist; real32 velocity; real32 velratio = 1.0f; udword iscapship; sdword numships = 0, numcapships = 0, numabmient = 0; static sdword numbattlechatter = 0; sword shipangle = 0; static real32 tempEQ[SOUND_EQ_SIZE]; GunInfo *gunInfo; sdword i; Gun *gun; bool specialon; bool ambienton; CloakGeneratorSpec *CGspec; GravWellGeneratorSpec *GWspec; CommandToDo *command; Derelict *pDerelict; real32 damageratio = 1.0f; sdword ambient; ShipSinglePlayerGameInfo *shipSinglePlayerGameInfo; static real32 strikescale = 5.0f; bool damageOn = FALSE; bool noAmbient = FALSE; if (!soundeventinited || soundpaused) { return; } // update the music volume musicEventUpdateVolume(); if (smSensorsActive || !mrRenderMainScreen) { return; } nearestShipDistance = REALlyBig; nearestShipMoving = FALSE; while (objnode != NULL) { noAmbient = FALSE; ship = (Ship *)listGetStructOfNode(objnode); // only want to do this if sound fx are on if (!enableSFX) { break; } // deal with derelicts first if (ship->objtype == OBJ_DerelictType) { // play the derelict ambience here pDerelict = (Derelict *)ship; dist = (real32)fsqrt(pDerelict->cameraDistanceSquared); if (dist < nearestShipDistance) { nearestShipDistance = dist; } if (SEinrange(DerelictAmbience, dist)) { vol = SEequalize(DerelictAmbience, dist, tempEQ); pan = getPanAngle(pDerelict->posinfo.position, pDerelict->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); if ((pDerelict->ambientSoundHandle == SOUND_NOTINITED) || soundover(pDerelict->ambientSoundHandle)) { pDerelict->ambientSoundHandle = splayEPRV(ShipBank, DerelictEventsLUT->lookup[GetPatch(DerelictEventsLUT, pDerelict->derelicttype, Derelict_Ambience)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); } else { soundvolume(pDerelict->ambientSoundHandle, vol); soundpan(pDerelict->ambientSoundHandle, pan); soundequalize(pDerelict->ambientSoundHandle, tempEQ); } // now we have the random ambience if ((pDerelict->randomSoundHandle == SOUND_NOTINITED) || soundover(pDerelict->randomSoundHandle)) { if (universe.totaltimeelapsed > pDerelict->nextRandomTime) { pDerelict->randomSoundHandle = splayEPRV(ShipBank, DerelictEventsLUT->lookup[GetPatch(DerelictEventsLUT, pDerelict->derelicttype, Derelict_RandomAmbience)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); if (pDerelict->randomSoundHandle == SOUND_NOTINITED) { pDerelict->nextRandomTime = universe.totaltimeelapsed + RANDOM_AMBIENCE_MINFREQ; } } } else { if (soundover(pDerelict->randomSoundHandle)) { pDerelict->randomSoundHandle = SOUND_NOTINITED; pDerelict->nextRandomTime = universe.totaltimeelapsed + RANDOM_AMBIENCE_MINFREQ + ((real32)(ranRandom(RAN_SoundGameThread) % RANDOM_AMBIENCE_ADDRANDOM) / 100.0f); } else { soundvolume(pDerelict->randomSoundHandle, vol); soundpan(pDerelict->randomSoundHandle, pan); soundequalize(pDerelict->randomSoundHandle, tempEQ); } } } else { SEstopsoundhandle(&(pDerelict->ambientSoundHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(pDerelict->randomSoundHandle), SOUND_FADE_STOPNOW); } goto nextship; } else if (ship->objtype != OBJ_ShipType) { // if this wasn't a Derelict or a Ship then skip it goto nextship; } // ok, now we're into the SHIP stuff shipclass = ship->staticinfo->shipclass; dist = (real32)fsqrt(ship->cameraDistanceSquared); // a little hack here so that these ships have reasonable volume curves if (ship->shiptype == MiningBase) { shipclass = CLASS_Mothership; } else if (ship->shiptype == ResearchStation) { shipclass = CLASS_Carrier; } // need to do this for the ships that aren't playing sounds if (shipclass == CLASS_Fighter) { ship->soundevent.coverage = rndComputeOverlap(ship, 5.0f); } else if (shipclass == CLASS_Corvette) { ship->soundevent.coverage = rndComputeOverlap(ship, 2.2f); } else { // all other ships don't have velocity ratio or have the coverage affect the engine volume ship->soundevent.coverage = rndComputeOverlap(ship, 0.4f); } // have we reached the maximum number of sounds for these types of ships? if (((numships >= SFX_MAX_STRIKEENGINES) && ((shipclass == CLASS_Fighter) || (shipclass == CLASS_Corvette))) || ((numcapships >= SFX_MAX_CAPENGINES) && ((shipclass != CLASS_Fighter) || (shipclass != CLASS_Corvette)))) { if ((shipclass != CLASS_Mothership) || (universe.curPlayerIndex != ship->playerowner->playerIndex)) { SEstopengine(ship, TRUE); SEstopsoundhandle(&(ship->soundevent.specialHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.ambientHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.damageHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.randomHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.gunHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.hyperspaceHandle), SOUND_FADE_STOPNOW); goto playloopingguns; // this is only the gun firing sounds } } // has this ship just exploded? if (ship->soundevent.engineHandle == SOUND_SHIP_EXPLODED) { soundEventShipRemove(ship); goto nextship; } // is this ship even in range to be heard? if (!SEinrange(shipclass, dist)) { // then shut the engind down if its playing SEstopengine(ship, TRUE); goto othersounds; } // need to keep track of the number of ships if ((shipclass != CLASS_Mothership) || (universe.curPlayerIndex != ship->playerowner->playerIndex)) { numships++; if (isCapitalShip(ship)) { numcapships++; } } // figure out all the variables pan = getPanAngle(ship->enginePosition, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); vol = SEequalize(shipclass, dist, tempEQ); shipangle = SEgetAngleToCamera(ship); velocity = fsqrt(vecMagnitudeSquared(ship->posinfo.velocity)); // need this for setting the music volume if (dist < nearestShipDistance) { nearestShipDistance = dist; if (velocity > SFX_FLOAT_VELOCITY) { nearestShipMoving = TRUE; } } // figure out the coverage for this ship (how much it is visibly overlapped on screen) // also figure out the volume scalar for the coverage and the velocity to max velocity ratio if (shipclass == CLASS_Fighter) { vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); velratio = FIGHTER_VELOCITY_LOWPITCH; + (velocity / ship->staticinfo->staticheader.maxvelocity * FIGHTER_VELOCITY_SCALE); if (velratio > FIGHTER_VELOCITY_HIGHPITCH) { velratio = FIGHTER_VELOCITY_HIGHPITCH; } } else if (shipclass == CLASS_Corvette) { vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); velratio = CORVETTE_VELOCITY_LOWPITCH; + (velocity / ship->staticinfo->staticheader.maxvelocity * CORVETTE_VELOCITY_SCALE); if (velratio > CORVETTE_VELOCITY_HIGHPITCH) { velratio = CORVETTE_VELOCITY_HIGHPITCH; } } else { // all other ships don't have velocity ratio or have the coverage affect the engine volume ship->soundevent.coverage = rndComputeOverlap(ship, 0.4f); } // need to figure out if this ship is actually doing something and not just drifting if (ship->soundevent.engineState != SOUND_STARTING) { if ((shipclass == CLASS_Fighter) || (shipclass == CLASS_Corvette)) { // if this ship isn't actually doing anything, then don't turn on the engines command = getShipAndItsCommand(&universe.mainCommandLayer, ship); if (command != NULL) { if ((command->ordertype.order == COMMAND_NULL) || (command->ordertype.order == COMMAND_MP_HYPERSPACEING)) { if (velocity <= 100.0f) { vol = 0; } } else if ((command->ordertype.order == COMMAND_MILITARYPARADE) && (velocity <= 2.0f * SFX_FLOAT_VELOCITY)) { vol = 0; } else { if (nisIsRunning && (velocity <= SFX_NIS_FLOAT_VELOCITY)) { vol = 0; } else if (velocity <= SFX_FLOAT_VELOCITY) { vol = 0; } } } else { vol = 0; } } else { // cap ships should always play unless they're moving if (velocity <= 0.0f) { vol = 0; } } } // ENGINE SOUNDS if (vol <= SOUND_VOL_MIN) { if (ship->soundevent.engineHandle > SOUND_NOTINITED) { SEstopengine(ship, TRUE); } goto othersounds; } else { if ((ship->soundevent.engineHandle == SOUND_NOTINITED) || soundover(ship->soundevent.engineHandle)) { // start the engine sound if (velratio > 1.0f) { if (shipclass == CLASS_Corvette) { ship->soundevent.engineHandle = splayFPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, velratio, pan, SOUND_PRIORITY_MAX - 1, vol, TRUE, TRUE, FALSE); } else if (shipclass == CLASS_Fighter) { ship->soundevent.engineHandle = splayFPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, velratio, pan, SOUND_PRIORITY_MAX - 2, vol, TRUE, TRUE, FALSE); } } else { ship->soundevent.engineHandle = splayEPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } } else { if ((ship->soundevent.engineState == SOUND_STARTING) && (velocity > SFX_FLOAT_VELOCITY)) { ship->soundevent.engineState = SOUND_PLAYING; } soundvolume(ship->soundevent.engineHandle, vol); soundpan(ship->soundevent.engineHandle, pan); if (velratio > 1.0f) { soundfrequency(ship->soundevent.engineHandle, velratio); } soundequalize(ship->soundevent.engineHandle, tempEQ); } if (shipclass == CLASS_Fighter) { if (FIGHTER_DOPPLER_USEVELOCITY) { soundshipheading(ship->soundevent.engineHandle, shipangle, FIGHTER_DOPPLER_HIGH, FIGHTER_DOPPLER_LOW, velratio, FIGHTER_DOPPLER_SCALE); } else { soundshipheading(ship->soundevent.engineHandle, shipangle, FIGHTER_DOPPLER_HIGH, FIGHTER_DOPPLER_LOW, 1.0f, FIGHTER_DOPPLER_SCALE); } } if (shipclass == CLASS_Corvette) { if (CORVETTE_DOPPLER_USEVELOCITY) { soundshipheading(ship->soundevent.engineHandle, shipangle, CORVETTE_DOPPLER_HIGH, CORVETTE_DOPPLER_LOW, velratio, CORVETTE_DOPPLER_SCALE); } else { soundshipheading(ship->soundevent.engineHandle, shipangle, CORVETTE_DOPPLER_HIGH, CORVETTE_DOPPLER_LOW, 1.0f, CORVETTE_DOPPLER_SCALE); } } } othersounds: // now we deal with the special sounds, ambients, damage ambients and random ambients if (!SEinrange(shipclass + AMBIENT_OFFSET, dist)) { SEstopsoundhandle(&(ship->soundevent.specialHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.ambientHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.damageHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.randomHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.hyperspaceHandle), SOUND_FADE_STOPNOW); goto playgimbles; } vol = SEequalize(shipclass + AMBIENT_OFFSET, dist, tempEQ); vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); specialon = FALSE; ambienton = TRUE; switch (ship->shiptype) { case CloakedFighter: break; case CloakGenerator: CGspec = (CloakGeneratorSpec *)ship->ShipSpecifics; if (CGspec->CloakOn && (universe.curPlayerIndex == ship->playerowner->playerIndex)) { specialon = TRUE; ambienton = FALSE; if ((ship->soundevent.specialHandle == SOUND_NOTINITED) || soundover(ship->soundevent.specialHandle)) { ship->soundevent.specialHandle = splayEPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_CloakingLoop)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } } break; case GravWellGenerator: GWspec = (GravWellGeneratorSpec *)ship->ShipSpecifics; if (GWspec->GravFieldOn) { if (SEinrange(Spec_GravWellGeneratorOn, dist)) { specialon = TRUE; ambienton = FALSE; vol = SEequalize(Spec_GravWellGeneratorOn, dist, tempEQ); if ((ship->soundevent.specialHandle == SOUND_NOTINITED) || soundover(ship->soundevent.specialHandle)) { ship->soundevent.specialHandle = splayEPRV(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_GravWellGenerator)], tempEQ, pan, SOUND_PRIORITY_MAX, vol); } } } break; case ResourceCollector: if ((ship->rceffect != NULL) && ((ship->soundevent.specialHandle == SOUND_NOTINITED) || soundover(ship->soundevent.specialHandle))) { command = getShipAndItsCommand(&universe.mainCommandLayer, ship); if (command != NULL) { if (command->ordertype.order == COMMAND_COLLECTRESOURCE) { if (command->collect.resource->objtype == OBJ_AsteroidType) { ship->soundevent.specialHandle = splayEPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_ResourceAsteroid)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } else { ship->soundevent.specialHandle = splayEPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_ResourceDustCloud)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } specialon = TRUE; ambienton = FALSE; } } } else if (ship->rceffect != NULL) { specialon = TRUE; ambienton = FALSE; } break; case SalCapCorvette: // is the tractor beam on? if ((((SalCapCorvetteSpec *)ship->ShipSpecifics)->tractorBeam == TRUE) && (SEinrange(shipclass, dist))) { // is the sound for it playing? if ((ship->soundevent.specialHandle == SOUND_NOTINITED) || soundover(ship->soundevent.specialHandle)) { ship->soundevent.specialHandle = splayEPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_Salvage)], tempEQ, pan, SOUND_PRIORITY_MAX, (sword)(vol * (1.0f - ship->soundevent.coverage)), TRUE); } specialon = TRUE; ambienton = FALSE; } break; case AdvanceSupportFrigate: case RepairCorvette: if (ship->rceffect != NULL) { if ((ship->soundevent.specialHandle == SOUND_NOTINITED) || soundover(ship->soundevent.specialHandle)) { ship->soundevent.specialHandle = splayEPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_RepairLoop)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } specialon = TRUE; ambienton = FALSE; } break; } // deal with the special sound if ((specialon) && (ship->soundevent.specialHandle != SOUND_NOTINITED)) { soundvolume(ship->soundevent.specialHandle, vol); soundpan(ship->soundevent.specialHandle, pan); soundequalize(ship->soundevent.specialHandle, tempEQ); } else if (ship->soundevent.specialHandle > SOUND_NOTINITED) { SEstopsoundhandle(&(ship->soundevent.specialHandle), SOUND_FADE_STOPTIME); } // DAMAGE AMBIENT if (ambienton) { ambient = ShipCmn_Ambient; // if there is already a damage loop playing then stop this one if (damageOn && (ship->soundevent.damageHandle != SOUND_NOTINITED)) { SEstopsoundhandle(&(ship->soundevent.damageHandle), SOUND_FADE_STOPTIME); } // take care of the damage loop if ((ship->soundevent.damageHandle == SOUND_NOTINITED) || soundover(ship->soundevent.damageHandle)) { if (SFX_DAMAGERATIO_ENABLE && !damageOn) { // if the damage ambient stuff is enabled damageratio = (real32)ship->health * (real32)((ShipStaticInfo *)ship->staticinfo)->oneOverMaxHealth; if (damageratio < SFX_DAMAGERATIO_LIGHT) { damageOn = TRUE; if (damageratio > SFX_DAMAGERATIO_MEDIUM) { ambient = ShipCmn_LightDamage; } else if (damageratio > SFX_DAMAGERATIO_HEAVY) { ambient = ShipCmn_MediumDamage; } else { ambient = ShipCmn_HeavyDamage; } // only play if a damage should be on ship->soundevent.damageHandle = splayEPRV(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ambient)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); } } ship->soundevent.lastAmbient = ambient; } else { if (SFX_DAMAGERATIO_ENABLE && !damageOn) { // this is the closest damaged ship damageratio = (real32)ship->health * (real32)((ShipStaticInfo *)ship->staticinfo)->oneOverMaxHealth; if (damageratio < SFX_DAMAGERATIO_LIGHT) { damageOn = TRUE; if (damageratio > SFX_DAMAGERATIO_MEDIUM) { ambient = ShipCmn_LightDamage; } else if (damageratio > SFX_DAMAGERATIO_HEAVY) { ambient = ShipCmn_MediumDamage; } else { ambient = ShipCmn_HeavyDamage; } if (ship->soundevent.lastAmbient != ambient) { if (ship->soundevent.lastAmbient != ShipCmn_Ambient) { // fade out the old, start the new soundstop(ship->soundevent.damageHandle, 0.2f); } ship->soundevent.damageHandle = splayEPRV(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ambient)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); ship->soundevent.lastAmbient = ambient; } // set the parameters for the damage sound soundvolume(ship->soundevent.damageHandle, vol); soundpan(ship->soundevent.damageHandle, pan); soundequalize(ship->soundevent.damageHandle, tempEQ); } } } // take care of the ambient loop if ((ship->soundevent.ambientHandle == SOUND_NOTINITED) || soundover(ship->soundevent.ambientHandle)) { // play the ambient loop regardless ship->soundevent.ambientHandle = splayEPRV(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Ambient)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); } else { // set the parameters for the ambient soundvolume(ship->soundevent.ambientHandle, vol); soundpan(ship->soundevent.ambientHandle, pan); soundequalize(ship->soundevent.ambientHandle, tempEQ); } // now we have the random ambience if (ship->soundevent.randomHandle == SOUND_NOTINITED) { if (universe.totaltimeelapsed > ship->soundevent.nextRandom) { ship->soundevent.randomHandle = splayEPRV(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_RandomAmbient)], tempEQ, pan, SOUND_PRIORITY_LOW, vol); if (ship->soundevent.randomHandle == SOUND_NOTINITED) { ship->soundevent.nextRandom = universe.totaltimeelapsed + RANDOM_AMBIENCE_MINFREQ; } } } else { if (soundover(ship->soundevent.randomHandle)) { // this puppy is done, get ready for the next ship->soundevent.randomHandle = SOUND_NOTINITED; ship->soundevent.nextRandom = universe.totaltimeelapsed + RANDOM_AMBIENCE_MINFREQ + ((real32)(ranRandom(RAN_SoundGameThread) % RANDOM_AMBIENCE_ADDRANDOM) / 100.0f); } else { soundvolume(ship->soundevent.randomHandle, vol); soundpan(ship->soundevent.randomHandle, pan); soundequalize(ship->soundevent.randomHandle, tempEQ); } } } else { // out of range so turn these puppies off SEstopsoundhandle(&(ship->soundevent.ambientHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.randomHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.damageHandle), SOUND_FADE_STOPNOW); } // HYPERSPACING shipSinglePlayerGameInfo = ship->shipSinglePlayerGameInfo; if (!singlePlayerGame || (singlePlayerGame && (ship->playerowner != universe.curPlayerPtr))) { if (shipSinglePlayerGameInfo->hsState == HS_SLICING_INTO) { if ((ship->soundevent.hyperspaceHandle == SOUND_NOTINITED) || soundover(ship->soundevent.hyperspaceHandle)) { ship->soundevent.hyperspaceHandle = splayFPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_Hyperdrive)], tempEQ, (real32)SOUND_DEFAULT, pan, SOUND_PRIORITY_MAX, vol, TRUE, TRUE, FALSE); } else { soundvolume(ship->soundevent.hyperspaceHandle, vol); soundpan(ship->soundevent.hyperspaceHandle, pan); soundequalize(ship->soundevent.hyperspaceHandle, tempEQ); } } else if (shipSinglePlayerGameInfo->hsState == HS_SLICING_OUTOF) { if ((ship->soundevent.hyperspaceHandle == SOUND_NOTINITED) || soundover(ship->soundevent.hyperspaceHandle)) { ship->soundevent.hyperspaceHandle = splayFPRVL(ShipBank, ShipEventsLUT->lookup[GetPatch(ShipEventsLUT, 0, Ship_HyperdriveOff)], tempEQ, (real32)SOUND_DEFAULT, pan, SOUND_PRIORITY_MAX, vol, TRUE, TRUE, FALSE); } else { soundvolume(ship->soundevent.hyperspaceHandle, vol); soundpan(ship->soundevent.hyperspaceHandle, pan); soundequalize(ship->soundevent.hyperspaceHandle, tempEQ); } } } playgimbles: // NEW Gimble stuff if (ship->gunInfo != NULL) { gunInfo = ship->gunInfo; if (SEinrange(ship->gunInfo->guns[0].gunstatic->gunsoundtype + GUNMOVE_OFFSET, dist)) { // check to see if they are playing vol = SEequalize(ship->gunInfo->guns[0].gunstatic->gunsoundtype + GUNMOVE_OFFSET, dist, tempEQ); vol = (sword)(vol * (1.0f - ship->soundevent.coverage)); for (i = 0; i < gunInfo->numGuns; i++) { gun = &gunInfo->guns[i]; if (((gun->gimblehandle != SOUND_NOTINITED) && !soundover(gun->gimblehandle)) && (vol > SOUND_VOL_MIN)) { soundvolume(gun->gimblehandle, vol); soundpan(gun->gimblehandle, pan); soundequalize(gun->gimblehandle, tempEQ); } } } else { // out of range so see if we need to shut off the gimbles for (i = 0; i < gunInfo->numGuns; i++) { gun = &gunInfo->guns[i]; if (gun->gimblehandle != SOUND_NOTINITED) { SEstopsoundhandle(&(gun->gimblehandle), SOUND_FADE_STOPNOW); } } } } playloopingguns: // get the pan from the center of the ship pan = getPanAngle(ship->posinfo.position, ship->staticinfo->staticheader.staticCollInfo.approxcollspheresize, dist); // check the burst fire guns if (ship->soundevent.burstfiring) { if (SEinrange(ship->gunInfo->guns[0].gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist)) { if (ship->aistateattack == STATE_BREAK) { soundEventBurstStop(ship, &ship->gunInfo->guns[0]); } else { vol = SEequalize(ship->gunInfo->guns[0].gunstatic->gunsoundtype + GUNSHOT_OFFSET, dist, tempEQ); vol = (sdword)(vol * (1.0f - (ship->soundevent.coverage * 0.5))); if (((ship->soundevent.burstHandle == SOUND_NOTINITED) || // do I think the sound is done soundover(ship->soundevent.burstHandle)) && // is the sound actually not playing (vol > SOUND_VOL_MIN)) // is the volume > 0 { ship->soundevent.burstHandle = splayEPRVL(GunBank, GunEventsLUT->lookup[GetPatch(GunEventsLUT, ship->gunInfo->guns[0].gunstatic->gunsoundtype, Gun_WeaponFireLooped)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } else { soundvolume(ship->soundevent.burstHandle, vol); soundpan(ship->soundevent.burstHandle, pan); soundequalize(ship->soundevent.burstHandle, tempEQ); } } } else { SEstopsoundhandle(&(ship->soundevent.burstHandle), SOUND_FADE_STOPNOW); } } // do the Ion Carving code here nextship: objnode = objnode->prev; } #endif } #else void soundEventUpdate(void) { Ship *ship; if (!soundeventinited || soundpaused) { return; } // update the music volume musicEventUpdateVolume(); nearestShipDistance = REALlyBig; nearestShipMoving = FALSE; /* update ship ranges */ SEupdateShipRange(); /* update engine sounds */ for (i = 0; i < numMoships; i++) { ship = moships[i]; /* EQ this puppy */ SEeq(ship->staticinfo->shipclass, ship->soundevent.distance, tempEQ); if (ship->soundevent.engineHandle == SOUND_NOTINITED) { /* start the engine sound */ ship->soundevent.engineHandle = splayEPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, ship->soundevent.pan, SOUND_PRIORITY_MAX, ship->soundevent.engineVol, TRUE); } else { if (ship->soundevent.engineState == SOUND_STARTING) { if (vecMagnitudeSquared(ship->posinfo.velocity) > SFX_FLOAT_VELOCITYSQR) { ship->soundevent.engineState = SOUND_PLAYING; } } /* set volume */ soundvolume(ship->soundevent.engineHandle, ship->soundevent.engineVol); /* set pan */ soundpan(ship->soundevent.engineHandle, ship->soundevent.pan); /* set equalization */ soundequalize(ship->soundevent.engineHandle, tempEQ); } } for (i = 0; i < SFX_MAX_CAPENGINES; i++) { ship = capships[i]; if (ship != NULL) { /* EQ this puppy */ SEeq(ship->staticinfo->shipclass, ship->soundevent.distance, tempEQ); if (ship->soundevent.engineHandle == SOUND_NOTINITED) { /* start the engine sound */ ship->soundevent.engineHandle = splayEPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, ship->soundevent.pan, SOUND_PRIORITY_MAX, ship->soundevent.engineVol, TRUE); } else { if (ship->soundevent.engineState == SOUND_STARTING) { if (vecMagnitudeSquared(ship->posinfo.velocity) > SFX_FLOAT_VELOCITYSQR) { ship->soundevent.engineState = SOUND_PLAYING; } } /* set volume */ soundvolume(ship->soundevent.engineHandle, ship->soundevent.engineVol); /* set pan */ soundpan(ship->soundevent.engineHandle, ship->soundevent.pan); /* set equalization */ soundequalize(ship->soundevent.engineHandle, tempEQ); } } } for (i = 0; i < SFX_MAX_STRIKEENGINES; i++) { ship = strike[i]; if (ship != NULL) { /* EQ this puppy */ SEeq(ship->staticinfo->shipclass, ship->soundevent.distance, tempEQ); if (ship->soundevent.engineHandle == SOUND_NOTINITED) { /* start the engine sound */ ship->soundevent.engineHandle = splayEPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, ship->soundevent.pan, SOUND_PRIORITY_MAX, ship->soundevent.engineVol, TRUE); } else { if (ship->soundevent.engineState == SOUND_STARTING) { if (vecMagnitudeSquared(ship->posinfo.velocity) > SFX_FLOAT_VELOCITYSQR) { ship->soundevent.engineState = SOUND_PLAYING; } } soundvolume(ship->soundevent.engineHandle, ship->soundevent.engineVol); soundpan(ship->soundevent.engineHandle, ship->soundevent.pan); soundequalize(ship->soundevent.engineHandle, tempEQ); } } } if (ship->soundevent.engineHandle == SOUND_SHIP_EXPLODED) { soundEventShipRemove(ship); goto nextship; } /* figure out the volume */ vol = SEequalize(shipclass, dist, tempEQ); if (vol > SOUND_VOL_MAX) { vol = SOUND_VOL_MAX; } shipangle = SEgetAngleToCamera(ship); velocity = fsqrt(vecMagnitudeSquared(ship->posinfo.velocity)); if (ship->staticinfo->maxfuel > 0.0) { /* this is a fighter */ if (shipclass == CLASS_Fighter) { velratio = FIGHTER_VELOCITY_LOWPITCH; + (velocity / ship->staticinfo->staticheader.maxvelocity * FIGHTER_VELOCITY_SCALE); if (velratio > FIGHTER_VELOCITY_HIGHPITCH) { velratio = FIGHTER_VELOCITY_HIGHPITCH; } } #if 0 /* this is a corvette */ else if (shipclass == CLASS_Corvette) { velratio = CORVETTE_VELOCITY_LOWPITCH; + (velocity / ship->staticinfo->staticheader.maxvelocity * CORVETTE_VELOCITY_SCALE); if (velratio > CORVETTE_VELOCITY_HIGHPITCH) { velratio = CORVETTE_VELOCITY_HIGHPITCH; } } #endif } if (nisIsRunning) { if ((velocity <= SFX_NIS_FLOAT_VELOCITY) && (ship->soundevent.engineState != SOUND_STARTING)) { vol = 0; } } else { if ((velocity <= SFX_FLOAT_VELOCITY) && (ship->soundevent.engineState != SOUND_STARTING)) { vol = 0; } } /* need this for setting the music volume */ if (dist < nearestShipDistance) { nearestShipDistance = dist; if (velocity > SFX_FLOAT_VELOCITY) { nearestShipMoving = TRUE; } } if (ship->soundevent.engineHandle == SOUND_NOTINITED) { /* start the engine sound */ if (velratio > 1.0f) { ship->soundevent.engineHandle = splayFPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, velratio, pan, SOUND_PRIORITY_MAX, vol, TRUE, TRUE, FALSE); } else { ship->soundevent.engineHandle = splayEPRVL(ShipBank, ShipCmnEventsLUT->lookup[GetPatch(ShipCmnEventsLUT, ship->shiptype, ShipCmn_Engine)], tempEQ, pan, SOUND_PRIORITY_MAX, vol, TRUE); } } else { if ((ship->soundevent.engineState == SOUND_STARTING) && (velocity > SFX_FLOAT_VELOCITY)) { ship->soundevent.engineState = SOUND_PLAYING; } /* set volume */ soundvolume(ship->soundevent.engineHandle, vol); /* set pan */ soundpan(ship->soundevent.engineHandle, pan); /* set frequency */ if (velratio > 1.0f) { soundfrequency(ship->soundevent.engineHandle, velratio); } /* set equalization */ soundequalize(ship->soundevent.engineHandle, tempEQ); } if (shipclass == CLASS_Fighter) { if (FIGHTER_DOPPLER_USEVELOCITY) { soundshipheading(ship->soundevent.engineHandle, shipangle, FIGHTER_DOPPLER_HIGH, FIGHTER_DOPPLER_LOW, velratio, FIGHTER_DOPPLER_SCALE); } else { soundshipheading(ship->soundevent.engineHandle, shipangle, FIGHTER_DOPPLER_HIGH, FIGHTER_DOPPLER_LOW, 1.0f, FIGHTER_DOPPLER_SCALE); } } #if 1 if (shipclass == CLASS_Corvette) { if (CORVETTE_DOPPLER_USEVELOCITY) { soundshipheading(ship->soundevent.engineHandle, shipangle, CORVETTE_DOPPLER_HIGH, CORVETTE_DOPPLER_LOW, velratio, CORVETTE_DOPPLER_SCALE); } else { soundshipheading(ship->soundevent.engineHandle, shipangle, CORVETTE_DOPPLER_HIGH, CORVETTE_DOPPLER_LOW, 1.0f, CORVETTE_DOPPLER_SCALE); } } #endif /* ambients */ /* special sounds */ /* gimbles */ } #endif #if 0 void SEupdateShipRange(void) { Node *objnode = universe.RenderList.tail; Ship *ship; Ship *tempship; Ship *temp; ShipClass shipclass; sdword i; numMoships = 0; while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); if (ship->objtype != OBJ_ShipType) { goto next; } shipclass = ship->staticinfo->shipclass; if (SEinrangeSqr(shipclass, ship->cameraDistanceSquared)) { ship->soundevent.distance = (real32)fsqrt(ship->cameraDistanceSquared); ship->soundevent.coverage = rndComputeOverlap(ship, 1.0); // make 1.0 tweakable in a script ship->soundevent.pan = getPanAngle(ship->enginePosition); ship->soundevent.engineVol = SEcalcvol(shipclass, ship->soundevent.distance); // want to modify the volume by the coverage and a tweak to modify the effect of coverage if (ship->soundevent.engineVol > SOUND_VOL_MAX) { ship->soundevent.engineVol = SOUND_VOL_MAX; } } else { ship->soundevent.engineVol = 0; } if (ship->soundevent.engineVol > 0) { tempship = ship; if ((shipclass == CLASS_Fighter) || (shipclass == CLASS_Corvette)) { for (i = 0; i < SFX_MAX_STRIKEENGINES; i++) { if (strike[i] != NULL) { if ((tempship->soundevent.engineVol > strike[i]->soundevent.engineVol) || ((tempship->soundevent.engineVol == strike[i]->soundevent.engineVol) && (tempship->soundevent.coverage < strike[i]->soundevent.coverage))) { temp = strike[i]; strike[i] = tempship; tempship = temp; } } else { strike[i] = tempship; break; } } } else if (shipclass == CLASS_Mothership) { if (numMoships < SE_MAX_MOSHIPS) { moships[numMoships++] = tempship; } } else { for (i = 0; i < SFX_MAX_CAPENGINES; i++) { if (capships[i] != NULL) { if ((tempship->soundevent.engineVol > capships[i]->soundevent.engineVol) || ((tempship->soundevent.engineVol == capships[i]->soundevent.engineVol) && (tempship->soundevent.coverage < capships[i]->soundevent.coverage))) { temp = capships[i]; capships[i] = tempship; tempship = temp; } } else { capships[i] = tempship; break; } } } } next: objnode = objnode->prev; } } #endif void soundEventInitStruct(SOUNDEVENT *pseStruct) { pseStruct->engineHandle = SOUND_NOTINITED; pseStruct->engineState = SOUND_NOTINITED; pseStruct->ambientHandle = SOUND_NOTINITED; pseStruct->damageHandle = SOUND_NOTINITED; pseStruct->specialHandle = SOUND_NOTINITED; pseStruct->hyperspaceHandle = SOUND_NOTINITED; pseStruct->actorNum = SOUND_NOTINITED; pseStruct->coverage = 0.0f; pseStruct->distance = REALlyBig; pseStruct->pan = SOUND_PAN_CENTER; pseStruct->engineVol = SOUND_NOTINITED; pseStruct->randomHandle = SOUND_NOTINITED; pseStruct->nextRandom = universe.totaltimeelapsed; pseStruct->lastAmbient = ShipCmn_Ambient; pseStruct->timeLastStatus = universe.totaltimeelapsed; pseStruct->burstHandle = SOUND_NOTINITED; pseStruct->burstfiring = FALSE; pseStruct->gunHandle = SOUND_NOTINITED; pseStruct->gun = NULL; } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventShipDied(Ship *deadship) { soundEventShipRemove(deadship); if (deadship != NULL) { deadship->soundevent.engineHandle = SOUND_SHIP_EXPLODED; } /* might need some other stuff here */ if (enableSpeech) { if (deadship != NULL) { /* remove all the speech events for this ship */ speechEventRemoveShip(deadship); if (deadship->playerowner == universe.curPlayerPtr) { /* need some global warnings */ if (isCapitalShip(deadship)) { if (deadship->shiptype != CryoTray) { speechEventFleet(STAT_F_Cap_Dies, deadship->staticinfo->shipclass, deadship->playerowner->playerIndex); } } else if (deadship->shiptype == ResourceCollector) { speechEventFleet(STAT_F_ResCol_Dies, 0, deadship->playerowner->playerIndex); } } } } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventShipRemove(Ship *ship) { if (enableSFX) { SEstopengine(ship, TRUE); soundEventBurstStop(ship, NULL); SEstopsoundhandle(&(ship->soundevent.specialHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.ambientHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.damageHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.randomHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.gunHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.hyperspaceHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(ship->soundevent.burstHandle), SOUND_FADE_STOPNOW); if (ship != NULL) { ship->soundevent.engineHandle = SOUND_NOTINITED; } } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventDerelictRemove(Derelict *pDerelict) { if (enableSFX) { SEstopsoundhandle(&(pDerelict->ambientSoundHandle), SOUND_FADE_STOPNOW); SEstopsoundhandle(&(pDerelict->randomSoundHandle), SOUND_FADE_STOPNOW); } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool SEinrange(sdword shipclass, real32 distance) { if (RangeLUT != NULL) { if (shipclass < RangeLUT->rows) { if (distance <= (real32)RangeLUT->lookup[shipclass * RangeLUT->columns + 2]) { return (TRUE); } } } return (FALSE); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool SEinrangeSqr(sdword shipclass, real32 distancesqr) { if (RangeLUT != NULL) { if (shipclass < RangeLUT->rows) { real32 rangelut = (real32)RangeLUT->lookup[shipclass * RangeLUT->columns + 2]; if (distancesqr <= (rangelut*rangelut)) { return (TRUE); } } } return (FALSE); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sword SEcalcvol(sdword objtype, real32 distance) { sdword i, pos, index = SOUND_ERR; real32 mult, vol = 0.0f; if ((RangeLUT != NULL) && (VolumeLUT != NULL)) { if ((objtype < RangeLUT->rows) && (objtype < VolumeLUT->rows)) { pos = objtype * RangeLUT->columns; for (i = 0; i < RangeLUT->columns; i++) { if (distance <= (real32)RangeLUT->lookup[pos + i]) { index = pos + i; break; } } if (index < SOUND_OK) { return (0); } mult = ((real32)RangeLUT->lookup[index] - distance) * RangeFloatLUT[index]; vol = volSFX * ((real32)VolumeLUT->lookup[index] + (mult * VolumeFloatLUT[index])); } } return ((sword)vol); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sword SEequalize(sdword objtype, real32 distance, real32 *eq) { sdword i, pos, index = SOUND_ERR, Findex = SOUND_ERR; real32 mult, vol = 0.0f; if ((RangeLUT != NULL) && (FrequencyLUT != NULL) && (VolumeLUT != NULL)) { if ((objtype < RangeLUT->rows) && (objtype < VolumeLUT->rows)) { pos = objtype * RangeLUT->columns; for (i = 0; i < RangeLUT->columns; i++) { if (distance <= (real32)RangeLUT->lookup[pos + i]) { Findex = i * FrequencyLUT->columns; index = pos + i; break; } } if (index < SOUND_OK) { for (i = 0; i < FrequencyLUT->columns; i++) { eq[i] = DefaultEQ[i]; } return (0); } mult = ((real32)RangeLUT->lookup[index] - distance) * RangeFloatLUT[index]; vol = volSFX * ((real32)VolumeLUT->lookup[index] + (mult * VolumeFloatLUT[index])); if (vol < SFX_MIN_PERCEPTABLE_VOL) { vol = 0; } else { if (vol > SOUND_VOL_MAX) { vol = SOUND_VOL_MAX; } for (i = 0; i < FrequencyLUT->columns; i++) { eq[i] = FrequencyLUT->lookup[Findex + i] + (mult * FreqLUT[Findex + i]); } } } } return ((sword)vol); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void SEeq(sdword objtype, real32 distance, real32 *eq) { sdword i, pos, index = SOUND_ERR, Findex = SOUND_ERR; real32 mult; if ((RangeLUT != NULL) && (FrequencyLUT != NULL) && (VolumeLUT != NULL)) { if ((objtype < RangeLUT->rows) && (objtype < VolumeLUT->rows)) { pos = objtype * RangeLUT->columns; for (i = 0; i < RangeLUT->columns; i++) { if (distance <= (real32)RangeLUT->lookup[pos + i]) { Findex = i * FrequencyLUT->columns; index = pos + i; break; } } if (index < SOUND_OK) { for (i = 0; i < FrequencyLUT->columns; i++) { eq[i] = DefaultEQ[i]; } return; } mult = ((real32)RangeLUT->lookup[index] - distance) * RangeFloatLUT[index]; for (i = 0; i < FrequencyLUT->columns; i++) { eq[i] = FrequencyLUT->lookup[Findex + i] + (mult * FreqLUT[Findex + i]); } } } return; } sword SEcalcenginevol(sdword shipclass, real32 distance) { sdword i, index = SOUND_ERR; real32 mult; sword vol; sword pos; pos = shipclass * RangeLUT->columns; for (i = 1; i < 3; i++) { if (distance <= (real32)RangeLUT->lookup[pos + i]) { index = pos + i - 1; break; } } if (index < SOUND_OK) { return (0); } mult = ((real32)RangeLUT->lookup[index+1] - distance) / (real32)(RangeLUT->lookup[index+1] - RangeLUT->lookup[index]); vol = (sword)(VolumeLUT->lookup[index+1] + (mult * (VolumeLUT->lookup[index] - VolumeLUT->lookup[index+1]))); return ((sword)(vol * SFX_VOL_FACTOR)); } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void SEstopengine(Ship *ship, bool stopnow) { if (ship == NULL) return; ship->soundevent.engineState = SOUND_NOTINITED; if (ship->soundevent.engineHandle > SOUND_NOTINITED) { if (stopnow) { soundstop(ship->soundevent.engineHandle, SOUND_FADE_STOPNOW); } else { soundstop(ship->soundevent.engineHandle, 5.0f); } ship->soundevent.engineHandle = SOUND_NOTINITED; } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void SEstopsoundhandle(sdword *shandle, real32 fadetime) { if (*shandle > SOUND_NOTINITED) { soundstop(*shandle, fadetime); *shandle = SOUND_NOTINITED; } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void SEloadbank(void) { char loadfile[100]; /* new stuff */ strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "GunEvents.lut"); fileLoadAlloc(loadfile, &GunEventsLUT, NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "ShipCmnEvents.lut"); fileLoadAlloc(loadfile, &ShipCmnEventsLUT, NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "ShipEvents.lut"); fileLoadAlloc(loadfile, &ShipEventsLUT, NonVolatile); if (ShipEventsLUT->checksum != ShipCmnEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "DerelictEvents.lut"); fileLoadAlloc(loadfile, &DerelictEventsLUT, NonVolatile); if (DerelictEventsLUT->checksum != ShipCmnEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } // strcpy(loadfile, SOUNDFXDIR); // strcat(loadfile, "SpecEffectEvents.lut"); // fileLoadAlloc(loadfile, &SpecEffectEventsLUT, NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "SpecExpEvents.lut"); fileLoadAlloc(loadfile, &SpecExpEventsLUT, NonVolatile); // if (SpecExpEventsLUT->checksum != SpecEffectEventsLUT->checksum) // { // dbgMessage("Lookup tables do not match. Not from same generate.\n"); // dbgAssert(FALSE); // } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "SpecHitEvents.lut"); fileLoadAlloc(loadfile, &SpecHitEventsLUT, NonVolatile); // if (SpecHitEventsLUT->checksum != SpecEffectEventsLUT->checksum) if (SpecHitEventsLUT->checksum != SpecExpEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "UIEvents.lut"); fileLoadAlloc(loadfile, &UIEventsLUT, NonVolatile); strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Guns.bnk"); fileLoadAlloc(loadfile, &GunBank, NonVolatile); if (soundbankadd(GunBank) != GunEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "Ships.bnk"); fileLoadAlloc(loadfile, &ShipBank, NonVolatile); if (soundbankadd(ShipBank) != ShipCmnEventsLUT->checksum) { dbgMessage("Ship bank file does not match Lookup tables. Not from same generate.\n"); dbgAssert(FALSE); } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "SpecialEffects.bnk"); fileLoadAlloc(loadfile, &SpecialEffectBank, NonVolatile); // if (soundbankadd(SpecialEffectBank) != SpecEffectEventsLUT->checksum) if (soundbankadd(SpecialEffectBank) != SpecExpEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } strcpy(loadfile, SOUNDFXDIR); strcat(loadfile, "UI.bnk"); fileLoadAlloc(loadfile, &UIBank, NonVolatile); if (soundbankadd(UIBank) != UIEventsLUT->checksum) { dbgMessage("Lookup tables do not match. Not from same generate.\n"); dbgAssert(FALSE); } } /*----------------------------------------------------------------------------- Name : Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void soundEventPlayCD(uword tracknum) { MCIERROR ret; MCI_STATUS_PARMS MCIStatus; // MCI_STATUS structure MCI_SET_PARMS MCISet; // MCI_SET structure MCI_PLAY_PARMS MCIPlay; // MCI_PLAY structure MCIOpen.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO; ret = mciSendCommand (0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD) (LPVOID) &MCIOpen); MCISet.dwTimeFormat = MCI_FORMAT_TMSF; mciSendCommand (MCIOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD) (LPVOID) &MCISet); MCIStatus.dwItem = MCI_STATUS_MEDIA_PRESENT; mciSendCommand (MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &MCIStatus); if (MCIStatus.dwReturn) { // Send an MCI_PLAY command to the CD Audio driver. MCIPlay.dwCallback = (DWORD) ghMainWindow; MCIPlay.dwFrom = MCI_MAKE_TMSF (tracknum, 0, 0, 0); ret = mciSendCommand (MCIOpen.wDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD) (LPVOID) &MCIPlay); } } void soundEventStopCD(void) { mciSendCommand (MCIOpen.wDeviceID, MCI_STOP, 0, 0); } void soundEventPlayMusic(sdword tracknum) { musicEventPlay(tracknum); return; } void soundEventStopMusic(real32 fadetime) { musicEventStop(-1, fadetime); return; } void soundEventStopTrack(sdword tracknum, real32 fadetime) { musicEventStop(tracknum, fadetime); return; } ////********** Panning Angle code ************///// /*----------------------------------------------------------------------------- Name : getPanAngle Description : calculates the angle between the passed vector and the cameras lookat vector (projected onto the cameras 2D horizontal plane). 0| | | -90 --------------------90 | | | -179/179 Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sword getPanAngle(vector WorldVector, real32 objsize, real32 distance) { vector CameraToPoint; vector CameraRightVec; vector CameraLookAt; vector ProjOnRight; vector ProjOnLookAt; vector Projection; real32 Prright; real32 Prlook; real32 dotprod; real32 angle; if (distance < (objsize * 2.0f)) { return ((sword)SOUND_PAN_CENTER); } vecSub(CameraToPoint, WorldVector, mrCamera->eyeposition); vecSub(CameraLookAt, mrCamera->lookatpoint, mrCamera->eyeposition); //if NIS isn't playing...we know upvector is 0,0,1 so we can simplify cross product a grreat // deal vecCrossProduct(CameraRightVec,CameraLookAt,mrCamera->upvector); vecNormalize(&CameraLookAt); Prlook = vecDotProduct(CameraLookAt,CameraToPoint); vecScalarMultiply(ProjOnLookAt,CameraLookAt,Prlook); Prright = vecDotProduct(CameraRightVec,CameraToPoint)/vecMagnitudeSquared(CameraRightVec); vecScalarMultiply(ProjOnRight,CameraRightVec,Prright); vecAdd(Projection,ProjOnLookAt,ProjOnRight); vecNormalize(&Projection); dotprod = vecDotProduct(Projection,CameraLookAt); if(dotprod <-1.0f) dotprod = -1.0f; else if(dotprod > 1.0f) dotprod = 1.0f; angle = (float) acos(dotprod); if(Prright < 0.0f) angle = -angle; return((sword) (angle*PI_UNDER_180)); } sword SEgetAngleToCamera(Ship *ship) { vector ShipToCamera; vector ShipDest; vector heading; vector head; vector up; real32 dotprod; real32 angle; matGetVectFromMatrixCol3(head,ship->rotinfo.coordsys); matGetVectFromMatrixCol1(up,ship->rotinfo.coordsys); vecAdd(heading,ship->posinfo.position,head); vecSub(ShipToCamera, mrCamera->eyeposition, ship->posinfo.position); vecSub(ShipDest, heading, ship->posinfo.position); vecNormalize(&ShipToCamera); vecNormalize(&ShipDest); dotprod = vecDotProduct(ShipToCamera,ShipDest); angle = (float) acos(dotprod); return((sword) (angle*PI_UNDER_180)); }