Implement modular multi-audio-language support.

This commit is contained in:
hackgrid 2023-10-14 15:13:13 +02:00
parent 738f3c73fa
commit 44217fb546
9 changed files with 210 additions and 25 deletions

View file

@ -69,21 +69,48 @@ default: english_audio
english_audio: portal_pak_dir english_audio: portal_pak_dir
@$(MAKE) buildgame @$(MAKE) buildgame
german_audio: vpk/portal_sound_vo_german_dir.vpk vpk/portal_sound_vo_german_000.vpk portal_pak_dir all_languages: portal_pak_dir german_audio french_audio russian_audio spanish_audio
vpk -x portal_pak_dir vpk/portal_sound_vo_german_dir.vpk
@$(MAKE) buildgame @$(MAKE) buildgame
german_audio: vpk/portal_sound_vo_german_dir.vpk vpk/portal_sound_vo_german_000.vpk portal_pak_dir
rm -rf portal_pak_dir/locales/de/
vpk -x portal_pak_dir/locales/de/ vpk/portal_sound_vo_german_dir.vpk
cd portal_pak_dir/locales/de/sound/vo/aperture_ai/; ls | xargs -I {} mv {} de_{}
rm -rf assets/locales/de/sound/vo/aperture_ai/
@mkdir -p assets/locales/de/sound/vo/aperture_ai/
cp assets/sound/vo/aperture_ai/*.sox assets/locales/de/sound/vo/aperture_ai/
cd assets/locales/de/sound/vo/aperture_ai/; rm -f ding_off.sox ding_on.sox
cd assets/locales/de/sound/vo/aperture_ai/; ls | xargs -I {} mv {} de_{}
french_audio: vpk/portal_sound_vo_french_dir.vpk vpk/portal_sound_vo_french_000.vpk portal_pak_dir french_audio: vpk/portal_sound_vo_french_dir.vpk vpk/portal_sound_vo_french_000.vpk portal_pak_dir
vpk -x portal_pak_dir vpk/portal_sound_vo_french_dir.vpk rm -rf portal_pak_dir/locales/fr/
@$(MAKE) buildgame vpk -x portal_pak_dir/locales/fr/ vpk/portal_sound_vo_french_dir.vpk
cd portal_pak_dir/locales/fr/sound/vo/aperture_ai/; ls | xargs -I {} mv {} fr_{}
rm -rf assets/locales/fr/sound/vo/aperture_ai/
@mkdir -p assets/locales/fr/sound/vo/aperture_ai/
cp assets/sound/vo/aperture_ai/*.sox assets/locales/fr/sound/vo/aperture_ai/
cd assets/locales/fr/sound/vo/aperture_ai/; rm -f ding_off.sox ding_on.sox
cd assets/locales/fr/sound/vo/aperture_ai/; ls | xargs -I {} mv {} fr_{}
russian_audio: vpk/portal_sound_vo_russian_dir.vpk vpk/portal_sound_vo_russian_000.vpk portal_pak_dir russian_audio: vpk/portal_sound_vo_russian_dir.vpk vpk/portal_sound_vo_russian_000.vpk portal_pak_dir
vpk -x portal_pak_dir vpk/portal_sound_vo_russian_dir.vpk rm -rf portal_pak_dir/locales/ru/
@$(MAKE) buildgame vpk -x portal_pak_dir/locales/ru/ vpk/portal_sound_vo_russian_dir.vpk
cd portal_pak_dir/locales/ru/sound/vo/aperture_ai/; ls | xargs -I {} mv {} ru_{}
rm -rf assets/locales/ru/sound/vo/aperture_ai/
@mkdir -p assets/locales/ru/sound/vo/aperture_ai/
cp assets/sound/vo/aperture_ai/*.sox assets/locales/ru/sound/vo/aperture_ai/
cd assets/locales/ru/sound/vo/aperture_ai/; rm -f ding_off.sox ding_on.sox
cd assets/locales/ru/sound/vo/aperture_ai/; ls | xargs -I {} mv {} ru_{}
spanish_audio: vpk/portal_sound_vo_spanish_dir.vpk vpk/portal_sound_vo_spanish_000.vpk portal_pak_dir spanish_audio: vpk/portal_sound_vo_spanish_dir.vpk vpk/portal_sound_vo_spanish_000.vpk portal_pak_dir
vpk -x portal_pak_dir vpk/portal_sound_vo_spanish_dir.vpk rm -rf portal_pak_dir/locales/es/
@$(MAKE) buildgame vpk -x portal_pak_dir/locales/es/ vpk/portal_sound_vo_spanish_dir.vpk
cd portal_pak_dir/locales/es/sound/vo/aperture_ai/; ls | xargs -I {} mv {} es_{}
rm -rf assets/locales/es/sound/vo/aperture_ai/
@mkdir -p assets/locales/es/sound/vo/aperture_ai/
cp assets/sound/vo/aperture_ai/*.sox assets/locales/es/sound/vo/aperture_ai/
cd assets/locales/es/sound/vo/aperture_ai/; rm -f ding_off.sox ding_on.sox
cd assets/locales/es/sound/vo/aperture_ai/; ls | xargs -I {} mv {} es_{}
buildgame: $(BASE_TARGET_NAME).z64 buildgame: $(BASE_TARGET_NAME).z64
@ -92,7 +119,7 @@ include $(COMMONRULES)
.s.o: .s.o:
$(AS) -Wa,-Iasm -o $@ $< $(AS) -Wa,-Iasm -o $@ $<
build/%.o: %.c build/%.o: %.c
@mkdir -p $(@D) @mkdir -p $(@D)
$(CC) $(CFLAGS) -MM $^ -MF "$(@:.o=.d)" -MT"$@" $(CC) $(CFLAGS) -MM $^ -MF "$(@:.o=.d)" -MT"$@"
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
@ -286,6 +313,7 @@ build/src/decor/decor_object_list.o: build/assets/models/dynamic_model_list.h bu
build/src/effects/effect_definitions.o: build/assets/materials/static.h build/src/effects/effect_definitions.o: build/assets/materials/static.h
build/src/effects/portal_trail.o: build/assets/materials/static.h build/assets/models/portal_gun/ball_trail.h build/src/effects/portal_trail.o: build/assets/materials/static.h build/assets/models/portal_gun/ball_trail.h
build/src/levels/level_definition.o: build/src/audio/subtitles.h build/src/levels/level_definition.o: build/src/audio/subtitles.h
build/src/locales/locales.o: build/src/audio/clips.h build/src/audio/languages.h
build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h
build/src/menu/game_menu.o: build/src/audio/clips.h build/assets/materials/ui.h build/assets/materials/images.h build/assets/test_chambers/test_chamber_00/test_chamber_00.h build/src/menu/game_menu.o: build/src/audio/clips.h build/assets/materials/ui.h build/assets/materials/images.h build/assets/test_chambers/test_chamber_00/test_chamber_00.h
build/src/menu/gameplay_options.o: build/assets/materials/ui.h build/src/audio/clips.h build/src/menu/gameplay_options.o: build/assets/materials/ui.h build/src/audio/clips.h
@ -437,9 +465,9 @@ build/assets/sound/sounds.sounds build/assets/sound/sounds.sounds.tbl: $(SOUND_C
build/asm/sound_data.o: build/assets/sound/sounds.sounds build/assets/sound/sounds.sounds.tbl build/asm/sound_data.o: build/assets/sound/sounds.sounds build/assets/sound/sounds.sounds.tbl
build/src/audio/clips.h: tools/generate_sound_ids.js $(SOUND_CLIPS) build/src/audio/clips.h build/src/audio/languages.h build/src/audio/languages.c: tools/generate_sound_ids.js $(SOUND_CLIPS)
@mkdir -p $(@D) @mkdir -p $(@D)
node tools/generate_sound_ids.js -o $@ -p SOUNDS_ $(SOUND_CLIPS) node tools/generate_sound_ids.js -o $(@D) -p SOUNDS_ $(SOUND_CLIPS)
build/src/audio/clips.o: build/src/audio/clips.h build/src/audio/clips.o: build/src/audio/clips.h
build/src/decor/decor_object_list.o: build/src/audio/clips.h build/src/decor/decor_object_list.o: build/src/audio/clips.h
@ -449,7 +477,7 @@ build/src/decor/decor_object_list.o: build/src/audio/clips.h
#################### ####################
build/src/audio/subtitles.h build/src/audio/subtitles.c: resource/closecaption_english.txt tools/level_scripts/subtitle_generate.py build/src/audio/subtitles.h build/src/audio/subtitles.c: resource/closecaption_english.txt tools/level_scripts/subtitle_generate.py
@python tools/level_scripts/subtitle_generate.py @python3 tools/level_scripts/subtitle_generate.py
#################### ####################
## Linking ## Linking
@ -465,7 +493,8 @@ CODEOBJECTS = $(patsubst %.c, build/%.o, $(CODEFILES)) \
build/assets/materials/static_mat.o \ build/assets/materials/static_mat.o \
build/assets/materials/ui_mat.o \ build/assets/materials/ui_mat.o \
build/assets/materials/hud_mat.o \ build/assets/materials/hud_mat.o \
build/src/audio/subtitles.o build/src/audio/subtitles.o \
build/src/audio/languages.o
CODEOBJECTS_NO_DEBUG = $(CODEOBJECTS) CODEOBJECTS_NO_DEBUG = $(CODEOBJECTS)
@ -508,7 +537,8 @@ $(BASE_TARGET_NAME)_debug.z64: $(CODESEGMENT)_debug.o $(OBJECTS) $(DATA_OBJECTS)
clean: clean:
rm -rf build rm -rf build
rm -rf portal_pak_dir rm -rf portal_pak_dir
rm -rf portal_pak_modified rm -rf portal_pak_modified
rm -rf assets/locales/
clean-src: clean-src:
rm -rf build/src rm -rf build/src
@ -521,6 +551,7 @@ clean-src:
clean-assets: clean-assets:
rm -rf build/assets rm -rf build/assets
rm -rf assets/locales/
rm -f $(CODESEGMENT)_debug.o rm -f $(CODESEGMENT)_debug.o
rm -f $(CODESEGMENT)_no_debug.o rm -f $(CODESEGMENT)_no_debug.o
rm -f $(BASE_TARGET_NAME)_debug.elf rm -f $(BASE_TARGET_NAME)_debug.elf

View file

@ -6,6 +6,7 @@
#include "../levels/levels.h" #include "../levels/levels.h"
#include "../util/memory.h" #include "../util/memory.h"
#include "../savefile/checkpoint.h" #include "../savefile/checkpoint.h"
#include "../locales/locales.h"
#include <math.h> #include <math.h>
@ -142,6 +143,7 @@ void cutsceneRunnerStartStep(struct CutsceneRunner* runner) {
break; break;
case CutsceneStepTypeQueueSound: case CutsceneStepTypeQueueSound:
{ {
step->queueSound.soundId = mapLocaleSound(step->queueSound.soundId);
cutsceneQueueSoundInChannel(step->queueSound.soundId, step->queueSound.volume * (1.0f / 255.0f), step->queueSound.channel, step->queueSound.subtitleId); cutsceneQueueSoundInChannel(step->queueSound.soundId, step->queueSound.volume * (1.0f / 255.0f), step->queueSound.channel, step->queueSound.subtitleId);
break; break;
} }

21
src/locales/locales.c Normal file
View file

@ -0,0 +1,21 @@
#include "locales.h"
#include "../build/src/audio/languages.h"
#include "../savefile/savefile.h"
int getAudioLanguage() {
return (int)gSaveData.audio.audioLanguage;
}
int mapLocaleSound(int soundId) {
int language = getAudioLanguage();
switch(language) {
default:
soundId = AudioLanguageValues[language][soundId];
break;
case AUDIO_LANGUAGE_EN:
break;
}
return soundId;
}

2
src/locales/locales.h Normal file
View file

@ -0,0 +1,2 @@
int getAudioLanguage();
int mapLocaleSound(int soundId);

View file

@ -7,6 +7,7 @@
#include "../build/src/audio/subtitles.h" #include "../build/src/audio/subtitles.h"
#include "../build/assets/materials/ui.h" #include "../build/assets/materials/ui.h"
#include "../build/src/audio/clips.h" #include "../build/src/audio/clips.h"
#include "../build/src/audio/languages.h"
#define GAMEPLAY_Y 54 #define GAMEPLAY_Y 54
#define GAMEPLAY_WIDTH 252 #define GAMEPLAY_WIDTH 252
@ -15,14 +16,19 @@
#define SCROLL_TICKS (int)maxf(NUM_SUBTITLE_LANGUAGES, 1) #define SCROLL_TICKS (int)maxf(NUM_SUBTITLE_LANGUAGES, 1)
#define SCROLL_INTERVALS (int)maxf((SCROLL_TICKS - 1), 1) #define SCROLL_INTERVALS (int)maxf((SCROLL_TICKS - 1), 1)
#define SCROLL_CHUNK_SIZE (0x10000 / SCROLL_INTERVALS)
#define SCROLL_TICKS_LANGUAGE (int)maxf(NUM_AUDIO_LANGUAGES, 1)
#define SCROLL_INTERVALS_LANGUAGE (int)maxf((SCROLL_TICKS_LANGUAGE - 1), 1)
#define SCROLL_CHUNK_SIZE_LANGUAGE (0x10000 / SCROLL_INTERVALS_LANGUAGE)
#define FULL_SCROLL_TIME 2.0f #define FULL_SCROLL_TIME 2.0f
#define SCROLL_MULTIPLIER (int)(0xFFFF * FIXED_DELTA_TIME / (80 * FULL_SCROLL_TIME)) #define SCROLL_MULTIPLIER (int)(0xFFFF * FIXED_DELTA_TIME / (80 * FULL_SCROLL_TIME))
#define SCROLL_CHUNK_SIZE (0x10000 / SCROLL_INTERVALS)
void audioOptionsInit(struct AudioOptions* audioOptions) { void audioOptionsInit(struct AudioOptions* audioOptions) {
audioOptions->selectedItem = AudioOptionSubtitlesEnabled; audioOptions->selectedItem = AudioOptionSubtitlesEnabled;
if (NUM_SUBTITLE_LANGUAGES){ if (NUM_SUBTITLE_LANGUAGES) {
audioOptions->subtitlesEnabled = menuBuildCheckbox(&gDejaVuSansFont, "Closed Captions", GAMEPLAY_X + 8, GAMEPLAY_Y + 8); audioOptions->subtitlesEnabled = menuBuildCheckbox(&gDejaVuSansFont, "Closed Captions", GAMEPLAY_X + 8, GAMEPLAY_Y + 8);
audioOptions->subtitlesEnabled.checked = (gSaveData.controls.flags & ControlSaveSubtitlesEnabled) != 0; audioOptions->subtitlesEnabled.checked = (gSaveData.controls.flags & ControlSaveSubtitlesEnabled) != 0;
@ -33,6 +39,15 @@ void audioOptionsInit(struct AudioOptions* audioOptions) {
audioOptions->subtitles_language_temp = (0xFFFF/SCROLL_TICKS)* gSaveData.controls.subtitleLanguage; audioOptions->subtitles_language_temp = (0xFFFF/SCROLL_TICKS)* gSaveData.controls.subtitleLanguage;
audioOptions->subtitlesLanguage.value = (int)gSaveData.controls.subtitleLanguage * (0xFFFF/SCROLL_TICKS); audioOptions->subtitlesLanguage.value = (int)gSaveData.controls.subtitleLanguage * (0xFFFF/SCROLL_TICKS);
} }
if (NUM_AUDIO_LANGUAGES > 1) {
audioOptions->audioLanguageText = menuBuildText(&gDejaVuSansFont, "Audio Language: ", GAMEPLAY_X + 8, GAMEPLAY_Y + 68);
audioOptions->audioLanguageDynamicText = menuBuildText(&gDejaVuSansFont, AudioLanguages[gSaveData.audio.audioLanguage], GAMEPLAY_X + 150, GAMEPLAY_Y + 68);
audioOptions->audioLanguage= menuBuildSlider(GAMEPLAY_X + 8, GAMEPLAY_Y + 88, 200, SCROLL_TICKS_LANGUAGE);
audioOptions->audio_language_temp = (0xFFFF/SCROLL_TICKS)* gSaveData.audio.audioLanguage;
audioOptions->audioLanguage.value = (int)gSaveData.audio.audioLanguage * (0xFFFF/SCROLL_TICKS_LANGUAGE);
}
} }
void audioOptionsHandleSlider(unsigned short* settingValue, float* sliderValue) { void audioOptionsHandleSlider(unsigned short* settingValue, float* sliderValue) {
@ -44,14 +59,14 @@ void audioOptionsHandleSlider(unsigned short* settingValue, float* sliderValue)
if (newValue >= 0xFFFF && controllerGetButtonDown(0, A_BUTTON)) { if (newValue >= 0xFFFF && controllerGetButtonDown(0, A_BUTTON)) {
newValue = 0; newValue = 0;
} else { } else {
newValue = newValue + SCROLL_CHUNK_SIZE; newValue = newValue + SCROLL_CHUNK_SIZE_LANGUAGE;
newValue = newValue - (newValue % SCROLL_CHUNK_SIZE); newValue = newValue - (newValue % SCROLL_CHUNK_SIZE_LANGUAGE);
} }
} }
if (controllerGetButtonDown(0, L_JPAD)) { if (controllerGetButtonDown(0, L_JPAD)) {
newValue = newValue - 1; newValue = newValue - 1;
newValue = newValue - (newValue % SCROLL_CHUNK_SIZE); newValue = newValue - (newValue % SCROLL_CHUNK_SIZE_LANGUAGE);
} }
if (newValue < 0) { if (newValue < 0) {
@ -89,7 +104,6 @@ enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions) {
} }
} }
if (NUM_SUBTITLE_LANGUAGES){
switch (audioOptions->selectedItem) { switch (audioOptions->selectedItem) {
case AudioOptionSubtitlesEnabled: case AudioOptionSubtitlesEnabled:
if (controllerGetButtonDown(0, A_BUTTON)) { if (controllerGetButtonDown(0, A_BUTTON)) {
@ -110,10 +124,16 @@ enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions) {
gSaveData.controls.subtitleLanguage = temp; gSaveData.controls.subtitleLanguage = temp;
audioOptions->subtitlesLanguageDynamicText = menuBuildText(&gDejaVuSansFont, SubtitleLanguages[gSaveData.controls.subtitleLanguage], GAMEPLAY_X + 150, GAMEPLAY_Y + 28); audioOptions->subtitlesLanguageDynamicText = menuBuildText(&gDejaVuSansFont, SubtitleLanguages[gSaveData.controls.subtitleLanguage], GAMEPLAY_X + 150, GAMEPLAY_Y + 28);
break; break;
} case AudioOptionAudioLanguage:
audioOptionsHandleSlider(&audioOptions->audio_language_temp, &audioOptions->audioLanguage.value);
int tempAudio = (int)((audioOptions->audio_language_temp * (1.0f/0xFFFF) * NUM_AUDIO_LANGUAGES));
tempAudio = (int)minf(maxf(0.0, tempAudio), NUM_AUDIO_LANGUAGES-1);
gSaveData.audio.audioLanguage = tempAudio;
audioOptions->audioLanguageDynamicText = menuBuildText(&gDejaVuSansFont, AudioLanguages[gSaveData.audio.audioLanguage], GAMEPLAY_X + 150, GAMEPLAY_Y + 68);
break;
} }
if (audioOptions->selectedItem == AudioOptionSubtitlesLanguage){ if (audioOptions->selectedItem == AudioOptionSubtitlesLanguage || audioOptions->selectedItem == AudioOptionAudioLanguage){
if ((controllerGetButtonDown(0, L_TRIG) || controllerGetButtonDown(0, Z_TRIG))) { if ((controllerGetButtonDown(0, L_TRIG) || controllerGetButtonDown(0, Z_TRIG))) {
return MenuDirectionLeft; return MenuDirectionLeft;
} }
@ -144,6 +164,11 @@ void audioOptionsRender(struct AudioOptions* audioOptions, struct RenderState* r
renderState->dl = menuSliderRender(&audioOptions->subtitlesLanguage, renderState->dl); renderState->dl = menuSliderRender(&audioOptions->subtitlesLanguage, renderState->dl);
} }
if (NUM_AUDIO_LANGUAGES > 1) {
gSPDisplayList(renderState->dl++, audioOptions->audioLanguage.back);
renderState->dl = menuSliderRender(&audioOptions->audioLanguage, renderState->dl);
}
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]); gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]);
@ -162,5 +187,14 @@ void audioOptionsRender(struct AudioOptions* audioOptions, struct RenderState* r
gSPDisplayList(renderState->dl++, audioOptions->subtitlesLanguageDynamicText); gSPDisplayList(renderState->dl++, audioOptions->subtitlesLanguageDynamicText);
} }
if (NUM_AUDIO_LANGUAGES > 1) {
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, audioOptions->selectedItem == AudioOptionAudioLanguage, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, audioOptions->audioLanguageText);
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, audioOptions->selectedItem == AudioOptionAudioLanguage, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, audioOptions->audioLanguageDynamicText);
}
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
} }

View file

@ -7,7 +7,7 @@
enum AudioOption { enum AudioOption {
AudioOptionSubtitlesEnabled, AudioOptionSubtitlesEnabled,
AudioOptionSubtitlesLanguage, AudioOptionSubtitlesLanguage,
AudioOptionAudioLanguage,
AudioOptionCount, AudioOptionCount,
}; };
@ -17,6 +17,10 @@ struct AudioOptions {
Gfx* subtitlesLanguageText; Gfx* subtitlesLanguageText;
Gfx* subtitlesLanguageDynamicText; Gfx* subtitlesLanguageDynamicText;
unsigned short subtitles_language_temp; unsigned short subtitles_language_temp;
struct MenuSlider audioLanguage;
Gfx* audioLanguageText;
Gfx* audioLanguageDynamicText;
unsigned short audio_language_temp;
short selectedItem; short selectedItem;
}; };
@ -24,4 +28,4 @@ void audioOptionsInit(struct AudioOptions* audioOptions);
enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions); enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions);
void audioOptionsRender(struct AudioOptions* audioOptions, struct RenderState* renderState, struct GraphicsTask* task); void audioOptionsRender(struct AudioOptions* audioOptions, struct RenderState* renderState, struct GraphicsTask* task);
#endif #endif

View file

@ -99,6 +99,7 @@ void savefileNew() {
gSaveData.audio.soundVolume = 0xFF; gSaveData.audio.soundVolume = 0xFF;
gSaveData.audio.musicVolume = 0xFF; gSaveData.audio.musicVolume = 0xFF;
gSaveData.audio.audioLanguage = 0;
controllerSetDeadzone(gSaveData.controls.deadzone * (1.0f / 0xFFFF) * MAX_DEADZONE); controllerSetDeadzone(gSaveData.controls.deadzone * (1.0f / 0xFFFF) * MAX_DEADZONE);
} }

View file

@ -57,6 +57,7 @@ struct ControlSaveState {
struct AudioSettingsSaveState { struct AudioSettingsSaveState {
unsigned char soundVolume; unsigned char soundVolume;
unsigned char musicVolume; unsigned char musicVolume;
unsigned char audioLanguage;
}; };
#define NO_TEST_CHAMBER 0xFF #define NO_TEST_CHAMBER 0xFF

View file

@ -7,6 +7,15 @@ let inputs = [];
let definePrefix = ''; let definePrefix = '';
let lastCommand = ''; let lastCommand = '';
let outputLanguagesSourceFile = '';
let outputLanguagesHeader = '';
let allSounds = [];
let languages = [];
let languages_codes = ["EN", "DE", "FR", "RU", "ES"];
let language_names = {"EN": "English", "DE": "German", "FR": "French", "RU": "Russian", "ES": "Spanish"};
let lookup = [];
languages.push("EN"); // Always included by default
for (let i = 2; i < process.argv.length; ++i) { for (let i = 2; i < process.argv.length; ++i) {
const arg = process.argv[i]; const arg = process.argv[i];
if (lastCommand) { if (lastCommand) {
@ -23,6 +32,10 @@ for (let i = 2; i < process.argv.length; ++i) {
} }
} }
outputLanguagesSourceFile = output + '/languages.c';
outputLanguagesHeader += output + '/languages.h';
output += '/clips.h';
inputs.push('TOTAL_COUNT'); inputs.push('TOTAL_COUNT');
const invalidCharactersRegex = /[^\w\d_]+/gm; const invalidCharactersRegex = /[^\w\d_]+/gm;
@ -31,6 +44,8 @@ function formatSoundName(soundFilename, index) {
const extension = path.extname(soundFilename); const extension = path.extname(soundFilename);
const lastPart = path.basename(soundFilename, extension); const lastPart = path.basename(soundFilename, extension);
const defineName = definePrefix + lastPart.replace(invalidCharactersRegex, '_').toUpperCase(); const defineName = definePrefix + lastPart.replace(invalidCharactersRegex, '_').toUpperCase();
trackSoundLanguages(soundFilename, defineName, index);
return `#define ${defineName} ${index}`; return `#define ${defineName} ${index}`;
} }
@ -44,4 +59,78 @@ ${soundFilenames.map(formatSoundName).join('\n')}
#endif` #endif`
} }
fs.writeFileSync(output, formatFile(output, inputs)); fs.writeFileSync(output, formatFile(output, inputs));
function trackSoundLanguages(soundFilename, defineName, index) {
languages_codes.forEach((language) => {
if (defineName.includes("_" + language + "_") && !languages.includes(language))
languages.push(language);
});
if (soundFilename != "TOTAL_COUNT")
allSounds.push({defineName: defineName, index: index});
}
function fillOverrideLookup() {
for (let language of languages) {
for (let overrideSound of allSounds) {
let baseSound = overrideSound;
let overrideName = overrideSound.defineName;
// check if current sound has base version of default language
if (overrideName.includes('_' + language + '_') && language != "EN") {
baseSound = allSounds.find(element => element.defineName == overrideName.replace('_' + language + '_', '_'));
}
lookup.push({language: language, baseIndex: baseSound.index, index: overrideSound.index, defineName: overrideSound.defineName});
}
}
}
function generateLanguagesHeader() {
let header = `#ifndef __LANGUAGES_H__
#define __LANGUAGES_H__
#define NUM_AUDIO_LANGUAGES ${languages.length}
extern char* AudioLanguages[];
extern int AudioLanguageValues[][${allSounds.length}];
`
header += 'enum AudioLanguagesKey\n{\n';
header += (languages.length > 0 ? '\tAUDIO_LANGUAGE_' + languages.join(',\n\tAUDIO_LANGUAGE_') + ',\n' : '');
header += '};\n';
header += '#endif';
return header;
}
function generateLanguagesSourceFile() {
fillOverrideLookup();
let sourcefile = '#include "languages.h"\n';
sourcefile += '\n';
sourcefile += 'char* AudioLanguages[] = \n{\n';
for (let language of languages) {
sourcefile += '\t"' + language_names[language].toUpperCase() + '",\n';
}
sourcefile += '};\n';
sourcefile += 'int AudioLanguageValues[][' + allSounds.length + '] = \n{\n';
for (let language of languages) {
sourcefile += '\t//' + language + '\n\t{\n';
for (let baseSound of allSounds) {
let overrideSound = lookup.find(lookElement => lookElement.language == language && lookElement.baseIndex == baseSound.index && lookElement.baseIndex != lookElement.index);
if (overrideSound === undefined) overrideSound = baseSound; // no override, use default
sourcefile += '\t' + overrideSound.index + ', // ' + baseSound.defineName + ' ('+baseSound.index+') -> ' + overrideSound.defineName + ' ('+ overrideSound.index+')' + '\n';
}
sourcefile += '\t},\n';
}
sourcefile += '};';
return sourcefile;
}
fs.writeFileSync(outputLanguagesHeader, generateLanguagesHeader());
fs.writeFileSync(outputLanguagesSourceFile, generateLanguagesSourceFile());