/*
===========================================================================
ARX FATALIS GPL Source Code
Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
.
In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
///////////////////////////////////////////////////////////////////////////////
//
// ARX_Sound.cpp
// ARX Sound Management
//
// Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
//
///////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include <../danae/arx_menu2.h>
#include
#include "eerieapp.h"
using namespace std;
#define _CRTDBG_MAP_ALLOC
#include
using namespace ATHENA;
extern long FINAL_RELEASE;
extern long EXTERNALVIEW;
extern INTERACTIVE_OBJ * CAMERACONTROLLER;
extern CMenuConfig * pMenuConfig;
typedef struct
{
char * name;
unsigned long variant_i;
unsigned long variant_c;
long * variant_l;
} ARX_SOUND_Material;
typedef struct
{
char * name;
unsigned long material_c;
ARX_SOUND_Material * material_l;
} ARX_SOUND_CollisionMap;
typedef struct
{
char * name;
long name_size;
float factor;
} ARX_SOUND_Presence;
enum ParseIniFileEnum
{
PARSE_INI_FILE_CONTINUE,
PARSE_INI_FILE_SKIP,
PARSE_INI_FILE_STOP
};
typedef unsigned long(* ParseIniFileCallback)(const char * lpszText);
static enum PlayingAmbianceType
{
PLAYING_AMBIANCE_MENU,
PLAYING_AMBIANCE_SCRIPT,
PLAYING_AMBIANCE_ZONE
};
typedef struct
{
char name[256];
float volume;
long loop;
long type;
} PlayingAmbiance;
static const unsigned long ARX_SOUND_UPDATE_INTERVAL(100);
static const unsigned long ARX_SOUND_STREAMING_LIMIT(2000);
static const unsigned long MAX_MATERIALS(17);
static const unsigned long MAX_VARIANTS(5);
static const unsigned long AMBIANCE_FADE_TIME(2000);
static const float ARX_SOUND_UNIT_FACTOR(0.01F);
static const float ARX_SOUND_ROLLOFF_FACTOR(1.3F);
static const float ARX_SOUND_DEFAULT_FALLSTART(200.0F);
static const float ARX_SOUND_DEFAULT_FALLEND(2200.0F);
static const float ARX_SOUND_REFUSE_DISTANCE(2500.0F);
static const char ARX_SOUND_PATH_INI[] = "localisation\\";
static const char ARX_SOUND_PATH_SAMPLE[] = "sfx\\";
static const char ARX_SOUND_PATH_AMBIANCE[] = "sfx\\ambiance\\";
static const char ARX_SOUND_PATH_ENVIRONMENT[] = "sfx\\environment\\";
static const char ARX_SOUND_PRESENCE_NAME[] = "presence";
static const char ARX_SOUND_FILE_EXTENSION_WAV[] = ".wav";
static const char ARX_SOUND_FILE_EXTENSION_INI[] = ".ini";
static const unsigned long ARX_SOUND_COLLISION_MAP_COUNT = 3;
static const char * ARX_SOUND_COLLISION_MAP_NAME[] =
{
"snd_armor",
"snd_step",
"snd_weapon"
};
static bool bIsActive(false);
static HANDLE hUpdateThread(NULL);
static bool bExitUpdateThread(false);
static long ambiance_zone(AAL_SFALSE);
static long ambiance_menu(AAL_SFALSE);
static long Inter_Materials[MAX_MATERIALS][MAX_MATERIALS][MAX_VARIANTS];
static unsigned long collision_map_c(0);
static ARX_SOUND_CollisionMap * collision_map_l = NULL;
static unsigned long presence_c(0);
static ARX_SOUND_Presence * presence_l = NULL;
// ARX mixers
long ARX_SOUND_MixerGame(AAL_SFALSE);
long ARX_SOUND_MixerGameSample(AAL_SFALSE);
long ARX_SOUND_MixerGameSpeech(AAL_SFALSE);
long ARX_SOUND_MixerGameAmbiance(AAL_SFALSE);
long ARX_SOUND_MixerMenu(AAL_SFALSE);
long ARX_SOUND_MixerMenuSample(AAL_SFALSE);
long ARX_SOUND_MixerMenuSpeech(AAL_SFALSE);
long ARX_SOUND_MixerMenuAmbiance(AAL_SFALSE);
// Menu ambiances
char AMB_MENU[] = "ambient_menu.amb";
char AMB_CREDITS[] = "ambient_credits.amb";
// Menu samples
long SND_MENU_CLICK(AAL_SFALSE);
long SND_MENU_CREDITS_LOOP(AAL_SFALSE);
long SND_MENU_LOOP(AAL_SFALSE);
long SND_MENU_OPTIONS_LOOP(AAL_SFALSE);
long SND_MENU_PUSH(AAL_SFALSE);
long SND_MENU_RELEASE(AAL_SFALSE);
// Interface samples
long SND_BACKPACK(AAL_SFALSE);
long SND_BOOK_OPEN(AAL_SFALSE);
long SND_BOOK_CLOSE(AAL_SFALSE);
long SND_BOOK_PAGE_TURN(AAL_SFALSE);
long SND_GOLD(AAL_SFALSE);
long SND_INVSTD(AAL_SFALSE);
long SND_MAP(AAL_SFALSE);
long SND_SCROLL_OPEN(AAL_SFALSE);
long SND_SCROLL_CLOSE(AAL_SFALSE);
long SND_TORCH_START(AAL_SFALSE);
long SND_TORCH_LOOP(AAL_SFALSE);
long SND_TORCH_END(AAL_SFALSE);
// Other SFX samples
long SND_FIREPLACE(AAL_SFALSE);
long SND_PLOUF(AAL_SFALSE);
long SND_QUAKE(AAL_SFALSE);
long SND_WHOOSH(AAL_SFALSE);
// Player samples
long SND_PLAYER_DEATH(AAL_SFALSE);
long SND_PLAYER_DEATH_BY_FIRE(AAL_SFALSE);
long SND_PLAYER_FILLLIFEMANA(AAL_SFALSE);
long SND_PLAYER_HEART_BEAT(AAL_SFALSE);
long SND_PLAYER_JUMP(AAL_SFALSE);
long SND_PLAYER_JUMP_END(AAL_SFALSE);
long SND_PLAYER_LEVEL_UP(AAL_SFALSE);
long SND_PLAYER_POISONED(AAL_SFALSE);
// Magic drawing samples
long SND_MAGIC_AMBIENT(AAL_SFALSE);
long SND_MAGIC_DRAW(AAL_SFALSE);
long SND_MAGIC_FIZZLE(AAL_SFALSE);
// Magic symbols samples
long SND_SYMB_AAM(AAL_SFALSE);
long SND_SYMB_CETRIUS(AAL_SFALSE);
long SND_SYMB_COSUM(AAL_SFALSE);
long SND_SYMB_COMUNICATUM(AAL_SFALSE);
long SND_SYMB_FOLGORA(AAL_SFALSE);
long SND_SYMB_FRIDD(AAL_SFALSE);
long SND_SYMB_KAOM(AAL_SFALSE);
long SND_SYMB_MEGA(AAL_SFALSE);
long SND_SYMB_MORTE(AAL_SFALSE);
long SND_SYMB_MOVIS(AAL_SFALSE);
long SND_SYMB_NHI(AAL_SFALSE);
long SND_SYMB_RHAA(AAL_SFALSE);
long SND_SYMB_SPACIUM(AAL_SFALSE);
long SND_SYMB_STREGUM(AAL_SFALSE);
long SND_SYMB_TAAR(AAL_SFALSE);
long SND_SYMB_TEMPUS(AAL_SFALSE);
long SND_SYMB_TERA(AAL_SFALSE);
long SND_SYMB_VISTA(AAL_SFALSE);
long SND_SYMB_VITAE(AAL_SFALSE);
long SND_SYMB_YOK(AAL_SFALSE);
// Spells samples
long SND_SPELL_ACTIVATE_PORTAL(AAL_SFALSE);
long SND_SPELL_ARMOR_START(AAL_SFALSE);
long SND_SPELL_ARMOR_END(AAL_SFALSE);
long SND_SPELL_ARMOR_LOOP(AAL_SFALSE);
long SND_SPELL_LOWER_ARMOR(AAL_SFALSE);
long SND_SPELL_BLESS(AAL_SFALSE);
long SND_SPELL_COLD_PROTECTION_START(AAL_SFALSE);
long SND_SPELL_COLD_PROTECTION_LOOP(AAL_SFALSE);
long SND_SPELL_COLD_PROTECTION_END(AAL_SFALSE);
long SND_SPELL_CONFUSE(AAL_SFALSE);
long SND_SPELL_CONTROL_TARGET(AAL_SFALSE);
long SND_SPELL_CREATE_FIELD(AAL_SFALSE);
long SND_SPELL_CREATE_FOOD(AAL_SFALSE);
long SND_SPELL_CURE_POISON(AAL_SFALSE);
long SND_SPELL_CURSE(AAL_SFALSE);
long SND_SPELL_DETECT_TRAP(AAL_SFALSE);
long SND_SPELL_DETECT_TRAP_LOOP(AAL_SFALSE);
long SND_SPELL_DISARM_TRAP(AAL_SFALSE);
long SND_SPELL_DISPELL_FIELD(AAL_SFALSE);
long SND_SPELL_DISPELL_ILLUSION(AAL_SFALSE);
long SND_SPELL_DOUSE(AAL_SFALSE);
long SND_SPELL_ELECTRIC(AAL_SFALSE);
long SND_SPELL_ENCHANT_WEAPON(AAL_SFALSE);
long SND_SPELL_EXPLOSION(AAL_SFALSE);
long SND_SPELL_EYEBALL_IN(AAL_SFALSE);
long SND_SPELL_EYEBALL_OUT(AAL_SFALSE);
long SND_SPELL_FIRE_FIELD(AAL_SFALSE);
long SND_SPELL_FIRE_HIT(AAL_SFALSE);
long SND_SPELL_FIRE_LAUNCH(AAL_SFALSE);
long SND_SPELL_FIRE_PROTECTION(AAL_SFALSE);
long SND_SPELL_FIRE_WIND(AAL_SFALSE);
long SND_SPELL_FREEZETIME(AAL_SFALSE);
long SND_SPELL_HARM(AAL_SFALSE);
long SND_SPELL_HEALING(AAL_SFALSE);
long SND_SPELL_ICE_FIELD(AAL_SFALSE);
long SND_SPELL_ICE_PROJECTILE_LAUNCH(AAL_SFALSE);
long SND_SPELL_INCINERATE(AAL_SFALSE);
long SND_SPELL_IGNITE(AAL_SFALSE);
long SND_SPELL_INVISIBILITY_START(AAL_SFALSE);
long SND_SPELL_INVISIBILITY_END(AAL_SFALSE);
long SND_SPELL_LEVITATE_START(AAL_SFALSE);
long SND_SPELL_LIGHTNING_START(AAL_SFALSE);
long SND_SPELL_LIGHTNING_LOOP(AAL_SFALSE);
long SND_SPELL_LIGHTNING_END(AAL_SFALSE);
long SND_SPELL_MAGICAL_HIT(AAL_SFALSE);
long SND_SPELL_MASS_LIGHTNING_END(AAL_SFALSE);
long SND_SPELL_FIRE_FIELD_START(AAL_SFALSE);
long SND_SPELL_FIRE_FIELD_LOOP(AAL_SFALSE);
long SND_SPELL_FIRE_FIELD_END(AAL_SFALSE);
long SND_SPELL_MAGICAL_SHIELD(AAL_SFALSE);
long SND_SPELL_MASS_INCINERATE(AAL_SFALSE);
long SND_SPELL_MASS_PARALYSE(AAL_SFALSE);
long SND_SPELL_MM_CREATE(AAL_SFALSE);
long SND_SPELL_MM_HIT(AAL_SFALSE);
long SND_SPELL_MM_LAUNCH(AAL_SFALSE);
long SND_SPELL_MM_LOOP(AAL_SFALSE);
long SND_SPELL_NEGATE_MAGIC(AAL_SFALSE);
long SND_SPELL_NO_EFFECT(AAL_SFALSE);
long SND_SPELL_PARALYSE(AAL_SFALSE);
long SND_SPELL_PARALYSE_END(AAL_SFALSE);
long SND_SPELL_POISON_PROJECTILE_LAUNCH(AAL_SFALSE);
long SND_SPELL_RAISE_DEAD(AAL_SFALSE);
long SND_SPELL_REPEL_UNDEAD(AAL_SFALSE);
long SND_SPELL_REPEL_UNDEAD_LOOP(AAL_SFALSE);
long SND_SPELL_RUNE_OF_GUARDING(AAL_SFALSE);
long SND_SPELL_SLOW_DOWN(AAL_SFALSE);
long SND_SPELL_SPARK(AAL_SFALSE);
long SND_SPELL_SPEED_START(AAL_SFALSE);
long SND_SPELL_SPEED_LOOP(AAL_SFALSE);
long SND_SPELL_SPEED_END(AAL_SFALSE);
long SND_SPELL_SUMMON_CREATURE(AAL_SFALSE);
long SND_SPELL_TELEKINESIS_START(AAL_SFALSE);
long SND_SPELL_TELEKINESIS_END(AAL_SFALSE);
long SND_SPELL_TELEPORT(AAL_SFALSE);
long SND_SPELL_TELEPORTED(AAL_SFALSE);
long SND_SPELL_VISION_START(AAL_SFALSE);
long SND_SPELL_VISION_LOOP(AAL_SFALSE);
bool bForceNoEAX = false;
static void ARX_SOUND_CreateEnvironment();
static void ARX_SOUND_CreateEnvironments();
static void ARX_SOUND_CreateStaticSamples();
static void ARX_SOUND_ReleaseStaticSamples();
static void ARX_SOUND_LoadCollision(const long & mat1, const long & mat2, const char * name);
static void ARX_SOUND_CreateCollisionMap(const char * file_name);
static void ARX_SOUND_CreateCollisionMaps();
static void ARX_SOUND_DeleteCollisionMaps();
static void ARX_SOUND_CreateMaterials();
static void ARX_SOUND_CreatePresenceMap();
static void ARX_SOUND_DeletePresenceMap();
static float GetSamplePresenceFactor(const char * name);
LPTHREAD_START_ROUTINE UpdateSoundThread(char *);
static void ARX_SOUND_LaunchUpdateThread();
static void ARX_SOUND_KillUpdateThread();
static void ARX_SOUND_ParseIniFile(char * _lpszTextFile, const unsigned long _ulFileSize, ParseIniFileCallback lpSectionCallback, ParseIniFileCallback lpStringCallback);
void ARX_SOUND_PreloadAll();
extern char pStringModSfx[];
extern char pStringModSpeech[];
long ARX_SOUND_Init(HWND hwnd)
{
if (bIsActive) ARX_SOUND_Release();
if ((bForceNoEAX) ||
(pMenuConfig && (!pMenuConfig->bEAX)))
{
if (aalInitForceNoEAX(hwnd) || aalEnable(AAL_FLAG_MULTITHREAD))
{
aalClean();
return -1;
}
}
else
{
if (aalInit(hwnd) || aalEnable(AAL_FLAG_MULTITHREAD))
{
aalClean();
return -1;
}
}
if (aalSetRootPath(Project.workingdir) ||
aalSetSamplePath(ARX_SOUND_PATH_SAMPLE) ||
aalSetAmbiancePath(ARX_SOUND_PATH_AMBIANCE) ||
aalSetEnvironmentPath(ARX_SOUND_PATH_ENVIRONMENT))
{
aalClean();
return -1;
}
// Create game mixers
ARX_SOUND_MixerGame = aalCreateMixer();
ARX_SOUND_MixerGameSample = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerGameSample, ARX_SOUND_MixerGame);
ARX_SOUND_MixerGameSpeech = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerGameSpeech, ARX_SOUND_MixerGame);
ARX_SOUND_MixerGameAmbiance = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerGameAmbiance, ARX_SOUND_MixerGame);
// Create menu mixers
ARX_SOUND_MixerMenu = aalCreateMixer();
ARX_SOUND_MixerMenuSample = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerMenuSample, ARX_SOUND_MixerMenu);
ARX_SOUND_MixerMenuSpeech = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerMenuSpeech, ARX_SOUND_MixerMenu);
ARX_SOUND_MixerMenuAmbiance = aalCreateMixer();
aalSetMixerParent(ARX_SOUND_MixerMenuAmbiance, ARX_SOUND_MixerMenu);
if ((ARX_SOUND_MixerGame == AAL_SFALSE) ||
(ARX_SOUND_MixerGameSample == AAL_SFALSE) ||
(ARX_SOUND_MixerGameSpeech == AAL_SFALSE) ||
(ARX_SOUND_MixerGameAmbiance == AAL_SFALSE) ||
(ARX_SOUND_MixerMenu == AAL_SFALSE) ||
(ARX_SOUND_MixerMenuSample == AAL_SFALSE) ||
(ARX_SOUND_MixerMenuSpeech == AAL_SFALSE) ||
(ARX_SOUND_MixerMenuAmbiance == AAL_SFALSE))
{
aalClean();
return -1;
}
// Standard Mixer: 22050 16 Stereo
aalFormat af;
af.frequency = 22050;
af.quality = 16;
af.channels = 2;
aalSetOutputFormat(af);
// Enable 3D positionning system
aalEnable(AAL_FLAG_POSITION);
aalSetStreamLimit(ARX_SOUND_STREAMING_LIMIT);
aalSetListenerUnitFactor(ARX_SOUND_UNIT_FACTOR);
aalSetListenerRolloffFactor(ARX_SOUND_ROLLOFF_FACTOR);
if (FINAL_RELEASE)
{
char pakfile[256];
aalEnable(AAL_FLAG_PACKEDRESOURCES);
if (pStringModSfx[0])
{
sprintf(pakfile, "%s%s", Project.workingdir, pStringModSfx);
if (FileExist(pakfile)) aalAddResourcePack(pakfile);
}
if (pStringModSpeech[0])
{
sprintf(pakfile, "%s%s", Project.workingdir, pStringModSpeech);
if (FileExist(pakfile)) aalAddResourcePack(pakfile);
}
sprintf(pakfile, "%ssfx.pak", Project.workingdir);
if (FileExist(pakfile)) aalAddResourcePack(pakfile);
else
{
MessageBox(NULL, "Unable to Find Data File\nPlease Reinstall ARX Fatalis", "Arx Fatalis - Error", MB_ICONEXCLAMATION | MB_OK);
exit(0);
}
sprintf(pakfile, "%sspeech.pak", Project.workingdir);
if (FileExist(pakfile))
{
aalAddResourcePack(pakfile);
}
else
{
sprintf(pakfile, "%sspeech_default.pak", Project.workingdir);
if (FileExist(pakfile))
{
aalAddResourcePack(pakfile);
}
else
{
MessageBox(NULL, "Unable to Find Data File\nPlease Reinstall ARX Fatalis", "Arx Fatalis - Error", MB_ICONEXCLAMATION | MB_OK);
exit(0);
}
}
}
// Load samples
ARX_SOUND_CreateStaticSamples();
ARX_SOUND_CreateMaterials();
ARX_SOUND_CreateCollisionMaps();
ARX_SOUND_CreatePresenceMap();
// Load environments, enable environment system and set default one if required
ARX_SOUND_CreateEnvironments();
if (Project.soundmode & ARX_SOUND_REVERB)
{
aalEnable(AAL_FLAG_REVERBERATION);
ARX_SOUND_EnvironmentSet("alley.aef");
}
ARX_SOUND_LaunchUpdateThread();
bIsActive = true;
ARX_SOUND_PreloadAll();
return 0;
}
void ARX_SOUND_PreloadAll()
{
}
void ARX_SOUND_Release()
{
ARX_SOUND_ReleaseStaticSamples();
ARX_SOUND_DeleteCollisionMaps();
ARX_SOUND_DeletePresenceMap();
ARX_SOUND_KillUpdateThread();
aalClean();
bIsActive = false;
Project.soundmode &= ~(ARX_SOUND_ON | ARX_SOUND_REVERB);
}
long ARX_SOUND_IsEnabled()
{
return bIsActive ? 1 : 0;
}
void ARX_SOUND_EnableReverb(const long & status)
{
if (bIsActive)
{
if (status)
{
if (aalEnable(AAL_FLAG_REVERBERATION))
Project.soundmode &= ~ARX_SOUND_REVERB;
else
Project.soundmode |= ARX_SOUND_REVERB;
}
else
{
aalDisable(AAL_FLAG_REVERBERATION);
Project.soundmode &= ~ARX_SOUND_REVERB;
}
}
}
long ARX_SOUND_IsReverbEnabled()
{
if (!bIsActive) return 0;
return aalIsEnabled(AAL_FLAG_REVERBERATION);
}
void ARX_SOUND_MixerSetVolume(const long & mixer_id, const float & volume)
{
if (bIsActive) aalSetMixerVolume(mixer_id, volume);
}
float ARX_SOUND_MixerGetVolume(const long & mixer_id)
{
float volume(0.0F);
if (bIsActive) aalGetMixerVolume(mixer_id, &volume);
return volume;
}
void ARX_SOUND_MixerStop(const long & mixer_id)
{
if (bIsActive) aalMixerStop(mixer_id);
}
void ARX_SOUND_MixerPause(const long & mixer_id)
{
if (bIsActive) aalMixerPause(mixer_id);
}
void ARX_SOUND_MixerResume(const long & mixer_id)
{
if (bIsActive) aalMixerResume(mixer_id);
}
void ARX_SOUND_MixerSwitch(const long & from, const long & to)
{
ARX_SOUND_MixerPause(from);
ARX_SOUND_MixerSetVolume(to, ARX_SOUND_MixerGetVolume(from));
ARX_SOUND_MixerSetVolume(to, ARX_SOUND_MixerGetVolume(from));
ARX_SOUND_MixerSetVolume(to, ARX_SOUND_MixerGetVolume(from));
ARX_SOUND_MixerResume(to);
}
// Sets the position of the listener
void ARX_SOUND_SetListener(const EERIE_3D * position, const EERIE_3D * front, const EERIE_3D * up)
{
if (bIsActive)
{
aalSetListenerPosition(*(aalVector *)position);
aalSetListenerDirection(*(aalVector *)front, *(aalVector *)up);
}
}
void ARX_SOUND_EnvironmentSet(const char * name)
{
if (bIsActive)
{
aalSLong e_id(aalGetEnvironment(name));
if (e_id != AAL_SFALSE)
{
aalSetListenerEnvironment(e_id);
aalSetEnvironmentRolloffFactor(e_id, ARX_SOUND_ROLLOFF_FACTOR);
}
}
}
long ARX_SOUND_PlaySFX(long & sample_id, const EERIE_3D * position, const float & pitch, const long & loop)
{
if (!bIsActive || sample_id == AAL_SFALSE) return AAL_SFALSE;
aalChannel channel;
char sample_name[256];
float presence;
channel.mixer = ARX_SOUND_MixerGameSample;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_FALLOFF;
channel.volume = 1.0F;
if (position)
{
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, position) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
}
aalGetSampleName(sample_id, sample_name);
presence = GetSamplePresenceFactor(sample_name);
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
if (pitch != 1.0F)
{
channel.flags |= AAL_FLAG_PITCH;
channel.pitch = pitch;
}
if (position)
{
channel.position.x = position->x;
channel.position.y = position->y;
channel.position.z = position->z;
}
else
{
channel.flags |= AAL_FLAG_RELATIVE;
channel.position.x = 0.0F;
channel.position.y = 0.0F;
channel.position.z = 1.0F;
}
aalSamplePlay(sample_id, channel, loop);
return sample_id;
}
long ARX_SOUND_PlayInterface(long & sample_id, const float & pitch, const long & loop)
{
if (!bIsActive || sample_id == AAL_SFALSE) return AAL_SFALSE;
aalChannel channel;
channel.mixer = ARX_SOUND_MixerGameSample;
channel.flags = AAL_FLAG_VOLUME;
channel.volume = 1.0F;
if (pitch != 1.0F) channel.flags |= AAL_FLAG_PITCH, channel.pitch = pitch;
aalSamplePlay(sample_id, channel, loop);
return sample_id;
}
long ARX_SOUND_PlayMenu(long & sample_id, const float & pitch, const long & loop)
{
if (!bIsActive || sample_id == AAL_SFALSE) return AAL_SFALSE;
aalChannel channel;
channel.mixer = ARX_SOUND_MixerMenuSample;
channel.flags = AAL_FLAG_VOLUME;
channel.volume = 1.0F;
if (pitch != 1.0F) channel.flags |= AAL_FLAG_PITCH, channel.pitch = pitch;
aalSamplePlay(sample_id, channel, loop);
return sample_id;
}
void ARX_SOUND_IOFrontPos(const INTERACTIVE_OBJ * io, aalVector & pos)
{
if (io)
{
pos.x = io->pos.x - EEsin(DEG2RAD(MAKEANGLE(io->angle.b))) * 100.0F;
pos.y = io->pos.y - 100.0F;
pos.z = io->pos.z + EEcos(DEG2RAD(MAKEANGLE(io->angle.b))) * 100.0F;
}
else if (ACTIVECAM)
{
pos.x = ACTIVECAM->pos.x - EEsin(DEG2RAD(MAKEANGLE(ACTIVECAM->angle.b))) * 100.0F;
pos.y = ACTIVECAM->pos.y - 100.0F;
pos.z = ACTIVECAM->pos.z + EEcos(DEG2RAD(MAKEANGLE(ACTIVECAM->angle.b))) * 100.0F;
}
else
{
Vector_Init((EERIE_3D *)&pos);
}
}
long ARX_SOUND_PlaySpeech(const char * name, const INTERACTIVE_OBJ * io)
{
if (!bIsActive) return AAL_SFALSE;
char file_name[256];
aalChannel channel;
aalSLong sample_id;
sprintf(file_name, "speech\\%s\\%s.wav", Project.localisationpath, name);
sample_id = aalCreateSample(file_name);
channel.mixer = ARX_SOUND_MixerGameSpeech;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_AUTOFREE | AAL_FLAG_FALLOFF;
channel.volume = 1.0F;
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
if (io)
{
if (((io == inter.iobj[0]) && !EXTERNALVIEW) ||
(io->ioflags & IO_CAMERA && io == CAMERACONTROLLER))
ARX_SOUND_IOFrontPos(io, channel.position);
else
{
channel.position.x = io->pos.x;
channel.position.y = io->pos.y;
channel.position.z = io->pos.z;
}
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, &io->pos) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
if (io->ioflags & IO_NPC && io->_npcdata->speakpitch != 1.0F)
{
channel.flags |= AAL_FLAG_PITCH;
channel.pitch = io->_npcdata->speakpitch;
}
}
else
{
channel.flags |= AAL_FLAG_RELATIVE;
channel.position.x = 0.0F;
channel.position.y = 0.0F;
channel.position.z = 100.0F;
}
aalSamplePlay(sample_id, channel);
return sample_id;
}
long ARX_SOUND_PlayCollision(const long & mat1, const long & mat2, const float & volume, const float & power, EERIE_3D * position, INTERACTIVE_OBJ * source)
{
if (!bIsActive) return 0;
if (mat1 == MATERIAL_NONE || mat2 == MATERIAL_NONE) return 0;
if (mat1 == MATERIAL_WATER || mat2 == MATERIAL_WATER)
ARX_PARTICLES_SpawnWaterSplash(position);
long sample_id;
sample_id = Inter_Materials[mat1][mat2][0];
if (sample_id == AAL_SFALSE) return 0;
aalChannel channel;
char sample_name[256];
float presence;
channel.mixer = ARX_SOUND_MixerGameSample;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_PITCH | AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_FALLOFF;
aalGetSampleName(sample_id, sample_name);
presence = GetSamplePresenceFactor(sample_name);
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
if (position)
{
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, position) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
}
//Launch 'ON HEAR' script event
ARX_NPC_SpawnAudibleSound(position, source, power, presence);
if (position)
{
channel.position.x = position->x;
channel.position.y = position->y;
channel.position.z = position->z;
}
else ARX_PLAYER_FrontPos((EERIE_3D *)&channel.position);
channel.pitch = 0.9F + 0.2F * rnd();
channel.volume = volume;
aalSamplePlay(sample_id, channel);
unsigned long length;
aalGetSampleLength(sample_id, length);
return (long)(channel.pitch * length);
}
long ARX_SOUND_PlayCollision(const char * name1, const char * name2, const float & volume, const float & power, EERIE_3D * position, INTERACTIVE_OBJ * source)
{
if (!bIsActive) return 0;
if (!name1 || !name2) return 0;
if (stricmp(name2, "WATER") == 0)
ARX_PARTICLES_SpawnWaterSplash(position);
for (unsigned long i(0); i < collision_map_c; i++)
{
ARX_SOUND_CollisionMap * c_map = &collision_map_l[i];
if (!stricmp(name1, c_map->name))
for (unsigned long j(0); j < c_map->material_c; j++)
{
ARX_SOUND_Material * c_material = &c_map->material_l[j];
if (!stricmp(name2, c_material->name))
{
long sample_id;
sample_id = c_material->variant_l[c_material->variant_i];
if (++c_material->variant_i >= c_material->variant_c) c_material->variant_i = 0;
if (sample_id == AAL_SFALSE)
return 0;
aalChannel channel;
channel.mixer = ARX_SOUND_MixerGameSample;
char sample_name[256];
float presence;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_PITCH | AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_FALLOFF;
aalGetSampleName(sample_id, sample_name);
presence = GetSamplePresenceFactor(sample_name);
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
//Launch 'ON HEAR' script event
ARX_NPC_SpawnAudibleSound(position, source, power, presence);
if (position)
{
channel.position.x = position->x;
channel.position.y = position->y;
channel.position.z = position->z;
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, position) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
}
else
ARX_PLAYER_FrontPos((EERIE_3D *)&channel.position);
channel.pitch = 0.975F + 0.5F * rnd();
channel.volume = volume;
aalSamplePlay(sample_id, channel);
unsigned long length;
aalGetSampleLength(sample_id, length);
return (long)(channel.pitch * length);
}
}
}
return 0;
}
long ARX_SOUND_PlayScript(const char * name, const INTERACTIVE_OBJ * io, const float & pitch, const long & loop)
{
if (!bIsActive) return AAL_SFALSE;
aalChannel channel;
long sample_id;
sample_id = aalCreateSample(name);
if (sample_id == AAL_SFALSE) return AAL_SFALSE;
channel.mixer = ARX_SOUND_MixerGameSample;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_AUTOFREE | AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_FALLOFF;
channel.volume = 1.0F;
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * GetSamplePresenceFactor(name);
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
if (io)
{
GetItemWorldPositionSound((INTERACTIVE_OBJ *)io, (EERIE_3D *)&channel.position);
if (loop != ARX_SOUND_PLAY_LOOPED)
{
EERIE_3D ePos;
ePos.x = channel.position.x;
ePos.y = channel.position.y;
ePos.z = channel.position.z;
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, &ePos) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
}
}
else
{
channel.flags |= AAL_FLAG_RELATIVE;
channel.position.x = 0.0F;
channel.position.y = 0.0F;
channel.position.z = 100.0F;
}
if (pitch != 1.0F)
{
channel.flags |= AAL_FLAG_PITCH;
channel.pitch = pitch;
}
aalSamplePlay(sample_id, channel, loop);
return sample_id;
}
long ARX_SOUND_PlayAnim(long & sample_id, const EERIE_3D * position)
{
if (!bIsActive || sample_id == AAL_SFALSE) return AAL_SFALSE;
aalChannel channel;
channel.mixer = ARX_SOUND_MixerGameSample;
channel.flags = AAL_FLAG_VOLUME;
channel.volume = 1.0F;
if (position)
{
char sample_name[256];
float presence;
channel.flags |= AAL_FLAG_POSITION | AAL_FLAG_REVERBERATION | AAL_FLAG_FALLOFF;
aalGetSampleName(sample_id, sample_name);
presence = GetSamplePresenceFactor(sample_name);
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
channel.position.x = position->x;
channel.position.y = position->y;
channel.position.z = position->z;
}
if (ACTIVECAM && EEDistance3D(&ACTIVECAM->pos, position) > ARX_SOUND_REFUSE_DISTANCE)
return -1;
aalSamplePlay(sample_id, channel);
return sample_id;
}
long ARX_SOUND_PlayCinematic(const char * name)
{
long sample_id;
aalChannel channel;
sample_id = aalCreateSample(name);
if (sample_id == AAL_SFALSE) return AAL_SFALSE;
channel.mixer = ARX_SOUND_MixerGameSpeech;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_AUTOFREE | AAL_FLAG_POSITION | AAL_FLAG_FALLOFF | AAL_FLAG_REVERBERATION | AAL_FLAG_POSITION;
channel.volume = 1.0F;
channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART;
channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
if (ACTIVECAM)
{
EERIE_3D front, up;
float t;
t = DEG2RAD(MAKEANGLE(ACTIVECAM->angle.b));
front.x = -EEsin(t);
front.y = 0.f;
front.z = EEcos(t);
TRUEVector_Normalize(&front);
up.x = 0.f;
up.y = 1.f;
up.z = 0.f;
ARX_SOUND_SetListener(&ACTIVECAM->pos, &front, &up);
}
ARX_SOUND_IOFrontPos(NULL, channel.position);
aalSamplePlay(sample_id, channel);
return sample_id;
}
long ARX_SOUND_IsPlaying(long & sample_id)
{
return bIsActive ? aalIsSamplePlaying(sample_id) : 0;
}
float ARX_SOUND_GetDuration(long & sample_id)
{
if (bIsActive && sample_id != AAL_SFALSE)
{
aalULong length;
aalGetSampleLength(sample_id, length);
return ARX_CLEAN_WARN_CAST_FLOAT(length);
}
return 0.f;
}
void ARX_SOUND_RefreshVolume(long & sample_id, const float & volume)
{
if (bIsActive && sample_id != AAL_SFALSE)
aalSetSampleVolume(sample_id, volume);
}
void ARX_SOUND_RefreshPitch(long & sample_id, const float & pitch)
{
if (bIsActive && sample_id != AAL_SFALSE)
aalSetSamplePitch(sample_id, pitch);
}
void ARX_SOUND_RefreshPosition(long & sample_id, const EERIE_3D * position)
{
if (bIsActive && sample_id != AAL_SFALSE)
{
if (position)
aalSetSamplePosition(sample_id, *(aalVector *)position);
else
{
EERIE_3D pos;
ARX_PLAYER_FrontPos(&pos);
aalSetSamplePosition(sample_id, *(aalVector *)&pos);
}
}
}
void ARX_SOUND_RefreshSpeechPosition(long & sample_id, const INTERACTIVE_OBJ * io)
{
if (!bIsActive || !io || sample_id == AAL_SFALSE) return;
aalVector position;
if (io)
{
if (((io == inter.iobj[0]) && !EXTERNALVIEW) ||
(io->ioflags & IO_CAMERA && io == CAMERACONTROLLER))
{
ARX_SOUND_IOFrontPos(io, position);
}
else
{
position.x = io->pos.x;
position.y = io->pos.y;
position.z = io->pos.z;
}
}
aalSetSamplePosition(sample_id, position);
}
long ARX_SOUND_Load(const char * name)
{
if (!bIsActive) return AAL_SFALSE;
char sample_name[256];
sprintf(sample_name, "%s%s", name, ARX_SOUND_FILE_EXTENSION_WAV);
return aalCreateSample(sample_name);
}
void ARX_SOUND_Free(const long & sample)
{
if (!bIsActive || sample == ARX_SOUND_INVALID_RESOURCE) return;
aalDeleteSample(sample);
}
void ARX_SOUND_Stop(long & sample_id)
{
if (bIsActive && sample_id != AAL_SFALSE) aalSampleStop(sample_id);
}
long ARX_SOUND_PlayScriptAmbiance(const char * name, const long & loop, const float & volume) //, const EERIE_3D *position)
{
if (!bIsActive) return AAL_SFALSE;
char temp[512];
strcpy(temp, name);
SetExt(temp, ".amb");
long ambiance_id(aalGetAmbiance(temp));
if (ambiance_id == AAL_SFALSE)
{
if (volume == 0.0F) return AAL_SFALSE;
ambiance_id = aalCreateAmbiance(temp);
aalSetAmbianceUserData(ambiance_id, (void *)PLAYING_AMBIANCE_SCRIPT);
aalChannel channel;
channel.mixer = ARX_SOUND_MixerGameAmbiance;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_AUTOFREE;
channel.volume = volume;
aalAmbiancePlay(ambiance_id, channel, loop);
}
else
{
if (volume <= 0.0F)
{
aalDeleteAmbiance(ambiance_id);
return AAL_SFALSE;
}
aalSetAmbianceVolume(ambiance_id, volume);
}
return ambiance_id;
}
long ARX_SOUND_PlayZoneAmbiance(const char * name, const long & loop, const float & volume)
{
if (!bIsActive) return AAL_SFALSE;
char temp[512];
strcpy(temp, name);
SetExt(temp, ".amb");
if (!stricmp(name, "NONE"))
{
aalAmbianceStop(ambiance_zone, AMBIANCE_FADE_TIME);
ambiance_zone = AAL_SFALSE;
return AAL_SFALSE;
}
long ambiance_id(aalGetAmbiance(temp));
if (ambiance_id == AAL_SFALSE)
{
ambiance_id = aalCreateAmbiance(temp);
aalSetAmbianceUserData(ambiance_id, (void *)PLAYING_AMBIANCE_ZONE);
}
else if (ambiance_id == ambiance_zone)
return ambiance_zone;
aalChannel channel;
channel.mixer = ARX_SOUND_MixerGameAmbiance;
channel.flags = AAL_FLAG_VOLUME | AAL_FLAG_AUTOFREE;
channel.volume = volume;
aalAmbianceStop(ambiance_zone, AMBIANCE_FADE_TIME);
aalAmbiancePlay(ambiance_zone = ambiance_id, channel, loop, AMBIANCE_FADE_TIME);
return ambiance_zone;
}
long ARX_SOUND_SetAmbianceTrackStatus(const char * ambiance_name, const char * track_name, const unsigned long & status)
{
if (!bIsActive || !ambiance_name) return AAL_SFALSE;
long ambiance_id, track_id;
char temp[512];
strcpy(temp, ambiance_name);
sprintf(temp, "%s", ambiance_name);
SetExt(temp, ".amb");
ambiance_id = aalGetAmbiance(temp);
if (ambiance_id == AAL_SFALSE) return AAL_SFALSE;
if (aalGetAmbianceTrackID(ambiance_id, track_name, track_id)) return AAL_SFALSE;
aalMuteAmbianceTrack(ambiance_id, track_id, (aalUBool)status);
return ambiance_id;
}
void ARX_SOUND_KillAmbiances()
{
if (!bIsActive) return;
aalSLong ambiance_id = aalGetAmbiance();
while (ambiance_id != AAL_SFALSE)
{
aalDeleteAmbiance(ambiance_id);
ambiance_id = aalGetAmbiance();
}
ambiance_zone = AAL_SFALSE;
}
long ARX_SOUND_PlayMenuAmbiance(const char * ambiance_name)
{
if (!bIsActive) return AAL_SFALSE;
aalDeleteAmbiance(ambiance_menu);
ambiance_menu = aalCreateAmbiance(ambiance_name);
aalSetAmbianceUserData(ambiance_menu, (void *)PLAYING_AMBIANCE_MENU);
aalChannel channel;
channel.mixer = ARX_SOUND_MixerMenuAmbiance;
channel.flags = AAL_FLAG_VOLUME;
channel.volume = 1.0F;
aalAmbiancePlay(ambiance_menu, channel, 0);
return ambiance_menu;
}
long nbelems = 0;
char ** elems = NULL;
long * numbers = NULL;
void ARX_SOUND_FreeAnimSamples()
{
if (elems)
{
for (long i = 0; i < nbelems; i++)
{
if (elems[i])
{
free(elems[i]);
elems[i] = NULL;
}
}
free(elems);
elems = NULL;
}
if (numbers)
{
free(numbers);
numbers = NULL;
}
nbelems = 0;
}
#define MAX_ANIMATIONS 900
extern ANIM_HANDLE animations[];
void ARX_SOUND_PushAnimSamples()
{
ARX_SOUND_FreeAnimSamples();
long number = 0;
for (long i = 0; i < MAX_ANIMATIONS; i++)
{
if (animations[i].path[0])
{
for (long j = 0; j < animations[i].alt_nb; j++)
{
EERIE_ANIM * anim = animations[i].anims[j];
for (long k = 0; k < anim->nb_key_frames; k++)
{
number++;
if (anim->frames[k].sample != -1)
{
char dest[256];
aalGetSampleName(anim->frames[k].sample, dest);
if (dest[0])
{
elems = (char **)realloc(elems, sizeof(char *) * (nbelems + 1));
elems[nbelems] = strdup(dest);
numbers = (long *)realloc(numbers, sizeof(long) * (nbelems + 1));
numbers[nbelems] = number;
nbelems++;
}
}
}
}
}
}
}
void ARX_SOUND_PopAnimSamples()
{
if ((!elems) ||
(!bIsActive))
{
return;
}
long curelem = 0;
long number = 0;
for (long i = 0; i < MAX_ANIMATIONS; i++)
{
if (animations[i].path[0])
{
for (long j = 0; j < animations[i].alt_nb; j++)
{
EERIE_ANIM * anim = animations[i].anims[j];
for (long k = 0; k < anim->nb_key_frames; k++)
{
number++;
if (number == numbers[curelem])
{
anim->frames[k].sample = aalCreateSample(elems[curelem++]);
}
}
}
}
}
ARX_SOUND_FreeAnimSamples();
}
void ARX_SOUND_AmbianceSavePlayList(void ** _play_list, unsigned long * size)
{
unsigned long count(0);
PlayingAmbiance * play_list = NULL;
long ambiance_id(AAL_SFALSE);
ambiance_id = aalGetNextAmbiance();
while (ambiance_id != AAL_SFALSE)
{
long type;
aalGetAmbianceUserData(ambiance_id, (void **)&type);
if (type == PLAYING_AMBIANCE_SCRIPT || type == PLAYING_AMBIANCE_ZONE)
{
void * ptr;
PlayingAmbiance * playing;
ptr = realloc(play_list, (count + 1) * sizeof(PlayingAmbiance));
if (!ptr) break;
play_list = (PlayingAmbiance *)ptr;
playing = &play_list[count];
aalGetAmbianceName(ambiance_id, playing->name);
aalGetAmbianceVolume(ambiance_id, playing->volume);
playing->loop = aalIsAmbianceLooped(ambiance_id) ? ARX_SOUND_PLAY_LOOPED : ARX_SOUND_PLAY_ONCE;
playing->type = type;
count++;
}
ambiance_id = aalGetNextAmbiance(ambiance_id);
}
*_play_list = play_list;
*size = count * sizeof(PlayingAmbiance);
}
void ARX_SOUND_AmbianceRestorePlayList(void * _play_list, unsigned long size)
{
unsigned long count = size / sizeof(PlayingAmbiance);
PlayingAmbiance * play_list = (PlayingAmbiance *)_play_list;
for (unsigned long i(0); i < count; i++)
{
PlayingAmbiance * playing = &play_list[i];
switch (playing->type)
{
case PLAYING_AMBIANCE_SCRIPT :
ARX_SOUND_PlayScriptAmbiance(playing->name, playing->loop, playing->volume);
break;
case PLAYING_AMBIANCE_ZONE :
ARX_SOUND_PlayZoneAmbiance(playing->name, playing->loop, playing->volume);
break;
}
}
}
// PâBôMéJèMçA
extern PakManager * pPakManager;
static void ARX_SOUND_CreateEnvironments()
{
if (FINAL_RELEASE)
{
vector *pvDirectory = NULL;
char lpszPakPath[512] = "";
sprintf(lpszPakPath, "%ssfx.pak", Project.workingdir);
if (!pPakManager) pPakManager = new PakManager;
if (!pPakManager->AddPak(lpszPakPath)) return;
pvDirectory = pPakManager->ExistDirectory((char *)ARX_SOUND_PATH_ENVIRONMENT);
if (!pvDirectory)
{
pPakManager->RemovePak(lpszPakPath);
return;
}
vector::iterator iv;
for (iv = pvDirectory->begin(); iv < pvDirectory->end(); iv++)
{
int nb = (*iv)->nbfiles;
EVE_TFILE * et = (*iv)->fichiers;
while (nb--)
{
aalCreateEnvironment((const char *)et->name);
et = et->fnext;
}
}
pPakManager->RemovePak(lpszPakPath);
pvDirectory->clear();
delete pvDirectory;
}
else
{
char path[512] = "";
_finddata_t fdata;
long fhandle;
sprintf(path, "%ssfx\\environment\\*.aef", Project.workingdir);
if ((fhandle = _findfirst(path, &fdata)) != -1)
{
do
{
aalCreateEnvironment(fdata.name);
}
while (_findnext(fhandle, &fdata));
_findclose(fhandle);
}
}
}
static void ARX_SOUND_CreateStaticSamples()
{
// Interface
SND_BACKPACK = aalCreateSample("interface_backpack.wav");
SND_MAP = aalCreateSample("interface_map.wav");
SND_BOOK_OPEN = aalCreateSample("book_open.wav");
SND_BOOK_CLOSE = aalCreateSample("book_close.wav");
SND_BOOK_PAGE_TURN = aalCreateSample("book_page_turn.wav");
SND_SCROLL_OPEN = aalCreateSample("scroll_open.wav");
SND_SCROLL_CLOSE = aalCreateSample("scroll_close.wav");
SND_TORCH_START = aalCreateSample("torch_start.wav");
SND_TORCH_LOOP = aalCreateSample("sfx_torch_11khz.wav");
SND_TORCH_END = aalCreateSample("torch_end.wav");
SND_INVSTD = aalCreateSample("interface_invstd.wav");
SND_GOLD = aalCreateSample("drop_coin.wav");
//Menu
SND_MENU_CLICK = aalCreateSample("menu_click.wav");
SND_MENU_CREDITS_LOOP = aalCreateSample("menu_credits_loop.wav");
SND_MENU_LOOP = aalCreateSample("menu_loop.wav");
SND_MENU_OPTIONS_LOOP = aalCreateSample("menu_options_loop.wav");
SND_MENU_PUSH = aalCreateSample("menu_push.wav");
SND_MENU_RELEASE = aalCreateSample("menu_release.wav");
//Other SFX samples
SND_FIREPLACE = aalCreateSample("fire_place.wav");
SND_PLOUF = aalCreateSample("fishing_plouf.wav");
SND_QUAKE = aalCreateSample("sfx_quake.wav");
SND_WHOOSH = aalCreateSample("whoosh07.wav");
// Player
SND_PLAYER_FILLLIFEMANA = aalCreateSample("player_filllifemana.wav");
SND_PLAYER_HEART_BEAT = aalCreateSample("player_heartb.wav");
SND_PLAYER_JUMP = aalCreateSample("player_jump.wav");
SND_PLAYER_JUMP_END = aalCreateSample("player_jumpend.wav");
SND_PLAYER_LEVEL_UP = aalCreateSample("player_level_up.wav");
SND_PLAYER_POISONED = aalCreateSample("player_poisoned.wav");
SND_PLAYER_DEATH_BY_FIRE = aalCreateSample("lava_death.wav");
// Magic draw
SND_MAGIC_AMBIENT = aalCreateSample("magic_ambient.wav");
SND_MAGIC_DRAW = aalCreateSample("magic_draw.wav");
SND_MAGIC_FIZZLE = aalCreateSample("magic_fizzle.wav");
// Magic symbols
SND_SYMB_AAM = aalCreateSample("magic_aam.wav");
SND_SYMB_CETRIUS = aalCreateSample("magic_citrius.wav");
SND_SYMB_COSUM = aalCreateSample("magic_cosum.wav");
SND_SYMB_COMUNICATUM = aalCreateSample("magic_comunicatum.wav");
SND_SYMB_FOLGORA = aalCreateSample("magic_folgora.wav");
SND_SYMB_FRIDD = aalCreateSample("magic_fridd.wav");
SND_SYMB_KAOM = aalCreateSample("magic_kaom.wav");
SND_SYMB_MEGA = aalCreateSample("magic_mega.wav");
SND_SYMB_MORTE = aalCreateSample("magic_morte.wav");
SND_SYMB_MOVIS = aalCreateSample("magic_movis.wav");
SND_SYMB_NHI = aalCreateSample("magic_nhi.wav");
SND_SYMB_RHAA = aalCreateSample("magic_rhaa.wav");
SND_SYMB_SPACIUM = aalCreateSample("magic_spacium.wav");
SND_SYMB_STREGUM = aalCreateSample("magic_stregum.wav");
SND_SYMB_TAAR = aalCreateSample("magic_taar.wav");
SND_SYMB_TEMPUS = aalCreateSample("magic_tempus.wav");
SND_SYMB_TERA = aalCreateSample("magic_tera.wav");
SND_SYMB_VISTA = aalCreateSample("magic_vista.wav");
SND_SYMB_VITAE = aalCreateSample("magic_vitae.wav");
SND_SYMB_YOK = aalCreateSample("magic_yok.wav");
// Spells
SND_SPELL_ACTIVATE_PORTAL = aalCreateSample("magic_spell_activate_portal.wav");
SND_SPELL_ARMOR_START = aalCreateSample("magic_spell_armor_start.wav");
SND_SPELL_ARMOR_END = aalCreateSample("magic_spell_armor_end.wav");
SND_SPELL_ARMOR_LOOP = aalCreateSample("magic_spell_armor_loop.wav");
SND_SPELL_LOWER_ARMOR = aalCreateSample("Magic_Spell_decrease_Armor.wav");
SND_SPELL_BLESS = aalCreateSample("magic_spell_bless.wav");
SND_SPELL_COLD_PROTECTION_START = aalCreateSample("Magic_Spell_Cold_Protection.wav");
SND_SPELL_COLD_PROTECTION_LOOP = aalCreateSample("Magic_Spell_Cold_Protection_loop.wav");
SND_SPELL_COLD_PROTECTION_END = aalCreateSample("Magic_Spell_Cold_Protection_end.wav");
SND_SPELL_CONFUSE = aalCreateSample("magic_spell_confuse.wav");
SND_SPELL_CONTROL_TARGET = aalCreateSample("magic_spell_control_target.wav");
SND_SPELL_CREATE_FIELD = aalCreateSample("magic_spell_create_field.wav");
SND_SPELL_CREATE_FOOD = aalCreateSample("magic_spell_create_food.wav");
SND_SPELL_CURE_POISON = aalCreateSample("magic_spell_cure_poison.wav");
SND_SPELL_CURSE = aalCreateSample("magic_spell_curse.wav");
SND_SPELL_DETECT_TRAP = aalCreateSample("magic_spell_detect_trap.wav");
SND_SPELL_DETECT_TRAP_LOOP = aalCreateSample("magic_spell_detect_trap_Loop.wav");
SND_SPELL_DISARM_TRAP = aalCreateSample("magic_spell_disarm_trap.wav");
SND_SPELL_DISPELL_FIELD = aalCreateSample("magic_spell_dispell_field.wav");
SND_SPELL_DISPELL_ILLUSION = aalCreateSample("magic_spell_dispell_illusion.wav");
SND_SPELL_DOUSE = aalCreateSample("magic_spell_douse.wav");
SND_SPELL_ELECTRIC = aalCreateSample("sfx_electric.wav");
SND_SPELL_ENCHANT_WEAPON = aalCreateSample("magic_spell_enchant_weapon.wav");
SND_SPELL_EXPLOSION = aalCreateSample("magic_spell_explosion.wav");
SND_SPELL_EYEBALL_IN = aalCreateSample("magic_spell_eyeball_in.wav");
SND_SPELL_EYEBALL_OUT = aalCreateSample("magic_spell_eyeball_out.wav");
SND_SPELL_FIRE_HIT = aalCreateSample("magic_spell_firehit.wav");
SND_SPELL_FIRE_LAUNCH = aalCreateSample("magic_spell_firelaunch.wav");
SND_SPELL_FIRE_PROTECTION = aalCreateSample("magic_spell_fire_protection.wav");
SND_SPELL_FIRE_WIND = aalCreateSample("magic_spell_firewind.wav");
SND_SPELL_FREEZETIME = aalCreateSample("magic_spell_freezetime.wav");
SND_SPELL_HARM = aalCreateSample("magic_spell_harm.wav");
SND_SPELL_HEALING = aalCreateSample("magic_spell_healing.wav");
SND_SPELL_ICE_FIELD = aalCreateSample("magic_spell_ice_field.wav");
SND_SPELL_ICE_PROJECTILE_LAUNCH = aalCreateSample("magic_spell_ice_projectile_launch.wav");
SND_SPELL_INCINERATE = aalCreateSample("magic_spell_incinerate.wav");
SND_SPELL_IGNITE = aalCreateSample("magic_spell_ignite.wav");
SND_SPELL_INVISIBILITY_START = aalCreateSample("magic_spell_invisibilityon.wav");
SND_SPELL_INVISIBILITY_END = aalCreateSample("magic_spell_invisibilityoff.wav");
SND_SPELL_LEVITATE_START = aalCreateSample("magic_spell_levitate_start.wav");
SND_SPELL_LIGHTNING_START = aalCreateSample("magic_spell_lightning_start.wav");
SND_SPELL_LIGHTNING_LOOP = aalCreateSample("magic_spell_lightning_loop.wav");
SND_SPELL_LIGHTNING_END = aalCreateSample("magic_spell_lightning_end.wav");
SND_SPELL_MAGICAL_HIT = aalCreateSample("magic_spell_magicalhit.wav");
SND_SPELL_MASS_LIGHTNING_END = aalCreateSample("magic_spell_mass_lightning_end.wav");
SND_SPELL_FIRE_FIELD_START = aalCreateSample("magic_spell_fire_field.wav");
SND_SPELL_FIRE_FIELD_LOOP = aalCreateSample("magic_spell_fire_field_loop.wav");
SND_SPELL_FIRE_FIELD_END = aalCreateSample("magic_spell_fire_field_end.wav");
SND_SPELL_MAGICAL_SHIELD = aalCreateSample("magic_spell_magicalshield.wav");
SND_SPELL_MASS_INCINERATE = aalCreateSample("magic_spell_mass_incinerate.wav");
SND_SPELL_MASS_PARALYSE = aalCreateSample("magic_spell_mass_paralyse.wav");
SND_SPELL_MM_CREATE = aalCreateSample("magic_spell_missilecreate.wav");
SND_SPELL_MM_HIT = aalCreateSample("magic_spell_missilehit.wav");
SND_SPELL_MM_LAUNCH = aalCreateSample("magic_spell_missilelaunch.wav");
SND_SPELL_MM_LOOP = aalCreateSample("magic_spell_missileloop.wav");
SND_SPELL_NEGATE_MAGIC = aalCreateSample("magic_spell_negate_magic.wav");
SND_SPELL_NO_EFFECT = aalCreateSample("magic_spell_noeffect.wav");
SND_SPELL_PARALYSE = aalCreateSample("magic_spell_paralyse.wav");
SND_SPELL_PARALYSE_END = aalCreateSample("magic_spell_paralyse_end.wav");
SND_SPELL_POISON_PROJECTILE_LAUNCH = aalCreateSample("magic_spell_poison_projectile_launch.wav");
SND_SPELL_RAISE_DEAD = aalCreateSample("magic_spell_raise_dead.wav");
SND_SPELL_REPEL_UNDEAD = aalCreateSample("magic_spell_repel_undead.wav");
SND_SPELL_REPEL_UNDEAD_LOOP = aalCreateSample("magic_spell_repell_loop.wav");
SND_SPELL_RUNE_OF_GUARDING = aalCreateSample("magic_spell_rune_of_guarding.wav");
SND_SPELL_SLOW_DOWN = aalCreateSample("magic_spell_slow_down.wav");
SND_SPELL_SPARK = aalCreateSample("sfx_spark.wav");
SND_SPELL_SPEED_START = aalCreateSample("magic_spell_speedstart.wav");
SND_SPELL_SPEED_LOOP = aalCreateSample("magic_spell_speed.wav");
SND_SPELL_SPEED_END = aalCreateSample("magic_spell_speedend.wav");
SND_SPELL_SUMMON_CREATURE = aalCreateSample("magic_spell_summon_creature.wav");
SND_SPELL_TELEKINESIS_START = aalCreateSample("magic_spell_telekinesison.wav");
SND_SPELL_TELEKINESIS_END = aalCreateSample("magic_spell_telekinesisoff.wav");
SND_SPELL_TELEPORT = aalCreateSample("magic_spell_teleport.wav");
SND_SPELL_TELEPORTED = aalCreateSample("magic_spell_teleported.wav");
SND_SPELL_VISION_START = aalCreateSample("magic_spell_vision2.wav");
SND_SPELL_VISION_LOOP = aalCreateSample("magic_spell_vision.wav");
}
// Reset each static sample to ARX_SOUND_INVALID_RESOURCE
// Those samples are freed from memory when Athena is deleted
static void ARX_SOUND_ReleaseStaticSamples()
{
// Interface samples
SND_BACKPACK = AAL_SFALSE;
SND_BOOK_OPEN = AAL_SFALSE;
SND_BOOK_CLOSE = AAL_SFALSE;
SND_BOOK_PAGE_TURN = AAL_SFALSE;
SND_GOLD = AAL_SFALSE;
SND_INVSTD = AAL_SFALSE;
SND_MAP = AAL_SFALSE;
SND_SCROLL_OPEN = AAL_SFALSE;
SND_SCROLL_CLOSE = AAL_SFALSE;
SND_TORCH_START = AAL_SFALSE;
SND_TORCH_LOOP = AAL_SFALSE;
SND_TORCH_END = AAL_SFALSE;
// Other SFX samples
SND_FIREPLACE = AAL_SFALSE;
SND_PLOUF = AAL_SFALSE;
SND_QUAKE = AAL_SFALSE;
// Menu samples
SND_MENU_CLICK = AAL_SFALSE;
SND_MENU_CREDITS_LOOP = AAL_SFALSE;
SND_MENU_LOOP = AAL_SFALSE;
SND_MENU_OPTIONS_LOOP = AAL_SFALSE;
SND_MENU_PUSH = AAL_SFALSE;
SND_MENU_RELEASE = AAL_SFALSE;
// Player samples
SND_PLAYER_DEATH = AAL_SFALSE;
SND_PLAYER_DEATH_BY_FIRE = AAL_SFALSE;
SND_PLAYER_FILLLIFEMANA = AAL_SFALSE;
SND_PLAYER_HEART_BEAT = AAL_SFALSE;
SND_PLAYER_JUMP = AAL_SFALSE;
SND_PLAYER_JUMP_END = AAL_SFALSE;
SND_PLAYER_LEVEL_UP = AAL_SFALSE;
SND_PLAYER_POISONED = AAL_SFALSE;
// Magic drawing samples
SND_MAGIC_AMBIENT = AAL_SFALSE;
SND_MAGIC_DRAW = AAL_SFALSE;
SND_MAGIC_FIZZLE = AAL_SFALSE;
// Magic symbols samples
SND_SYMB_AAM = AAL_SFALSE;
SND_SYMB_CETRIUS = AAL_SFALSE;
SND_SYMB_COSUM = AAL_SFALSE;
SND_SYMB_COMUNICATUM = AAL_SFALSE;
SND_SYMB_FOLGORA = AAL_SFALSE;
SND_SYMB_FRIDD = AAL_SFALSE;
SND_SYMB_KAOM = AAL_SFALSE;
SND_SYMB_MEGA = AAL_SFALSE;
SND_SYMB_MORTE = AAL_SFALSE;
SND_SYMB_MOVIS = AAL_SFALSE;
SND_SYMB_NHI = AAL_SFALSE;
SND_SYMB_RHAA = AAL_SFALSE;
SND_SYMB_SPACIUM = AAL_SFALSE;
SND_SYMB_STREGUM = AAL_SFALSE;
SND_SYMB_TAAR = AAL_SFALSE;
SND_SYMB_TEMPUS = AAL_SFALSE;
SND_SYMB_TERA = AAL_SFALSE;
SND_SYMB_VISTA = AAL_SFALSE;
SND_SYMB_VITAE = AAL_SFALSE;
SND_SYMB_YOK = AAL_SFALSE;
// Spells samples
SND_SPELL_ACTIVATE_PORTAL = AAL_SFALSE;
SND_SPELL_ARMOR_START = AAL_SFALSE;
SND_SPELL_ARMOR_END = AAL_SFALSE;
SND_SPELL_ARMOR_LOOP = AAL_SFALSE;
SND_SPELL_LOWER_ARMOR = AAL_SFALSE;
SND_SPELL_BLESS = AAL_SFALSE;
SND_SPELL_COLD_PROTECTION_START = AAL_SFALSE;
SND_SPELL_COLD_PROTECTION_LOOP = AAL_SFALSE;
SND_SPELL_COLD_PROTECTION_END = AAL_SFALSE;
SND_SPELL_CONFUSE = AAL_SFALSE;
SND_SPELL_CONTROL_TARGET = AAL_SFALSE;
SND_SPELL_CREATE_FIELD = AAL_SFALSE;
SND_SPELL_CREATE_FOOD = AAL_SFALSE;
SND_SPELL_CURE_POISON = AAL_SFALSE;
SND_SPELL_CURSE = AAL_SFALSE;
SND_SPELL_DETECT_TRAP = AAL_SFALSE;
SND_SPELL_DETECT_TRAP_LOOP = AAL_SFALSE;
SND_SPELL_DISARM_TRAP = AAL_SFALSE;
SND_SPELL_DISPELL_FIELD = AAL_SFALSE;
SND_SPELL_DISPELL_ILLUSION = AAL_SFALSE;
SND_SPELL_DOUSE = AAL_SFALSE;
SND_SPELL_ELECTRIC = AAL_SFALSE;
SND_SPELL_ENCHANT_WEAPON = AAL_SFALSE;
SND_SPELL_EXPLOSION = AAL_SFALSE;
SND_SPELL_EYEBALL_IN = AAL_SFALSE;
SND_SPELL_EYEBALL_OUT = AAL_SFALSE;
SND_SPELL_FIRE_FIELD = AAL_SFALSE;
SND_SPELL_FIRE_HIT = AAL_SFALSE;
SND_SPELL_FIRE_LAUNCH = AAL_SFALSE;
SND_SPELL_FIRE_PROTECTION = AAL_SFALSE;
SND_SPELL_FIRE_WIND = AAL_SFALSE;
SND_SPELL_FREEZETIME = AAL_SFALSE;
SND_SPELL_HARM = AAL_SFALSE;
SND_SPELL_HEALING = AAL_SFALSE;
SND_SPELL_ICE_FIELD = AAL_SFALSE;
SND_SPELL_ICE_PROJECTILE_LAUNCH = AAL_SFALSE;
SND_SPELL_INCINERATE = AAL_SFALSE;
SND_SPELL_IGNITE = AAL_SFALSE;
SND_SPELL_INVISIBILITY_START = AAL_SFALSE;
SND_SPELL_INVISIBILITY_END = AAL_SFALSE;
SND_SPELL_LEVITATE_START = AAL_SFALSE;
SND_SPELL_LIGHTNING_START = AAL_SFALSE;
SND_SPELL_LIGHTNING_LOOP = AAL_SFALSE;
SND_SPELL_LIGHTNING_END = AAL_SFALSE;
SND_SPELL_MAGICAL_HIT = AAL_SFALSE;
SND_SPELL_MASS_LIGHTNING_END = AAL_SFALSE;
SND_SPELL_FIRE_FIELD_START = AAL_SFALSE;
SND_SPELL_FIRE_FIELD_LOOP = AAL_SFALSE;
SND_SPELL_FIRE_FIELD_END = AAL_SFALSE;
SND_SPELL_MAGICAL_SHIELD = AAL_SFALSE;
SND_SPELL_MASS_INCINERATE = AAL_SFALSE;
SND_SPELL_MASS_PARALYSE = AAL_SFALSE;
SND_SPELL_MM_CREATE = AAL_SFALSE;
SND_SPELL_MM_HIT = AAL_SFALSE;
SND_SPELL_MM_LAUNCH = AAL_SFALSE;
SND_SPELL_MM_LOOP = AAL_SFALSE;
SND_SPELL_NEGATE_MAGIC = AAL_SFALSE;
SND_SPELL_PARALYSE = AAL_SFALSE;
SND_SPELL_PARALYSE_END = AAL_SFALSE;
SND_SPELL_POISON_PROJECTILE_LAUNCH = AAL_SFALSE;
SND_SPELL_RAISE_DEAD = AAL_SFALSE;
SND_SPELL_REPEL_UNDEAD = AAL_SFALSE;
SND_SPELL_REPEL_UNDEAD_LOOP = AAL_SFALSE;
SND_SPELL_RUNE_OF_GUARDING = AAL_SFALSE;
SND_SPELL_SLOW_DOWN = AAL_SFALSE;
SND_SPELL_SPARK = AAL_SFALSE;
SND_SPELL_SPEED_START = AAL_SFALSE;
SND_SPELL_SPEED_LOOP = AAL_SFALSE;
SND_SPELL_SPEED_END = AAL_SFALSE;
SND_SPELL_SUMMON_CREATURE = AAL_SFALSE;
SND_SPELL_TELEKINESIS_START = AAL_SFALSE;
SND_SPELL_TELEKINESIS_END = AAL_SFALSE;
SND_SPELL_TELEPORT = AAL_SFALSE;
SND_SPELL_TELEPORTED = AAL_SFALSE;
SND_SPELL_VISION_START = AAL_SFALSE;
SND_SPELL_VISION_LOOP = AAL_SFALSE;
}
long ARX_MATERIAL_GetIdByName(char * name)
{
if (!stricmp(name, "WEAPON")) return MATERIAL_WEAPON;
if (!stricmp(name, "FLESH")) return MATERIAL_FLESH;
if (!stricmp(name, "METAL")) return MATERIAL_METAL;
if (!stricmp(name, "GLASS")) return MATERIAL_GLASS;
if (!stricmp(name, "CLOTH")) return MATERIAL_CLOTH;
if (!stricmp(name, "WOOD")) return MATERIAL_WOOD;
if (!stricmp(name, "EARTH")) return MATERIAL_EARTH;
if (!stricmp(name, "WATER")) return MATERIAL_WATER;
if (!stricmp(name, "ICE")) return MATERIAL_ICE;
if (!stricmp(name, "GRAVEL")) return MATERIAL_GRAVEL;
if (!stricmp(name, "STONE")) return MATERIAL_STONE;
if (!stricmp(name, "FOOT_LARGE")) return MATERIAL_FOOT_LARGE;
if (!stricmp(name, "FOOT_BARE")) return MATERIAL_FOOT_BARE;
if (!stricmp(name, "FOOT_SHOE")) return MATERIAL_FOOT_SHOE;
if (!stricmp(name, "FOOT_METAL")) return MATERIAL_FOOT_METAL;
if (!stricmp(name, "FOOT_STEALTH")) return MATERIAL_FOOT_STEALTH;
return MATERIAL_NONE;
}
bool ARX_MATERIAL_GetNameById(long id, char * name)
{
switch (id)
{
case MATERIAL_WEAPON:
strcpy(name, "WEAPON");
return true;
break;
case MATERIAL_FLESH:
strcpy(name, "FLESH");
return true;
break;
case MATERIAL_METAL:
strcpy(name, "METAL");
return true;
break;
case MATERIAL_GLASS:
strcpy(name, "GLASS");
return true;
break;
case MATERIAL_CLOTH:
strcpy(name, "CLOTH");
return true;
break;
case MATERIAL_WOOD:
strcpy(name, "WOOD");
return true;
break;
case MATERIAL_EARTH:
strcpy(name, "EARTH");
return true;
break;
case MATERIAL_WATER:
strcpy(name, "WATER");
return true;
break;
case MATERIAL_ICE:
strcpy(name, "ICE");
return true;
break;
case MATERIAL_GRAVEL:
strcpy(name, "GRAVEL");
return true;
break;
case MATERIAL_STONE:
strcpy(name, "STONE");
return true;
break;
case MATERIAL_FOOT_LARGE:
strcpy(name, "FOOT_LARGE");
return true;
break;
case MATERIAL_FOOT_BARE:
strcpy(name, "FOOT_BARE");
return true;
break;
case MATERIAL_FOOT_SHOE:
strcpy(name, "FOOT_SHOE");
return true;
break;
case MATERIAL_FOOT_METAL:
strcpy(name, "FOOT_METAL");
return true;
break;
case MATERIAL_FOOT_STEALTH:
strcpy(name, "FOOT_STEALTH");
return true;
break;
}
strcpy(name, "NONE");
return false;
}
static void ARX_SOUND_LoadCollision(const long & mat1, const long & mat2, const char * name)
{
char path[256];
for (long i(0); i < MAX_VARIANTS; i++)
{
sprintf(path, "%s_%d.wav", name, i + 1);
Inter_Materials[mat1][mat2][i] = aalCreateSample(path);
if (mat1 != mat2)
Inter_Materials[mat2][mat1][i] = Inter_Materials[mat1][mat2][i];
}
}
unsigned long CollisionMapSectionCallback(const char * lpszSection)
{
void * ptr;
unsigned long ulSectionSize(strlen(lpszSection) + 1);
ARX_SOUND_CollisionMap * current_map;
//Resize the collision map list
ptr = realloc(collision_map_l, sizeof(ARX_SOUND_CollisionMap) * (collision_map_c + 1));
if (!ptr) return PARSE_INI_FILE_STOP;
collision_map_l = (ARX_SOUND_CollisionMap *)ptr;
current_map = &collision_map_l[collision_map_c];
//Initialize the current collision map
current_map->name = NULL;
current_map->name = (char *)malloc(ulSectionSize);
if (!current_map->name)
{
collision_map_l = (ARX_SOUND_CollisionMap *)realloc(collision_map_l, sizeof(ARX_SOUND_CollisionMap) * collision_map_c);
return PARSE_INI_FILE_STOP;
}
memcpy(current_map->name, lpszSection, ulSectionSize);
current_map->material_c = 0;
current_map->material_l = NULL;
collision_map_c++;
return PARSE_INI_FILE_CONTINUE;
}
unsigned long CollisionMapStringCallback(const char * lpszString)
{
ARX_SOUND_Material * current_material;
unsigned long ulKeySize;
const char * lpszValue;
void * ptr;
ARX_SOUND_CollisionMap * current_map = &collision_map_l[collision_map_c - 1];
//Find value position in current string and compute key size
lpszValue = strchr(lpszString, '=');
if (!lpszValue) return PARSE_INI_FILE_CONTINUE;
ulKeySize = ++lpszValue - lpszString;
if (!strlen(lpszValue)) return PARSE_INI_FILE_CONTINUE;
//Allocate the material
ptr = realloc(current_map->material_l, sizeof(ARX_SOUND_Material) * (current_map->material_c + 1));
if (!ptr) return PARSE_INI_FILE_STOP;
current_map->material_l = (ARX_SOUND_Material *)ptr;
current_material = ¤t_map->material_l[current_map->material_c];
//Initialize it
current_material->name = (char *)malloc(ulKeySize);
if (!current_material->name)
{
current_map->material_l = (ARX_SOUND_Material *)realloc(current_map->material_l, sizeof(ARX_SOUND_Material) * current_map->material_c);
return PARSE_INI_FILE_STOP;
}
memcpy(current_material->name, lpszString, ulKeySize);
current_material->name[ulKeySize - 1] = 0;
//current_material->name = strdup(lpszString);
current_material->variant_c = current_material->variant_i = 0;
current_material->variant_l = NULL;
//Find and create samples for the current material
char path[256];
for (unsigned long i(0); i < MAX_VARIANTS; i++)
{
long sample_id;
if (i)
sprintf(path, "%s%u%s", lpszValue, i, ARX_SOUND_FILE_EXTENSION_WAV);
else
sprintf(path, "%s%s", lpszValue, ARX_SOUND_FILE_EXTENSION_WAV);
sample_id = aalCreateSample(path);
if (sample_id == ARX_SOUND_INVALID_RESOURCE)
{
sprintf(path, "%s_%u%s", lpszValue, i, ARX_SOUND_FILE_EXTENSION_WAV);
sample_id = aalCreateSample(path);
}
if (sample_id != ARX_SOUND_INVALID_RESOURCE)
{
ptr = realloc(current_material->variant_l, sizeof(long) * (current_material->variant_c + 1));
if (!ptr) break;
current_material->variant_l = (long *)ptr;
current_material->variant_l[current_material->variant_c] = sample_id;
current_material->variant_c++;
}
}
if (!current_material->variant_c)
{
free(current_material->name);
current_map->material_l = (ARX_SOUND_Material *)realloc(current_map->material_l, sizeof(ARX_SOUND_Material) * current_map->material_c);
}
else current_map->material_c++;
return PARSE_INI_FILE_CONTINUE;
}
static void ARX_SOUND_CreateCollisionMaps()
{
char path[256];
for (unsigned long i = 0; i < ARX_SOUND_COLLISION_MAP_COUNT; i++)
{
char * lpszFileText;
long lFileSize;
sprintf(path, "%s%s%s%s",
Project.workingdir,
ARX_SOUND_PATH_INI, ARX_SOUND_COLLISION_MAP_NAME[i], ARX_SOUND_FILE_EXTENSION_INI);
lpszFileText = (char *)PAK_FileLoadMallocZero(path, &lFileSize);
if (!lpszFileText) return;
ARX_SOUND_ParseIniFile(lpszFileText, lFileSize, CollisionMapSectionCallback, CollisionMapStringCallback);
free(lpszFileText);
}
}
static void ARX_SOUND_DeleteCollisionMaps()
{
for (unsigned long i(0); i < collision_map_c; i++)
{
ARX_SOUND_CollisionMap * current_map = &collision_map_l[i];
for (unsigned long j(0); j < current_map->material_c; j++)
{
ARX_SOUND_Material * current_material = ¤t_map->material_l[j];
for (unsigned long k(0); k < current_material->variant_c; k++)
aalDeleteSample(current_material->variant_l[k]);
free(current_material->variant_l);
free(current_material->name);
}
free(current_map->material_l);
free(current_map->name);
}
free(collision_map_l), collision_map_l = NULL, collision_map_c = 0;
}
static void ARX_SOUND_CreateMaterials()
{
memset(Inter_Materials, -1, sizeof(long) * MAX_MATERIALS * MAX_MATERIALS * MAX_VARIANTS);
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WEAPON, "WEAPON_on_WEAPON");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_FLESH, "WEAPON_on_FLESH");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_METAL, "WEAPON_on_METAL");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_GLASS, "WEAPON_on_GLASS");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_CLOTH, "WEAPON_on_CLOTH");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WOOD, "WEAPON_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_EARTH, "WEAPON_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WATER, "WEAPON_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_ICE, "WEAPON_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_GRAVEL, "WEAPON_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_STONE, "WEAPON_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_FLESH, "FLESH_on_FLESH");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_METAL, "FLESH_on_METAL");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_GLASS, "FLESH_on_GLASS");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_CLOTH, "FLESH_on_CLOTH");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_WOOD, "FLESH_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_EARTH, "FLESH_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_WATER, "FLESH_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_ICE, "FLESH_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_GRAVEL, "FLESH_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_FLESH, MATERIAL_STONE, "FLESH_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_METAL, "METAL_on_METAL");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_GLASS, "METAL_on_GLASS");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_CLOTH, "METAL_on_CLOTH");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_WOOD, "METAL_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_EARTH, "METAL_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_WATER, "METAL_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_ICE, "METAL_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_GRAVEL, "METAL_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_METAL, MATERIAL_STONE, "METAL_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_GLASS, "GLASS_on_GLASS");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_CLOTH, "GLASS_on_CLOTH");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_WOOD, "GLASS_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_EARTH, "GLASS_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_WATER, "GLASS_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_ICE, "GLASS_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_GRAVEL, "GLASS_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_GLASS, MATERIAL_STONE, "GLASS_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_CLOTH, "CLOTH_on_CLOTH");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_WOOD, "CLOTH_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_EARTH, "CLOTH_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_WATER, "CLOTH_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_ICE, "CLOTH_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_GRAVEL, "CLOTH_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_CLOTH, MATERIAL_STONE, "CLOTH_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_WOOD, "WOOD_on_WOOD");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_EARTH, "WOOD_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_WATER, "WOOD_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_ICE, "WOOD_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_GRAVEL, "WOOD_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_WOOD, MATERIAL_STONE, "WOOD_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_EARTH, MATERIAL_EARTH, "EARTH_on_EARTH");
ARX_SOUND_LoadCollision(MATERIAL_EARTH, MATERIAL_WATER, "EARTH_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_EARTH, MATERIAL_ICE, "EARTH_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_EARTH, MATERIAL_GRAVEL, "EARTH_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_EARTH, MATERIAL_STONE, "EARTH_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_WATER, MATERIAL_WATER, "WATER_on_WATER");
ARX_SOUND_LoadCollision(MATERIAL_WATER, MATERIAL_ICE, "WATER_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_WATER, MATERIAL_GRAVEL, "WATER_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_WATER, MATERIAL_STONE, "WATER_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_ICE, MATERIAL_ICE, "ICE_on_ICE");
ARX_SOUND_LoadCollision(MATERIAL_ICE, MATERIAL_GRAVEL, "ICE_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_ICE, MATERIAL_STONE, "ICE_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_GRAVEL, MATERIAL_GRAVEL, "GRAVEL_on_GRAVEL");
ARX_SOUND_LoadCollision(MATERIAL_GRAVEL, MATERIAL_STONE, "GRAVEL_on_STONE");
ARX_SOUND_LoadCollision(MATERIAL_STONE, MATERIAL_STONE, "STONE_on_STONE");
}
unsigned long PresenceSectionCallback(const char * lpszText)
{
return PARSE_INI_FILE_CONTINUE;
}
unsigned long PresenceStringCallback(const char * lpszText)
{
unsigned long ulKeySize;
const char * lpszValue;
void * ptr;
ARX_SOUND_Presence * current_presence;
lpszValue = strchr(lpszText, '=');
if (!lpszValue) return PARSE_INI_FILE_CONTINUE;
ulKeySize = lpszValue - lpszText + sizeof(ARX_SOUND_FILE_EXTENSION_WAV);
if (!strlen(++lpszValue)) return PARSE_INI_FILE_CONTINUE;
//Allocate the new map entry
ptr = realloc(presence_l, sizeof(ARX_SOUND_Presence) * (presence_c + 1));
if (!ptr) return PARSE_INI_FILE_STOP;
presence_l = (ARX_SOUND_Presence *)ptr;
current_presence = &presence_l[presence_c];
current_presence->name = (char *)malloc(ulKeySize);
if (!current_presence->name)
{
presence_l = (ARX_SOUND_Presence *)realloc(presence_l, sizeof(ARX_SOUND_Presence) * (presence_c));
return PARSE_INI_FILE_STOP;
}
memcpy(current_presence->name, lpszText, ulKeySize - sizeof(ARX_SOUND_FILE_EXTENSION_WAV));
memcpy(¤t_presence->name[ulKeySize - sizeof(ARX_SOUND_FILE_EXTENSION_WAV)], ARX_SOUND_FILE_EXTENSION_WAV, sizeof(ARX_SOUND_FILE_EXTENSION_WAV));
current_presence->name_size = ulKeySize;
current_presence->factor = (float)atoi(lpszValue) / 100.0F;
presence_c++;
return PARSE_INI_FILE_CONTINUE;
}
static void ARX_SOUND_CreatePresenceMap()
{
char path[256];
char * lpszFileText;
long lFileSize;
sprintf(path, "%s%s%s%s",
Project.workingdir,
ARX_SOUND_PATH_INI, ARX_SOUND_PRESENCE_NAME, ARX_SOUND_FILE_EXTENSION_INI);
lpszFileText = (char *)PAK_FileLoadMallocZero(path, &lFileSize);
if (!lpszFileText) return;
ARX_SOUND_ParseIniFile(lpszFileText, lFileSize, PresenceSectionCallback, PresenceStringCallback);
free(lpszFileText);
}
static void ARX_SOUND_DeletePresenceMap()
{
for (unsigned long i(0); i < presence_c; i++)
free(presence_l[i].name);
free(presence_l), presence_l = NULL, presence_c = 0;
}
static float GetSamplePresenceFactor(const char * name)
{
for (unsigned long i(0); i < presence_c; i++)
if (!strnicmp(presence_l[i].name, name, presence_l[i].name_size)) return presence_l[i].factor;
return 1.0F;
}
LARGE_INTEGER Sstart_chrono, Send_chrono;
unsigned long BENCH_SOUND = 0;
LPTHREAD_START_ROUTINE UpdateSoundThread(char *)
{
bExitUpdateThread = false;
while (!bExitUpdateThread)
{
Sleep(ARX_SOUND_UPDATE_INTERVAL);
QueryPerformanceCounter(&Sstart_chrono);
aalUpdate();
QueryPerformanceCounter(&Send_chrono);
BENCH_SOUND = (unsigned long)(Send_chrono.QuadPart - Sstart_chrono.QuadPart);
}
ExitThread(0);
return 0;
}
static void ARX_SOUND_LaunchUpdateThread()
{
DWORD id;
if (hUpdateThread) return;
hUpdateThread = (HANDLE)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateSoundThread, NULL, 0, &id);
if (hUpdateThread) SetThreadPriority(hUpdateThread, THREAD_PRIORITY_NORMAL);//_LOWEST);
}
static void ARX_SOUND_KillUpdateThread()
{
if (!hUpdateThread) return;
SetThreadPriority(hUpdateThread, THREAD_PRIORITY_HIGHEST);
bExitUpdateThread = true;
if (WaitForSingleObject(hUpdateThread, 5000) == WAIT_TIMEOUT)
MessageBox(NULL, "Failed while killing audio thread", "ARX Fatalis - Error", MB_OK);
CloseHandle(hUpdateThread), hUpdateThread = NULL;
}
static bool isSection(char * _lpszText)
{
ULONG i = 0;
unsigned long ulTextSize = strlen(_lpszText);
bool bFirst = false;
bool bLast = false;
while (i < ulTextSize)
{
if (_lpszText[i] == '[')
{
if (bFirst) return false;
else bFirst = true;
}
else if (_lpszText[i] == ']')
{
if (!bFirst) return false;
if (bLast) return false;
else bLast = true;
}
else if (isalpha(_lpszText[i]))
{
if (!bFirst) return false;
else if (bFirst && bLast) return false;
}
i++;
}
if (bFirst && bLast) return true;
return false;
}
//-----------------------------------------------------------------------------
static bool isString(char * _lpszText)
{
ULONG i = 0;
unsigned long ulTextSize = strlen(_lpszText);
bool bSpace = false;
bool bAlpha = false;
while (i < ulTextSize)
{
if (_lpszText[i] == '=')
{
if (bSpace) return false;
else bSpace = true;
}
else if (isalpha(_lpszText[i]) && !bAlpha)
{
bAlpha = true;
}
i++;
}
if (bSpace && bAlpha) return true;
return false;
}
//-----------------------------------------------------------------------------
static bool isNotEmpty(char * _lpszText)
{
ULONG i = 0;
unsigned long ulTextSize = strlen(_lpszText);
while (i < ulTextSize)
{
if (isalpha(_lpszText[i])) return true;
i++;
}
return false;
}
//-----------------------------------------------------------------------------
static char * CleanSection(const char * _lpszText)
{
unsigned long ulTextSize = strlen(_lpszText);
char * lpszText = (char *)malloc((ulTextSize + 1) * sizeof(char));
ZeroMemory(lpszText, (ulTextSize + 1) * sizeof(char));
unsigned long ulPos = 0;
bool bFirst = false;
for (unsigned long ul = 0; ul < ulTextSize; ul++)
{
if (_lpszText[ul] == '[') bFirst = true;
else if (_lpszText[ul] == ']') break;
else if (bFirst)
{
lpszText[ulPos] = _lpszText[ul];
ulPos ++;
}
}
return lpszText;
}
//-----------------------------------------------------------------------------
static char * CleanString(const char * _lpszText)
{
unsigned long ulTextSize = strlen(_lpszText);
char * lpszText = (char *)malloc((ulTextSize + 1) * sizeof(char));
ZeroMemory(lpszText, (ulTextSize + 1) * sizeof(char));
unsigned long ulPos = 0;
for (unsigned long ul = 0; ul < ulTextSize; ul++)
if (_lpszText[ul] == '=' || _lpszText[ul] == '_' || isalnum(_lpszText[ul]))
{
lpszText[ulPos] = _lpszText[ul];
++ulPos;
}
while (ulPos--)
{
if (isalpha(lpszText[ulPos])) break;
else if (lpszText[ulPos] == '"' || lpszText[ulPos] == ' ')
lpszText[ulPos] = 0;
}
return lpszText;
}
static void ARX_SOUND_ParseIniFile(char * _lpszTextFile, const unsigned long _ulFileSize, ParseIniFileCallback lpSectionCallback, ParseIniFileCallback lpStringCallback)
{
char * pFile = _lpszTextFile;
if (!lpSectionCallback || !lpStringCallback) return;
//-------------------------------------------------------------------------
//clean up comments
for (unsigned long i = 0; i < _ulFileSize; i++)
if (pFile[i] == '/' && pFile[i + 1] == '/')
{
unsigned long j = i;
while (j < _ulFileSize && pFile[j] != '\r' && pFile[j + 1] != '\n')
{
pFile[j] = ' ';
j++;
}
}
//-------------------------------------------------------------------------
// get all lines into list
list lText;
char * pLine = strtok(pFile, "\r\n");
while (pLine)
{
if (isNotEmpty(pLine)) lText.insert(lText.end(), (pLine));
pLine = strtok(NULL, "\r\n");
}
list::iterator it;
//-------------------------------------------------------------------------
// look up for sections and associated keys
it = lText.begin();
while (it != lText.end())
{
if (isSection(*it))
{
unsigned long lResult;
char * lpszSection;
lResult = (*lpSectionCallback)(lpszSection = CleanSection(*it));
free(lpszSection);
if (lResult == PARSE_INI_FILE_SKIP) continue;
else if (lResult == PARSE_INI_FILE_STOP) break;
it++;
while ((it != lText.end()) && (!isSection(*it)))
{
if (isString(*it))
{
char * lpszString = CleanString(*it);
lResult = (*lpStringCallback)(lpszString);
free(lpszString);
if (lResult == PARSE_INI_FILE_SKIP) continue;
else if (lResult == PARSE_INI_FILE_STOP) break;
it++;
}
else break;
}
continue;
}
it++;
}
it = it;
}