#include "builddefines.h" #include "Ambient Control.h" #include "Sound Control.h" #include "Game Events.h" #include "lighting.h" #include "random.h" // sevenfm #include "SmokeEffects.h" #include "Overhead.h" #include "Strategic Movement.h" #include "Game Clock.h" #include "Strategic Mines.h" AMBIENTDATA_STRUCT gAmbData[ MAX_AMBIENT_SOUNDS ]; INT16 gsNumAmbData = 0; // sevenfm UINT32 guiAmbientFire = NO_SAMPLE; UINT8 gubAmbientFutureFireVolume = 0; UINT32 guiFireAmbientLastUpdate = 0; extern STR8 pVertStrings[]; extern STR8 pHortStrings[]; extern CHAR16 (*pTownNames)[MAX_TOWN_NAME_LENGHT]; UINT8 gubCurrentSteadyStateAmbience = SSA_NONE; UINT8 gubCurrentSteadyStateSound = 0; UINT32 guiCurrentSteadyStateSoundHandle = NO_SAMPLE; STEADY_STATE_AMBIENCE gSteadyStateAmbientTable[ NUM_STEADY_STATE_AMBIENCES ] = { // NONE "", "", "", "", // NIGHT "", "", "", "", // COUNTRYSIZE // DAY "SOUNDS\\SSA\\insects Day 01.wav", "", "", "", // NIGHT "SOUNDS\\SSA\\night_crickets_01D.wav", "SOUNDS\\SSA\\night_crickets_01B.wav", "SOUNDS\\SSA\\night_crickets_01C.wav", "SOUNDS\\SSA\\night_crickets_01A.wav", // NEAR WATER // DAY "SOUNDS\\SSA\\swamp_day_01a.wav", "SOUNDS\\SSA\\swamp_day_01b.wav", "SOUNDS\\SSA\\swamp_day_01c.wav", "SOUNDS\\SSA\\swamp_day_01d.wav", //NIGHT "SOUNDS\\SSA\\marsh_at_night_01a.wav", "SOUNDS\\SSA\\marsh_at_night_01b.wav", "SOUNDS\\SSA\\marsh_at_night_01c.wav", "SOUNDS\\SSA\\marsh_at_night_01d.wav", //INWATER //DAY "SOUNDS\\SSA\\middle_of_water_01d.wav", "SOUNDS\\SSA\\middle_of_water_01c.wav", "SOUNDS\\SSA\\middle_of_water_01b.wav", "SOUNDS\\SSA\\middle_of_water_01a.wav", // night "SOUNDS\\SSA\\middle_of_water_01d.wav", "SOUNDS\\SSA\\middle_of_water_01c.wav", "SOUNDS\\SSA\\middle_of_water_01b.wav", "SOUNDS\\SSA\\middle_of_water_01a.wav", // HEAVY FOREST // day "SOUNDS\\SSA\\JUNGLE_DAY_01a.wav", "SOUNDS\\SSA\\JUNGLE_DAY_01b.wav", "SOUNDS\\SSA\\JUNGLE_DAY_01c.wav", "SOUNDS\\SSA\\JUNGLE_DAY_01d.wav", // night "SOUNDS\\SSA\\night_crickets_03a.wav", "SOUNDS\\SSA\\night_crickets_03b.wav", "SOUNDS\\SSA\\night_crickets_03c.wav", "SOUNDS\\SSA\\night_crickets_03d.wav", // PINE FOREST // DAY "SOUNDS\\SSA\\pine_forest_01a.wav", "SOUNDS\\SSA\\pine_forest_01b.wav", "SOUNDS\\SSA\\pine_forest_01c.wav", "SOUNDS\\SSA\\pine_forest_01d.wav", // NIGHT "SOUNDS\\SSA\\night_crickets_02a.wav", "SOUNDS\\SSA\\night_crickets_02b.wav", "SOUNDS\\SSA\\night_crickets_02c.wav", "SOUNDS\\SSA\\night_crickets_02d.wav", // ABANDANDED // DAY "SOUNDS\\SSA\\metal_wind_01a.wav", "SOUNDS\\SSA\\metal_wind_01b.wav", "SOUNDS\\SSA\\metal_wind_01c.wav", "SOUNDS\\SSA\\metal_wind_01d.wav", // NIGHT "SOUNDS\\SSA\\night_insects_01a.wav", "SOUNDS\\SSA\\night_insects_01b.wav", "SOUNDS\\SSA\\night_insects_01c.wav", "SOUNDS\\SSA\\night_insects_01d.wav", // AIRPORT // DAY "SOUNDS\\SSA\\rotating radar dish.wav", "", "", "", // NIGHT "SOUNDS\\SSA\\rotating radar dish.wav", "", "", "", // WASTE LAND // DAY "SOUNDS\\SSA\\gentle_wind.wav", "", "", "", // NIGHT "SOUNDS\\SSA\\insects_at_night_04.wav", "", "", "", // UNDERGROUND // DAY "SOUNDS\\SSA\\low ominous ambience.wav", "", "", "", // NIGHT "SOUNDS\\SSA\\low ominous ambience.wav", "", "", "", // OCEAN // DAY "SOUNDS\\SSA\\sea_01a.wav", "SOUNDS\\SSA\\sea_01b.wav", "SOUNDS\\SSA\\sea_01c.wav", "SOUNDS\\SSA\\sea_01d.wav", // NIGHT "SOUNDS\\SSA\\ocean_waves_01a.wav", "SOUNDS\\SSA\\ocean_waves_01b.wav", "SOUNDS\\SSA\\ocean_waves_01c.wav", "SOUNDS\\SSA\\ocean_waves_01d.wav", }; BOOLEAN LoadAmbientControlFile( UINT8 ubAmbientID ) { SGPFILENAME zFilename; HWFILE hFile; INT32 cnt; // BUILD FILENAME sprintf( zFilename, "AMBIENT\\%d.bad", ubAmbientID ); // OPEN, LOAD hFile = FileOpen( zFilename, FILE_ACCESS_READ, FALSE); if ( !hFile ) { return( FALSE ); } // READ # if( !FileRead( hFile, &gsNumAmbData, sizeof( INT16 ), NULL ) ) { return( FALSE ); } // LOOP FOR OTHERS for ( cnt = 0; cnt < gsNumAmbData; cnt++ ) { if( !FileRead( hFile, &(gAmbData[ cnt ]), sizeof( AMBIENTDATA_STRUCT ), NULL ) ) { return( FALSE ); } sprintf( zFilename, "AMBIENT\\%s", gAmbData[ cnt ].zFilename ); strcpy( gAmbData[ cnt ].zFilename, zFilename ); } FileClose( hFile ); return( TRUE ); } void GetAmbientDataPtr( AMBIENTDATA_STRUCT **ppAmbData, UINT16 *pusNumData ) { *ppAmbData = gAmbData; *pusNumData = gsNumAmbData; } void StopAmbients( ) { SoundStopAllRandom( ); } void HandleNewSectorAmbience( UINT8 ubAmbientID ) { // OK, we could have just loaded a sector, erase all ambient sounds from queue, shutdown all ambient groupings SoundStopAllRandom( ); DeleteAllStrategicEventsOfType( EVENT_AMBIENT ); if( !gfBasement && !gfCaves ) { if( LoadAmbientControlFile( ubAmbientID ) ) { // OK, load them up! BuildDayAmbientSounds( ); } else { DebugMsg(TOPIC_JA2, DBG_LEVEL_0, String("Cannot load Ambient data for tileset" ) ); } } } void DeleteAllAmbients() { // JA2Gold: it seems that ambient sounds don't get unloaded when we exit a sector!? SoundStopAllRandom(); DeleteAllStrategicEventsOfType( EVENT_AMBIENT ); } UINT32 SetupNewAmbientSound( UINT32 uiAmbientID ) { RANDOMPARMS rpParms; //SoundLog((CHAR8 *)String(" SetupNewAmbientSound()1: uiAmbientID: '%d'", uiAmbientID ) ); memset(&rpParms, 0xff, sizeof(RANDOMPARMS)); rpParms.uiTimeMin = gAmbData[ uiAmbientID ].uiMinTime; rpParms.uiTimeMax = gAmbData[ uiAmbientID ].uiMaxTime; rpParms.uiVolMin = CalculateSoundEffectsVolume( gAmbData[ uiAmbientID ].uiVol ); rpParms.uiVolMax = CalculateSoundEffectsVolume( gAmbData[ uiAmbientID ].uiVol ); rpParms.uiPriority = GROUP_AMBIENT; //SoundLog((CHAR8 *)String(" SetupNewAmbientSound()2: gAmbData[ uiAmbientID ].zFilename: '%s', Params: '%s'", gAmbData[ uiAmbientID ].zFilename, &rpParms ) ); return SoundPlayRandom( gAmbData[ uiAmbientID ].zFilename, &rpParms ); //bug Nr14 } UINT32 StartSteadyStateAmbient( UINT32 ubVolume, UINT32 ubLoops) { SOUNDPARMS spParms; memset(&spParms, 0xff, sizeof(SOUNDPARMS)); spParms.uiVolume = CalculateSoundEffectsVolume( ubVolume ); spParms.uiLoop = ubLoops; spParms.uiPriority=GROUP_AMBIENT; return(SoundPlay(gSteadyStateAmbientTable[gubCurrentSteadyStateAmbience].zSoundNames[gubCurrentSteadyStateSound], &spParms)); } BOOLEAN SetSteadyStateAmbience(UINT8 ubAmbience) { BOOLEAN fInNight = FALSE; INT32 cnt; UINT8 ubNumSounds = 0; UINT8 ubChosenSound; // Stop all ambients... if (guiCurrentSteadyStateSoundHandle != NO_SAMPLE) { SoundStop(guiCurrentSteadyStateSoundHandle); guiCurrentSteadyStateSoundHandle = NO_SAMPLE; } // Determine what time of day we are in ( day/night) if (gubEnvLightValue >= LIGHT_DUSK_CUTOFF) { fInNight = TRUE; } // loop through listing to get num sounds... // sevenfm: bugfix for night ambients for (cnt = fInNight * 4; cnt < fInNight * 4 + NUM_SOUNDS_PER_TIMEFRAME / 2; cnt++) //for (cnt = (fInNight * 4); cnt < (NUM_SOUNDS_PER_TIMEFRAME / 2); cnt++) { if (gSteadyStateAmbientTable[ubAmbience].zSoundNames[cnt][0] == 0) { break; } ubNumSounds++; } if (ubNumSounds == 0) { return(FALSE); } // Pick one ubChosenSound = (UINT8)Random(ubNumSounds); // Set! gubCurrentSteadyStateAmbience = ubAmbience; gubCurrentSteadyStateSound = ubChosenSound; guiCurrentSteadyStateSoundHandle = StartSteadyStateAmbient(LOWVOLUME, 0); return(TRUE); } void UpdateFireAmbient(void) { INT32 iVolume; UINT32 uiClock; if (!gGameExternalOptions.fEnableTA) { return; } if (guiCurrentScreen != GAME_SCREEN) { return; } uiClock = GetJA2Clock(); if (uiClock - guiFireAmbientLastUpdate < 50) { return; } guiFireAmbientLastUpdate = uiClock; if (FindVisibleSmokeEffect(BURNABLEGAS_SMOKE_EFFECT)) { gubAmbientFutureFireVolume = CalculateSoundEffectsVolume(gGameExternalOptions.ubVolumeTA); if (guiAmbientFire == NO_SAMPLE) { StartFireAmbient(); } // check if successfully started if (guiAmbientFire != NO_SAMPLE) { iVolume = SoundGetVolume(guiAmbientFire); if (iVolume != gubAmbientFutureFireVolume) { // increase volume until it reaches desired level iVolume = min((INT32)gubAmbientFutureFireVolume, iVolume + 4); SoundSetVolume(guiAmbientFire, iVolume); } } } else { gubAmbientFutureFireVolume = 0; // check if ambient sound is playing if (guiAmbientFire != NO_SAMPLE) { iVolume = SoundGetVolume(guiAmbientFire); if (iVolume != gubAmbientFutureFireVolume) { // increase volume until it reaches desired level iVolume = max((INT32)gubAmbientFutureFireVolume, iVolume - 4); SoundSetVolume(guiAmbientFire, iVolume); } if (iVolume == 0) { StopFireAmbient(); } } } } void StopFireAmbient(void) { if (guiAmbientFire != NO_SAMPLE) { SoundStop(guiAmbientFire); guiAmbientFire = NO_SAMPLE; } } void StartFireAmbient(void) { CHAR8 filename[1024]; SOUNDPARMS spParms; // Stop ambient if (guiAmbientFire != NO_SAMPLE) { return; } strcpy(filename, "Ambient\\fire.ogg"); //gubAmbientFireVolume = LOWVOLUME; // start sound memset(&spParms, 0xff, sizeof(SOUNDPARMS)); //spParms.uiVolume = CalculateSoundEffectsVolume( LOWVOLUME ); spParms.uiVolume = 0; spParms.uiLoop = 0; spParms.uiPriority = GROUP_AMBIENT; //guiAmbientFire = SoundPlay( zFileName, &spParms ); guiAmbientFire = SoundPlayStreamedFile(filename, &spParms); } #define MAX_SSA_SOUNDS 10 extern BOOLEAN AreInMeanwhile(); void SetSSA(void) { BOOLEAN fNight = FALSE; BOOLEAN fCombat = FALSE; UINT8 ubNumSounds = 0; UINT8 ubChosenSound; CHAR8 filename[1024]; CHAR16 name16[1024]; CHAR8 SectorName[1024]; CHAR8 TownName[1024]; CHAR8 GenericName[1024]; CHAR8 UnderGround[1024]; BOOLEAN fUnderground = FALSE; SGPFILENAME zFileName; UINT8 ubSectorID; SOUNDPARMS spParms; SECTORINFO *pSector = NULL; //UNDERGROUND_SECTORINFO *pUnderground; //CHAR16 zString[1024]; UINT16 usTownSectorIndex; BOOLEAN fFoundSAM = FALSE; UINT8 ubMineIndex; //MINE_STATUS_TYPE *pMineStatus; memset(TownName, 0, 1024 * sizeof(char)); memset(name16, 0, 1024 * sizeof(wchar_t)); // Stop all ambients... if (guiCurrentSteadyStateSoundHandle != NO_SAMPLE) { SoundStop(guiCurrentSteadyStateSoundHandle); guiCurrentSteadyStateSoundHandle = NO_SAMPLE; } if (!gGameExternalOptions.fEnableSSA) { return; } // no ambients in the rain if (GetWeatherInCurrentSector() != WEATHER_FORECAST_NORMAL) { return; } // no ambients in cutscenes if(AreInMeanwhile()) { return; } // Determine what time of day we are in ( day/night) if (gubEnvLightValue >= LIGHT_DUSK_CUTOFF) { fNight = TRUE; } // determine combat state if( gTacticalStatus.uiFlags & INCOMBAT)// || NumCapableEnemyInSector( ) || HostileZombiesPresent() ) { fCombat = TRUE; } // determine sector name UINT8 ubTownID = GetTownIdForSector(gWorldSectorX, gWorldSectorY); if (ubTownID != BLANK_SECTOR && gbWorldSectorZ == 0) { //wcstombs(TownName, pTownNames[ubTownID], wcslen(pTownNames[ubTownID])+1); wcstombs(TownName, pTownNames[ubTownID], 1024 - 1); //ScreenMsg(FONT_ORANGE, MSG_INTERFACE, L"%s", pTownNames[ubTownID]); } // check sector file sprintf(SectorName, "%s%s", pVertStrings[gWorldSectorY], pHortStrings[gWorldSectorX]); // determine underground if (gbWorldSectorZ > 0) { fUnderground = TRUE; } // determine town name // check town file // determine generic name // check generic file // prepare name strcpy(filename, "Ambient\\SSA\\"); strcat(filename, SectorName); if (fUnderground) { sprintf(UnderGround, "u%d", gbWorldSectorZ + 1); strcat(filename, UnderGround); } strcat(filename, "_"); if (!fUnderground) { if (fNight) strcat(filename, "night_"); else strcat(filename, "day_"); } // find number of files ubNumSounds = 0; for (UINT8 i = 1; i <= MAX_SSA_SOUNDS; i++) { sprintf(zFileName, "%s%d.ogg", filename, i); if (!FileExists(zFileName)) break; else ubNumSounds++; } // check town name if (ubNumSounds == 0 && !fUnderground && ubTownID != BLANK_SECTOR) { // prepare name strcpy(filename, "Ambient\\SSA\\"); strcat(filename, TownName); strcat(filename, "_"); if (fNight) strcat(filename, "night_"); else strcat(filename, "day_"); // find number of files ubNumSounds = 0; for (UINT8 i = 1; i <= MAX_SSA_SOUNDS; i++) { sprintf(zFileName, "%s%d.ogg", filename, i); if (!FileExists(zFileName)) break; else ubNumSounds++; } } // check generic name if (ubNumSounds == 0) { ubSectorID = SECTOR(gWorldSectorX, gWorldSectorY); // underground sectors if (fUnderground) { strcpy(GenericName, ""); for (ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++) { // pMineStatus = &(gMineStatus[ ubMineIndex ]); if (gMineStatus[ubMineIndex].sSectorX == gWorldSectorX && gMineStatus[ubMineIndex].sSectorY == gWorldSectorY) { if (gMineStatus[ubMineIndex].fEmpty) { strcpy(GenericName, "EmptyMine"); } else { strcpy(GenericName, "Mine"); } break; } } } else if (ubTownID != BLANK_SECTOR) { // always use town if defined strcpy(GenericName, "Town"); } else { usTownSectorIndex = SECTOR(gWorldSectorX, gWorldSectorY); // Test for known SAM Site at this location for (UINT16 x = 0; x < MAX_NUMBER_OF_SAMS; x++) { if (pSamList[x] == usTownSectorIndex) // && fSamSiteFound[ x ] { fFoundSAM = TRUE; break; } } if (fFoundSAM) { strcpy(GenericName, "SAM"); } else { // make generic name from movement type in MovementCosts.xml switch (SectorInfo[ubSectorID].ubTraversability[THROUGH_STRATEGIC_MOVE]) { case TOWN: strcpy(GenericName, "Town"); break; case SAND: case SAND_ROAD: strcpy(GenericName, "Desert"); break; case FARMLAND: case FARMLAND_ROAD: strcpy(GenericName, "Farmland"); break; case PLAINS: case PLAINS_ROAD: case ROAD: strcpy(GenericName, "Plains"); break; break; case HILLS: case HILLS_ROAD: strcpy(GenericName, "Hills"); break; case SPARSE: case SPARSE_ROAD: case DENSE: case DENSE_ROAD: strcpy(GenericName, "Forest"); break; case SWAMP: case SWAMP_ROAD: strcpy(GenericName, "Swamp"); break; case TROPICS: case TROPICS_ROAD: strcpy(GenericName, "Tropical"); break; case WATER: strcpy(GenericName, "Water"); break; case NS_RIVER: case EW_RIVER: strcpy(GenericName, "River"); break; case COASTAL: case COASTAL_ROAD: strcpy(GenericName, "Coastal"); break; default: strcpy(GenericName, ""); } } } // prepare name strcpy(filename, "Ambient\\SSA\\"); strcat(filename, GenericName); strcat(filename, "_"); if (!fUnderground) { if (fNight) strcat(filename, "night_"); else strcat(filename, "day_"); } // find number of files ubNumSounds = 0; for (UINT8 i = 1; i <= MAX_SSA_SOUNDS; i++) { sprintf(zFileName, "%s%d.ogg", filename, i); if (!FileExists(zFileName)) break; else ubNumSounds++; } } if (ubNumSounds == 0) { return; } // pick random file ubChosenSound = (guiHour % ubNumSounds) + 1; //ubChosenSound = Random(ubNumSounds) + 1; // make a file name sprintf(zFileName, "%s%d.ogg", filename, ubChosenSound); // start sound memset(&spParms, 0xff, sizeof(SOUNDPARMS)); //spParms.uiVolume = CalculateSoundEffectsVolume( LOWVOLUME ); spParms.uiVolume = CalculateSoundEffectsVolume(gGameExternalOptions.ubVolumeSSA); spParms.uiLoop = 0; spParms.uiPriority = GROUP_AMBIENT; //guiCurrentSteadyStateSoundHandle = SoundPlay( zFileName, &spParms ); guiCurrentSteadyStateSoundHandle = SoundPlayStreamedFile(zFileName, &spParms); }