From 7e0606932f21f56519cc53dee18c1fe7632626f9 Mon Sep 17 00:00:00 2001 From: Sevenfm Date: Sat, 8 Feb 2020 19:35:10 +0000 Subject: [PATCH] New options to control Sector Steady Ambients: ENABLE_SSA (default FALSE) VOLUME_SSA (default 50) DEBUG_SSA (default FALSE) Increased number of sound channels to 64. SoundPlay(): show more information when failed to play sound. PlayVoiceTaunt(): limit max number of voices to 99. vfs::String::as_utf16(): show original string if failed to convert. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8745 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 3 + GameSettings.h | 3 + Standard Gaming Platform/soundman.cpp | 41 ++- Tactical/Civ Quotes.cpp | 2 +- TileEngine/Ambient Control.cpp | 351 ++++++++++++++++++++++++-- TileEngine/Ambient Control.h | 1 + ext/VFS/src/Core/vfs_string.cpp | 8 +- gameloop.cpp | 20 +- 8 files changed, 392 insertions(+), 37 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 0fe21fd9..807e3975 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -934,6 +934,9 @@ void LoadGameExternalOptions() gGameExternalOptions.gubMaxPercentNoiseSilencedSound = iniReader.ReadInteger("Sound Settings","MAX_PERCENT_NOISE_SILENCED_SOUND", 35, 0, 100 ); gGameExternalOptions.fEnableTA = iniReader.ReadBoolean("Sound Settings", "ENABLE_TA", TRUE, false); gGameExternalOptions.ubVolumeTA = iniReader.ReadInteger("Sound Settings", "VOLUME_TA", 50, 1, 127); + gGameExternalOptions.fEnableSSA = iniReader.ReadBoolean("Sound Settings", "ENABLE_SSA", false, false); + gGameExternalOptions.fDebugSSA = iniReader.ReadBoolean("Sound Settings", "DEBUG_SSA", false, false); + gGameExternalOptions.ubVolumeSSA = iniReader.ReadInteger("Sound Settings", "VOLUME_SSA", 50, 1, 127); //################# Tactical Interface Settings ################# diff --git a/GameSettings.h b/GameSettings.h index 9dac15af..4cd21e47 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -467,6 +467,9 @@ typedef struct UINT8 gubMaxPercentNoiseSilencedSound; BOOLEAN fEnableTA; UINT8 ubVolumeTA; + BOOLEAN fEnableSSA; + BOOLEAN fDebugSSA; + UINT8 ubVolumeSSA; // WDS - Option to turn off stealing BOOLEAN fStealingDisabled; diff --git a/Standard Gaming Platform/soundman.cpp b/Standard Gaming Platform/soundman.cpp index 8e63f956..e298fb73 100644 --- a/Standard Gaming Platform/soundman.cpp +++ b/Standard Gaming Platform/soundman.cpp @@ -22,6 +22,9 @@ #include "fmod.h" #include "fmod_errors.h" #include "sgp_logger.h" + // sevenfm + #include "message.h" + #include "Sound Control.h" #endif // Uncomment this to disable the startup of sound hardware @@ -30,11 +33,8 @@ // global settings #define SOUND_MAX_CACHED 128 // number of cache slots -#ifdef JA2 -#define SOUND_MAX_CHANNELS 16 // number of mixer channels -#else -#define SOUND_MAX_CHANNELS 32 // number of mixer channels -#endif +// sevenfm: increased number of channels +#define SOUND_MAX_CHANNELS 64 // default memory limit #define SOUND_DEFAULT_MEMORY (8048*1024) @@ -292,24 +292,38 @@ UINT32 SoundPlay(STR pFilename, SOUNDPARMS *pParms) { UINT32 uiSample, uiChannel; - if( fSoundSystemInit ) + if (fSoundSystemInit) { - if( !SoundPlayStreamed(pFilename) ) + if (!SoundPlayStreamed(pFilename)) { - if((uiSample=SoundLoadSample(pFilename))!=NO_SAMPLE) + if ((uiSample = SoundLoadSample(pFilename)) != NO_SAMPLE) { - if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR) + if ((uiChannel = SoundGetFreeChannel()) != SOUND_ERROR) { return(SoundStartSample(uiSample, uiChannel, pParms)); } + else + { + SoundLog((CHAR8 *)String("Could not get free channel, uiChannel = %d", uiChannel)); + } + } + else + { + SoundLog((CHAR8 *)String("Could not load sample, uiSample = %d", uiSample)); } } else { //Trying to play a sound which is bigger then the 'guiSoundCacheThreshold' - FastDebugMsg(String("SoundPlay: ERROR: Trying to play %s sound is too lardge to load into cache, use SoundPlayStreamedFile() instead\n", pFilename ) ); + FastDebugMsg(String("SoundPlay: ERROR: Trying to play %s sound is too large to load into cache, use SoundPlayStreamedFile() instead\n", pFilename)); + + SoundLog((CHAR8 *)String("SoundPlay: ERROR: Trying to play %s sound is too large to load into cache, use SoundPlayStreamedFile() instead\n", pFilename)); } } + else + { + SoundLog((CHAR8 *)String("SoundSystemInit FALSE")); + } return(SOUND_ERROR); } @@ -848,8 +862,10 @@ UINT32 uiChannel, uiSample; uiSample=pSoundList[uiChannel].uiSample; // if this was a random sample, decrease the iteration count - if ( (uiSample != -1) && (pSampleList[uiSample].uiFlags&SAMPLE_RANDOM) ) + if (uiSample != -1 && (pSampleList[uiSample].uiFlags & SAMPLE_RANDOM)) + { SoundStopIndex(uiChannel); + } } } @@ -1481,8 +1497,7 @@ UINT32 uiSoundID; // Loop if((pParms!=NULL) && (pParms->uiLoop!=SOUND_PARMS_DEFAULT)) { - // If looping infinately, lock the sample so it can't be unloaded - // and mark it as a looping sound + // If looping infinitely, lock the sample so it can't be unloaded and mark it as a looping sound if(pParms->uiLoop==0) { pSampleList[uiSample].uiFlags|=SAMPLE_LOCKED; diff --git a/Tactical/Civ Quotes.cpp b/Tactical/Civ Quotes.cpp index 97816851..11318873 100644 --- a/Tactical/Civ Quotes.cpp +++ b/Tactical/Civ Quotes.cpp @@ -2271,7 +2271,7 @@ BOOLEAN PlayVoiceTaunt(SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTa // count possible voices UINT8 ubVoiceCount; - for (ubVoiceCount = 1; ubVoiceCount <= 100; ubVoiceCount++) + for (ubVoiceCount = 1; ubVoiceCount < 100; ubVoiceCount++) { sprintf(buf, "%s%02d", filename, ubVoiceCount); strcat(buf, "\\alert.ogg"); diff --git a/TileEngine/Ambient Control.cpp b/TileEngine/Ambient Control.cpp index 78948a6b..9f6bae78 100644 --- a/TileEngine/Ambient Control.cpp +++ b/TileEngine/Ambient Control.cpp @@ -13,7 +13,16 @@ #include "Ambient Control.h" #include "lighting.h" #include "Random.h" - #include "SmokeEffects.h" // sevenfm + // sevenfm + #include "SmokeEffects.h" + #include "message.h" + #include "Overhead.h" + #include "strategicmap.h" + #include "Strategic Movement.h" + #include "Game Clock.h" + #include "Queen Command.h" + #include "undergroundinit.h" + #include "strategic mines.h" #endif AMBIENTDATA_STRUCT gAmbData[ MAX_AMBIENT_SOUNDS ]; @@ -24,6 +33,10 @@ UINT32 guiAmbientFire = NO_SAMPLE; UINT8 gubAmbientFutureFireVolume = 0; UINT32 guiFireAmbientLastUpdate = 0; +extern STR8 pVertStrings[]; +extern STR8 pHortStrings[]; +extern CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT]; + UINT8 gubCurrentSteadyStateAmbience = SSA_NONE; UINT8 gubCurrentSteadyStateSound = 0; UINT32 guiCurrentSteadyStateSoundHandle = NO_SAMPLE; @@ -255,7 +268,7 @@ UINT32 SetupNewAmbientSound( UINT32 uiAmbientID ) UINT32 StartSteadyStateAmbient( UINT32 ubVolume, UINT32 ubLoops) { -SOUNDPARMS spParms; + SOUNDPARMS spParms; memset(&spParms, 0xff, sizeof(SOUNDPARMS)); @@ -263,12 +276,12 @@ SOUNDPARMS spParms; spParms.uiLoop = ubLoops; spParms.uiPriority=GROUP_AMBIENT; - return(SoundPlay( gSteadyStateAmbientTable[ gubCurrentSteadyStateAmbience ].zSoundNames[ gubCurrentSteadyStateSound ], &spParms ) ); + return(SoundPlay(gSteadyStateAmbientTable[gubCurrentSteadyStateAmbience].zSoundNames[gubCurrentSteadyStateSound], &spParms)); } -BOOLEAN SetSteadyStateAmbience( UINT8 ubAmbience ) +BOOLEAN SetSteadyStateAmbience(UINT8 ubAmbience) { BOOLEAN fInNight = FALSE; INT32 cnt; @@ -276,44 +289,46 @@ BOOLEAN SetSteadyStateAmbience( UINT8 ubAmbience ) UINT8 ubChosenSound; // Stop all ambients... - if ( guiCurrentSteadyStateSoundHandle != NO_SAMPLE ) + if (guiCurrentSteadyStateSoundHandle != NO_SAMPLE) { - SoundStop( guiCurrentSteadyStateSoundHandle ); + SoundStop(guiCurrentSteadyStateSoundHandle); guiCurrentSteadyStateSoundHandle = NO_SAMPLE; } // Determine what time of day we are in ( day/night) - if( gubEnvLightValue >= LIGHT_DUSK_CUTOFF) + if (gubEnvLightValue >= LIGHT_DUSK_CUTOFF) { - fInNight = TRUE; + fInNight = TRUE; } // loop through listing to get num sounds... - for ( cnt = ( fInNight * 4 ); cnt < ( NUM_SOUNDS_PER_TIMEFRAME / 2 ); cnt++ ) + // 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; + if (gSteadyStateAmbientTable[ubAmbience].zSoundNames[cnt][0] == 0) + { + break; + } + + ubNumSounds++; } - ubNumSounds++; - } - - if ( ubNumSounds == 0 ) + if (ubNumSounds == 0) { - return( FALSE ); + return(FALSE); } // Pick one - ubChosenSound = (UINT8) Random( ubNumSounds ); + ubChosenSound = (UINT8)Random(ubNumSounds); // Set! gubCurrentSteadyStateAmbience = ubAmbience; - gubCurrentSteadyStateSound = ubChosenSound; + gubCurrentSteadyStateSound = ubChosenSound; - guiCurrentSteadyStateSoundHandle = StartSteadyStateAmbient( LOWVOLUME, 0 ); + guiCurrentSteadyStateSoundHandle = StartSteadyStateAmbient(LOWVOLUME, 0); - return( TRUE ); + return(TRUE); } void UpdateFireAmbient(void) @@ -419,3 +434,297 @@ void StartFireAmbient(void) //guiAmbientFire = SoundPlay( zFileName, &spParms ); guiAmbientFire = SoundPlayStreamedFile(filename, &spParms); } + +#define MAX_SSA_SOUNDS 10 + +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; + } + + // 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, "Sounds\\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, "Sounds\\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, "Sounds\\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 = gGameExternalOptions.ubVolumeSSA; // default is LOWVOLUME + spParms.uiLoop = 0; + spParms.uiPriority = GROUP_AMBIENT; + + //guiCurrentSteadyStateSoundHandle = SoundPlay( zFileName, &spParms ); + guiCurrentSteadyStateSoundHandle = SoundPlayStreamedFile(zFileName, &spParms); +} \ No newline at end of file diff --git a/TileEngine/Ambient Control.h b/TileEngine/Ambient Control.h index a793dc66..2668d25e 100644 --- a/TileEngine/Ambient Control.h +++ b/TileEngine/Ambient Control.h @@ -17,6 +17,7 @@ extern AMBIENTDATA_STRUCT gAmbData[ MAX_AMBIENT_SOUNDS ]; extern INT16 gsNumAmbData; BOOLEAN SetSteadyStateAmbience( UINT8 ubAmbience ); +void SetSSA(void); void UpdateFireAmbient(void); void StopFireAmbient(void); diff --git a/ext/VFS/src/Core/vfs_string.cpp b/ext/VFS/src/Core/vfs_string.cpp index 3f1fea84..0b894092 100644 --- a/ext/VFS/src/Core/vfs_string.cpp +++ b/ext/VFS/src/Core/vfs_string.cpp @@ -185,12 +185,17 @@ vfs::String::str_t vfs::String::as_utf16(const char* str) } void vfs::String::as_utf16(const char* str, vfs::String::str_t &str16) { + wchar_t buf16[1024]; + if(str == NULL) { return; } try { + memset(buf16, 0, 1024 * sizeof(wchar_t)); + mbstowcs(buf16, str, 1024 - 1); + ::size_t len = strlen(str); ::size_t d = utf8::distance(str,str+len); if(d > 0) @@ -202,7 +207,8 @@ void vfs::String::as_utf16(const char* str, vfs::String::str_t &str16) catch(utf8::invalid_utf8& ex) { utf8::uint8_t c = ex.utf8_octet(); - VFS_THROW( _BS(L"Invalid UTF8 character '") << (wchar_t)c << L"'=" << (unsigned char)c << _BS::wget ); + //VFS_THROW( _BS(L"Invalid UTF8 character '") << (wchar_t)c << L"'=" << (unsigned char)c << _BS::wget ); + VFS_THROW(_BS(L"Invalid UTF8 character '") << (wchar_t)c << L"'=" << (unsigned char)c << L" str16:" << buf16 << _BS::wget); } catch(utf8::not_enough_room &ex) { diff --git a/gameloop.cpp b/gameloop.cpp index 55e5fafe..d3524f4f 100644 --- a/gameloop.cpp +++ b/gameloop.cpp @@ -520,6 +520,9 @@ void SetPendingNewScreen( UINT32 uiNewScreen ) extern UINT32 guiRainLoop; // end rain +// sevenfm +extern UINT32 guiCurrentSteadyStateSoundHandle; + // Gets called when the screen changes, place any needed in code in here void HandleNewScreenChange( UINT32 uiNewScreen, UINT32 uiOldScreen ) { @@ -541,8 +544,23 @@ void HandleNewScreenChange( UINT32 uiNewScreen, UINT32 uiOldScreen ) } // end rain - if (uiNewScreen != MSG_BOX_SCREEN) + // sevenfm: start/stop SSA + if (uiNewScreen == GAME_SCREEN) { + // check that no sound is playing currently + if (guiCurrentSteadyStateSoundHandle == NO_SAMPLE) + { + SetSSA(); + } + } + else if (uiNewScreen != MSG_BOX_SCREEN) + { + // Stop SSA + if (guiCurrentSteadyStateSoundHandle != NO_SAMPLE) + { + SoundStop(guiCurrentSteadyStateSoundHandle); + guiCurrentSteadyStateSoundHandle = NO_SAMPLE; + } // stop ambients StopFireAmbient(); }