Files
source/TileEngine/Ambient Control.cpp
T
Marco Antonio J. Costaandmajcosta 86ad401186 add newline at end of file where it's lacking
.editorconfig already enforces it but it's getting changed piecemeal in
every commit. just get it done with.

the script:
```

find . -type f -not -path "./.git/*" -not -path "./.vs/*" | while read -r file; do
	isFile=$(file -0 "$file" | cut -d $'\0' -f2)
	case "$isFile" in
		(*text*)
			echo "$file is text"
			if [[ $(tail -c 1 "$file" | wc -l) -ne 1 ]]; then
				echo "" >> "$file"
			fi
			;;
		(*)
			echo "file isn't text"
			;;
	esac
done
```
2024-12-14 19:05:48 -03:00

725 lines
16 KiB
C++

#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_TOWNS][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 <Here> 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);
}