Merge pull request #263 from westonCoder/real-subtitles-addition

Added Subtitles to Game
This commit is contained in:
lambertjamesd 2023-10-07 19:16:57 -06:00 committed by GitHub
commit 8b539390b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 350 additions and 70 deletions

Binary file not shown.

View file

@ -12,13 +12,13 @@ cutscenes:
- delay 2
- show_prompt CutscenePromptTypeJump
- delay 3
- q_sound SOUNDS_00_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_2 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_3 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_4 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_5 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_6 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_7 CH_GLADOS
- q_sound SOUNDS_00_PART1_ENTRY_1 CH_GLADOS SUBTITLE_00_PART1_ENTRY_1
- q_sound SOUNDS_00_PART1_ENTRY_2 CH_GLADOS SUBTITLE_00_PART1_ENTRY_2
- q_sound SOUNDS_00_PART1_ENTRY_3 CH_GLADOS SUBTITLE_00_PART1_ENTRY_3
- q_sound SOUNDS_00_PART1_ENTRY_4 CH_GLADOS SUBTITLE_00_PART1_ENTRY_4
- q_sound SOUNDS_00_PART1_ENTRY_5 CH_GLADOS SUBTITLE_00_PART1_ENTRY_5
- q_sound SOUNDS_00_PART1_ENTRY_6 CH_GLADOS SUBTITLE_00_PART1_ENTRY_6
- q_sound SOUNDS_00_PART1_ENTRY_7 CH_GLADOS SUBTITLE_00_PART1_ENTRY_7
- delay 7
- show_prompt CutscenePromptTypeNone
- wait_for_channel CH_GLADOS
@ -30,9 +30,9 @@ cutscenes:
- set_signal cube_dropper
- show_prompt CutscenePromptTypePickup
- wait_for_signal success
- q_sound SOUNDS_00_PART1_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_00_PART1_SUCCESS_2 CH_GLADOS
- q_sound SOUNDS_00_PART1_SUCCESS_3 CH_GLADOS
- q_sound SOUNDS_00_PART1_SUCCESS_1 CH_GLADOS SUBTITLE_00_PART1_SUCCESS_1
- q_sound SOUNDS_00_PART1_SUCCESS_2 CH_GLADOS SUBTITLE_00_PART1_SUCCESS_2
- q_sound SOUNDS_00_PART1_SUCCESS_3 CH_GLADOS SUBTITLE_00_PART1_SUCCESS_3
START_SECOND_ROOM:
- start_cutscene SECOND_ROOM_INSTRUCTIONS
- open_portal stationary_portal 1
@ -45,8 +45,8 @@ cutscenes:
- delay 5
- goto portal_loop
SECOND_ROOM_INSTRUCTIONS:
- q_sound SOUNDS_00_PART2_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_00_PART2_ENTRY_1 CH_GLADOS SUBTITLE_00_PART2_ENTRY_1
- wait_for_signal success_1
- q_sound SOUNDS_00_PART2_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_00_PART2_SUCCESS_1 CH_GLADOS SUBTITLE_00_PART2_SUCCESS_1
HOVER_CUBE_PROMPT:
- show_prompt CutscenePromptTypeDrop

View file

@ -6,8 +6,8 @@ cutscenes:
- start_cutscene portal_loop
- set_signal FIRST_ELEVATOR
INTRO_CUTSCENE:
- q_sound SOUNDS_01_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_01_PART1_ENTRY_2 CH_GLADOS
- q_sound SOUNDS_01_PART1_ENTRY_1 CH_GLADOS SUBTITLE_01_PART1_ENTRY_1
- q_sound SOUNDS_01_PART1_ENTRY_2 CH_GLADOS SUBTITLE_01_PART1_ENTRY_2
- wait_for_channel CH_GLADOS
- set_signal room_0_entrance
GET_GUN:
@ -16,19 +16,19 @@ cutscenes:
- hide_pedestal
- stop_cutscene portal_loop
- show_prompt CutscenePromptTypePortal1
- q_sound 01_PART1_GET_PORTAL_GUN_1 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_2 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_3 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_4 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_5 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_6 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_7 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_8 CH_GLADOS
- q_sound 01_PART1_GET_PORTAL_GUN_1 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_1
- q_sound 01_PART1_GET_PORTAL_GUN_2 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_2
- q_sound 01_PART1_GET_PORTAL_GUN_3 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_3
- q_sound 01_PART1_GET_PORTAL_GUN_4 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_4
- q_sound 01_PART1_GET_PORTAL_GUN_5 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_5
- q_sound 01_PART1_GET_PORTAL_GUN_6 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_6
- q_sound 01_PART1_GET_PORTAL_GUN_7 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_7
- q_sound 01_PART1_GET_PORTAL_GUN_8 CH_GLADOS SUBTITLE_01_PART1_GET_PORTAL_GUN_8
MIND_THE_GAP:
- open_portal portal_gap 0
- q_sound SOUNDS_01_PART2_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_01_PART2_ENTRY_1 CH_GLADOS SUBTITLE_01_PART2_ENTRY_1
FINISH_03:
- q_sound SOUNDS_01_PART2_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_01_PART2_SUCCESS_1 CH_GLADOS SUBTITLE_01_PART2_SUCCESS_1
portal_loop:
- open_portal portal_exit 0
- label loop_start

View file

@ -1,25 +1,25 @@
cutscenes:
INTRO:
- q_sound SOUNDS_02_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_02_PART1_ENTRY_1 CH_GLADOS SUBTITLE_02_PART1_ENTRY_1
- wait_for_channel CH_GLADOS
- open_portal portal_0 0
- q_sound SOUNDS_02_PART1_ENTRY_2 CH_GLADOS
- q_sound SOUNDS_02_PART1_ENTRY_2 CH_GLADOS SUBTITLE_02_PART1_ENTRY_2
- wait_for_signal success
- q_sound SOUNDS_02_PART1_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_02_PART1_SUCCESS_2 CH_GLADOS
- q_sound SOUNDS_02_PART1_SUCCESS_1 CH_GLADOS SUBTITLE_02_PART1_SUCCESS_1
- q_sound SOUNDS_02_PART1_SUCCESS_2 CH_GLADOS SUBTITLE_02_PART1_SUCCESS_2
DROP_CUBE:
- set_signal cube_dropper
ENTER_BUTTON_ROOM:
- open_portal portal_1
BAD_PERSON:
- q_sound SOUNDS_ESCAPE_01_PART1_NAG01_1 CH_GLADOS
- q_sound SOUNDS_ESCAPE_01_PART1_NAG01_1 CH_GLADOS SUBTITLE_ESCAPE_01_PART1_NAG01_1
- wait_for_channel CH_GLADOS
- set_signal bad_person
ENTER_SMALL_ROOM:
- set_signal in_room
- open_portal portal_2 0
- q_sound SOUNDS_02_PART2_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_02_PART2_SUCCESS_2 CH_GLADOS
- q_sound SOUNDS_02_PART2_SUCCESS_1 CH_GLADOS SUBTITLE_02_PART2_SUCCESS_1
- q_sound SOUNDS_02_PART2_SUCCESS_2 CH_GLADOS SUBTITLE_02_PART2_SUCCESS_2
operators:
- should_open_door = exit_2_0 and exit_2_1
- should_open_door = should_open_door or bad_person

View file

@ -13,16 +13,16 @@ cutscenes:
- save_checkpoint 0.001
- open_portal ground_portal_2
- start_cutscene BALL_2
- q_sound SOUNDS_03_PART2_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_03_PART2_ENTRY_1 CH_GLADOS SUBTITLE_03_PART2_ENTRY_1
- wait_for_signal horizontal_activiate 2
- q_sound 03_PART2_PLATFORM_ACTIVATED_1 CH_GLADOS
- q_sound 03_PART2_PLATFORM_ACTIVATED_1 CH_GLADOS SUBTITLE_03_PART2_PLATFORM_ACTIVATED_1
INTRO:
- save_checkpoint 0
- open_portal ground_portal 0
- q_sound SOUNDS_03_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_03_PART1_ENTRY_2 CH_GLADOS
- q_sound SOUNDS_03_PART1_ENTRY_1 CH_GLADOS SUBTITLE_03_PART1_ENTRY_1
- q_sound SOUNDS_03_PART1_ENTRY_2 CH_GLADOS SUBTITLE_03_PART1_ENTRY_2
- wait_for_signal exit_activate 2
- q_sound SOUNDS_03_PART1_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_03_PART1_SUCCESS_1 CH_GLADOS SUBTITLE_03_PART1_SUCCESS_1
START_BALL:
- set_signal launch_ball
- wait_for_signal exit_activate

View file

@ -1,8 +1,8 @@
cutscenes:
SUCCESS:
- q_sound SOUNDS_04_PART1_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_04_PART1_SUCCESS_1 CH_GLADOS SUBTITLE_04_PART1_SUCCESS_1
INTRO_CUTSCENE:
- q_sound SOUNDS_04_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_04_PART1_ENTRY_1 CH_GLADOS SUBTITLE_04_PART1_ENTRY_1
DROWN_PLAYER:
- kill_player water
OPEN_PORTAL:

View file

@ -4,20 +4,20 @@ cutscenes:
INTRO_CUTSCENE:
- set_signal cube_dropper
- open_portal portal_0 0
- q_sound SOUNDS_05_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_ENTRY_2 CH_GLADOS
- q_sound SOUNDS_05_PART1_ENTRY_1 CH_GLADOS SUBTITLE_05_PART1_ENTRY_1
- q_sound SOUNDS_05_PART1_ENTRY_2 CH_GLADOS SUBTITLE_05_PART1_ENTRY_2
- start_cutscene NAG
- wait_for_signal success
- stop_cutscene NAG
- q_sound SOUNDS_05_PART1_SUCCESS_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_SUCCESS_1 CH_GLADOS SUBTITLE_05_PART1_SUCCESS_1
NAG:
- delay 28
- q_sound SOUNDS_05_PART1_NAG1_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_NAG1_1 CH_GLADOS SUBTITLE_05_PART1_NAG1_1
- delay 20
- q_sound SOUNDS_05_PART1_NAG2_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_NAG2_1 CH_GLADOS SUBTITLE_05_PART1_NAG2_1
- delay 25
- q_sound SOUNDS_05_PART1_NAG3_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_NAG3_1 CH_GLADOS SUBTITLE_05_PART1_NAG3_1
- delay 25.001
- q_sound SOUNDS_05_PART1_NAG4_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_NAG4_1 CH_GLADOS SUBTITLE_05_PART1_NAG4_1
- delay 26
- q_sound SOUNDS_05_PART1_NAG5_1 CH_GLADOS
- q_sound SOUNDS_05_PART1_NAG5_1 CH_GLADOS SUBTITLE_05_PART1_NAG5_1

View file

@ -8,16 +8,16 @@ cutscenes:
- play_animation piston_top piston_top_0
- play_animation piston_bottom piston_bottom_0
FIRST_ROOM:
- q_sound SOUNDS_06_PART1_ENTRY_1 CH_GLADOS
- q_sound SOUNDS_06_PART1_ENTRY_1 CH_GLADOS SUBTITLE_06_PART1_ENTRY_1
- delay 4
- open_portal first_room_portal 0
OPEN_FIRST_DOOR:
- set_signal room_0_exit
SECOND_SUCCESS:
- q_sound SOUNDS_06_PART1_SUCCESS_2_1 CH_GLADOS
- q_sound SOUNDS_06_PART1_SUCCESS_2_1 CH_GLADOS SUBTITLE_06_PART1_SUCCESS_2_1
- play_animation piston_top piston_top_1
FIRST_SUCCESS:
- q_sound SOUNDS_06_PART1_SUCCESS_1_1 CH_GLADOS
- q_sound SOUNDS_06_PART1_SUCCESS_1_1 CH_GLADOS SUBTITLE_06_PART1_SUCCESS_1_1
SECOND_ROOM:
- close_portal 0
- close_portal 1

View file

@ -25,17 +25,17 @@ cutscenes:
- start_cutscene portal_loop
- start_cutscene platform_ferry
- set_signal launch_ball
- q_sound 07_PART1_ENTRY_1 CH_GLADOS
- q_sound 07_PART1_ENTRY_2 CH_GLADOS
- q_sound 07_PART1_ENTRY_3 CH_GLADOS
- q_sound 07_PART1_ENTRY_1 CH_GLADOS SUBTITLE_07_PART1_ENTRY_1
- q_sound 07_PART1_ENTRY_2 CH_GLADOS SUBTITLE_07_PART1_ENTRY_2
- q_sound 07_PART1_ENTRY_3 CH_GLADOS SUBTITLE_07_PART1_ENTRY_3
TILT:
- delay 4
- set_signal cube_dropper
- play_animation tilt tilt
START_1:
- q_sound 07_PART2_ENTRY_1 CH_GLADOS
- q_sound 07_PART2_ENTRY_1 CH_GLADOS SUBTITLE_07_PART2_ENTRY_1
- wait_for_signal weeeee
- q_sound 07_PART2_SUCCESS_1 CH_GLADOS
- q_sound 07_PART2_SUCCESS_1 CH_GLADOS SUBTITLE_07_PART2_SUCCESS_1
portal_loop:
- label loop_start
- open_portal portal_0 0
@ -60,12 +60,12 @@ cutscenes:
- start_cutscene platform_loop
- close_portal 0
- show_prompt CutscenePromptTypePortal0
- q_sound 07_PART1_GET_DEVICE_COMPONENT_1 CH_GLADOS
- q_sound 07_PART1_GET_DEVICE_COMPONENT_2 CH_GLADOS
- q_sound 07_PART1_GET_DEVICE_COMPONENT_3 CH_GLADOS
- q_sound 07_PART1_GET_DEVICE_COMPONENT_1 CH_GLADOS SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_1
- q_sound 07_PART1_GET_DEVICE_COMPONENT_2 CH_GLADOS SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_2
- q_sound 07_PART1_GET_DEVICE_COMPONENT_3 CH_GLADOS SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_3
- wait_for_signal trapped
- q_sound 07_PART1_TRAPPED_1 CH_GLADOS
- q_sound 07_PART1_TRAPPED_2 CH_GLADOS
- q_sound 07_PART1_TRAPPED_1 CH_GLADOS SUBTITLE_07_PART1_TRAPPED_1
- q_sound 07_PART1_TRAPPED_2 CH_GLADOS SUBTITLE_07_PART1_TRAPPED_2
- wait_for_channel CH_GLADOS
- set_signal trap_door
PROMPT_SWITCH:

View file

@ -18,6 +18,7 @@ u64 gTriggeredCutscenes;
struct QueuedSound {
struct QueuedSound* next;
u16 soundId;
u16 subtitleId;
float volume;
};
@ -94,7 +95,7 @@ void cutsceneRunnerCancel(struct CutsceneRunner* runner) {
runner->currentCutscene = NULL;
}
void cutsceneQueueSound(int soundId, float volume, int channel) {
void cutsceneQueueSound(int soundId, float volume, int channel, int subtitleId) {
struct QueuedSound* next = gCutsceneNextFreeSound;
if (!next) {
@ -106,6 +107,7 @@ void cutsceneQueueSound(int soundId, float volume, int channel) {
next->next = NULL;
next->soundId = soundId;
next->volume = volume;
next->subtitleId = subtitleId;
struct QueuedSound* tail = gCutsceneSoundQueues[channel];
@ -140,7 +142,7 @@ void cutsceneRunnerStartStep(struct CutsceneRunner* runner) {
break;
case CutsceneStepTypeQueueSound:
{
cutsceneQueueSoundInChannel(step->queueSound.soundId, step->queueSound.volume * (1.0f / 255.0f), step->queueSound.channel);
cutsceneQueueSoundInChannel(step->queueSound.soundId, step->queueSound.volume * (1.0f / 255.0f), step->queueSound.channel, step->queueSound.subtitleId);
break;
}
case CutsceneStepTypeDelay:
@ -395,6 +397,8 @@ void cutscenesUpdateSounds() {
struct QueuedSound* curr = gCutsceneSoundQueues[i];
gCutsceneCurrentSound[i] = soundPlayerPlay(curr->soundId, curr->volume, gCutsceneChannelPitch[i], NULL, NULL);
hudShowSubtitle(&gScene.hud, curr->subtitleId);
gCutsceneSoundQueues[i] = curr->next;
curr->next = gCutsceneNextFreeSound;
@ -402,6 +406,7 @@ void cutscenesUpdateSounds() {
} else {
if (gCutsceneCurrentSound[i] != SOUND_ID_NONE) {
soundPlayerPlay(soundsIntercom[1], 1.0f, gCutsceneChannelPitch[i], NULL, NULL);
hudResolveSubtitle(&gScene.hud);
}
gCutsceneCurrentSound[i] = SOUND_ID_NONE;
@ -563,20 +568,23 @@ void cutsceneSerializeRead(struct Serializer* serializer) {
for (int i = 0; i < CH_COUNT; ++i) {
s16 nextId;
serializeRead(serializer, &nextId, sizeof(nextId));
while (nextId != SOUND_ID_NONE) {
s16 nextSubtitleId;
serializeRead(serializer, &nextSubtitleId, sizeof(nextSubtitleId));
u8 volume;
serializeRead(serializer, &volume, sizeof(volume));
cutsceneQueueSound(nextId, volume * (1.0f / 255.0f), i);
cutsceneQueueSound(nextId, volume * (1.0f / 255.0f), i, nextSubtitleId);
serializeRead(serializer, &nextId, sizeof(nextId));
}
}
}
void cutsceneQueueSoundInChannel(int soundId, float volume, int channel) {
void cutsceneQueueSoundInChannel(int soundId, float volume, int channel, int subtitleId) {
if (!gCutsceneSoundQueues[channel] && !soundPlayerIsPlaying(gCutsceneCurrentSound[channel])) {
cutsceneQueueSound(soundsIntercom[0], volume, channel);
cutsceneQueueSound(soundsIntercom[0], volume, channel, subtitleId);
}
cutsceneQueueSound(soundId, volume, channel);
cutsceneQueueSound(soundId, volume, channel, subtitleId);
}

View file

@ -43,6 +43,6 @@ void cutsceneSerializeWrite(struct Serializer* serializer, SerializeAction actio
void cutsceneSerializeRead(struct Serializer* serializer);
int cutsceneRunnerIsChannelPlaying(int channel);
void cutsceneQueueSoundInChannel(int soundId, float volume, int channel);
void cutsceneQueueSoundInChannel(int soundId, float volume, int channel, int subtitleId);
#endif

View file

@ -63,6 +63,70 @@ enum CutscenePromptType {
CutscenePromptTypeJump,
};
enum CutsceneSubtitleType {
CutsceneSubtitleTypeNone,
SUBTITLE_00_PART1_ENTRY_1,
SUBTITLE_00_PART1_ENTRY_2,
SUBTITLE_00_PART1_ENTRY_3,
SUBTITLE_00_PART1_ENTRY_4,
SUBTITLE_00_PART1_ENTRY_5,
SUBTITLE_00_PART1_ENTRY_6,
SUBTITLE_00_PART1_ENTRY_7,
SUBTITLE_00_PART1_SUCCESS_1,
SUBTITLE_00_PART1_SUCCESS_2,
SUBTITLE_00_PART1_SUCCESS_3,
SUBTITLE_00_PART2_ENTRY_1,
SUBTITLE_00_PART2_SUCCESS_1,
SUBTITLE_01_PART1_ENTRY_1,
SUBTITLE_01_PART1_ENTRY_2,
SUBTITLE_01_PART1_GET_PORTAL_GUN_1,
SUBTITLE_01_PART1_GET_PORTAL_GUN_2,
SUBTITLE_01_PART1_GET_PORTAL_GUN_3,
SUBTITLE_01_PART1_GET_PORTAL_GUN_4,
SUBTITLE_01_PART1_GET_PORTAL_GUN_5,
SUBTITLE_01_PART1_GET_PORTAL_GUN_6,
SUBTITLE_01_PART1_GET_PORTAL_GUN_7,
SUBTITLE_01_PART1_GET_PORTAL_GUN_8,
SUBTITLE_01_PART2_ENTRY_1,
SUBTITLE_01_PART2_SUCCESS_1,
SUBTITLE_02_PART1_ENTRY_1,
SUBTITLE_02_PART1_ENTRY_2,
SUBTITLE_02_PART1_SUCCESS_1,
SUBTITLE_02_PART1_SUCCESS_2,
SUBTITLE_ESCAPE_01_PART1_NAG01_1,
SUBTITLE_02_PART2_SUCCESS_1,
SUBTITLE_02_PART2_SUCCESS_2,
SUBTITLE_03_PART2_ENTRY_1,
SUBTITLE_03_PART2_PLATFORM_ACTIVATED_1,
SUBTITLE_03_PART1_ENTRY_1,
SUBTITLE_03_PART1_ENTRY_2,
SUBTITLE_03_PART1_SUCCESS_1,
SUBTITLE_04_PART1_SUCCESS_1,
SUBTITLE_04_PART1_ENTRY_1,
SUBTITLE_05_PART1_ENTRY_1,
SUBTITLE_05_PART1_ENTRY_2,
SUBTITLE_05_PART1_SUCCESS_1,
SUBTITLE_05_PART1_NAG1_1,
SUBTITLE_05_PART1_NAG2_1,
SUBTITLE_05_PART1_NAG3_1,
SUBTITLE_05_PART1_NAG4_1,
SUBTITLE_05_PART1_NAG5_1,
SUBTITLE_06_PART1_ENTRY_1,
SUBTITLE_06_PART1_SUCCESS_2_1,
SUBTITLE_06_PART1_SUCCESS_1_1,
SUBTITLE_07_PART1_ENTRY_1,
SUBTITLE_07_PART1_ENTRY_2,
SUBTITLE_07_PART1_ENTRY_3,
SUBTITLE_07_PART2_ENTRY_1,
SUBTITLE_07_PART2_SUCCESS_1,
SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_1,
SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_2,
SUBTITLE_07_PART1_GET_DEVICE_COMPONENT_3,
SUBTITLE_07_PART1_TRAPPED_1,
SUBTITLE_07_PART1_TRAPPED_2,
};
#define CH_NONE 0xFF
#define CH_GLADOS 0
@ -80,6 +144,7 @@ struct CutsceneStep {
struct {
u16 soundId;
u8 channel;
u16 subtitleId;
u8 volume;
} queueSound;
struct {

View file

@ -1,9 +1,22 @@
#include "audio_options.h"
#include "../controls/controller.h"
#include "../savefile/savefile.h"
#include "../font/dejavusans.h"
#include "../audio/soundplayer.h"
#include "../build/assets/materials/ui.h"
#include "../build/src/audio/clips.h"
#define GAMEPLAY_Y 54
#define GAMEPLAY_WIDTH 252
#define GAMEPLAY_HEIGHT 124
#define GAMEPLAY_X ((SCREEN_WD - GAMEPLAY_WIDTH) / 2)
void audioOptionsInit(struct AudioOptions* audioOptions) {
audioOptions->selectedItem = 0;
audioOptions->selectedItem = AudioOptionSubtitlesEnabled;
audioOptions->subtitlesEnabled = menuBuildCheckbox(&gDejaVuSansFont, "Closed Captions", GAMEPLAY_X + 8, GAMEPLAY_Y + 8);
audioOptions->subtitlesEnabled.checked = (gSaveData.controls.flags & ControlSaveSubtitlesEnabled) != 0;
}
enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions) {
@ -13,6 +26,38 @@ enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions) {
return MenuDirectionUp;
}
if (controllerDir & ControllerDirectionDown) {
++audioOptions->selectedItem;
if (audioOptions->selectedItem == AudioOptionCount) {
audioOptions->selectedItem = 0;
}
}
if (controllerDir & ControllerDirectionUp) {
if (audioOptions->selectedItem == 0) {
audioOptions->selectedItem = AudioOptionCount - 1;
} else {
--audioOptions->selectedItem;
}
}
switch (audioOptions->selectedItem) {
case AudioOptionSubtitlesEnabled:
if (controllerGetButtonDown(0, A_BUTTON)) {
audioOptions->subtitlesEnabled.checked = !audioOptions->subtitlesEnabled.checked;
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL);
if (audioOptions->subtitlesEnabled.checked) {
gSaveData.controls.flags |= ControlSaveSubtitlesEnabled;
} else {
gSaveData.controls.flags &= ~ControlSaveSubtitlesEnabled;
}
}
break;
}
if ((controllerDir & ControllerDirectionLeft || controllerGetButtonDown(0, L_TRIG) || controllerGetButtonDown(0, Z_TRIG))) {
return MenuDirectionLeft;
}
@ -25,5 +70,18 @@ enum MenuDirection audioOptionsUpdate(struct AudioOptions* audioOptions) {
}
void audioOptionsRender(struct AudioOptions* audioOptions, struct RenderState* renderState, struct GraphicsTask* task) {
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, audioOptions->subtitlesEnabled.outline);
renderState->dl = menuCheckboxRender(&audioOptions->subtitlesEnabled, renderState->dl);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]);
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, audioOptions->selectedItem == AudioOptionSubtitlesEnabled, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, audioOptions->subtitlesEnabled.text);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
}

View file

@ -4,7 +4,14 @@
#include "./menu.h"
#include "../graphics/graphics.h"
enum AudioOption {
AudioOptionSubtitlesEnabled,
AudioOptionCount,
};
struct AudioOptions {
struct MenuCheckbox subtitlesEnabled;
short selectedItem;
};

View file

@ -461,6 +461,11 @@ void controlsMenuRender(struct ControlsMenu* controlsMenu, struct RenderState* r
#define CONTROL_PROMPT_HEIGHT 24
#define CONTROL_PROMPT_PADDING 6
#define SUBTITLE_LEFT_MARGIN 10
#define SUBTITLE_BOTTOM_MARGIN 10
#define SUBTITLE_PADDING 5
void controlsRenderPrompt(enum ControllerAction action, char* message, float opacity, struct RenderState* renderState) {
struct Vector2s16 size = fontMeasure(&gDejaVuSansFont, message);
@ -503,4 +508,41 @@ void controlsRenderPrompt(enum ControllerAction action, char* message, float opa
gDPSetEnvColor(renderState->dl++, 232, 206, 80, opacityAsInt);
renderState->dl = controlsRenderIcons(renderState->dl, action, textPositionX - CONTROL_PROMPT_PADDING, textPositionY);
gSPDisplayList(renderState->dl++, ui_material_revert_list[BUTTON_ICONS_INDEX]);
}
void controlsRenderSubtitle(char* message, float opacity, struct RenderState* renderState) {
struct Vector2s16 size = fontMeasure(&gDejaVuSansFont, message);
int opacityAsInt = (int)(255 * opacity);
if (opacityAsInt > 255) {
opacityAsInt = 255;
} else if (opacityAsInt < 0) {
opacityAsInt = 0;
}
int textPositionX = (SUBTITLE_LEFT_MARGIN + SUBTITLE_PADDING);
int textPositionY = (SCREEN_HT - SUBTITLE_BOTTOM_MARGIN - SUBTITLE_PADDING) - size.y;
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gDPSetEnvColor(renderState->dl++, 0, 0, 0, opacityAsInt / 3);
gDPFillRectangle(
renderState->dl++,
textPositionX - CONTROL_PROMPT_PADDING,
textPositionY - CONTROL_PROMPT_PADDING,
textPositionX + size.x + CONTROL_PROMPT_PADDING,
SCREEN_HT - SUBTITLE_BOTTOM_MARGIN
);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]);
gDPSetEnvColor(renderState->dl++, 255, 60, 60, opacityAsInt);
renderState->dl = fontRender(
&gDejaVuSansFont,
message,
textPositionX,
textPositionY,
renderState->dl
);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
}

View file

@ -42,5 +42,6 @@ enum MenuDirection controlsMenuUpdate(struct ControlsMenu* controlsMenu);
void controlsMenuRender(struct ControlsMenu* controlsMenu, struct RenderState* renderState, struct GraphicsTask* task);
void controlsRenderPrompt(enum ControllerAction action, char* message, float opacity, struct RenderState* renderState);
void controlsRenderSubtitle(char* message, float opacity, struct RenderState* renderState);
#endif

View file

@ -38,6 +38,8 @@ enum ControlSaveFlags {
ControlSaveFlagsInvertYaw = (1 << 1),
ControlSaveTankControls = (1 << 2),
ControlSaveSubtitlesEnabled = (1 << 5),
ControlSaveMoveablePortals = (1 << 8),
ControlSaveWideScreen = (1 << 9),
};

View file

@ -6,6 +6,7 @@
#include "../util/time.h"
#include "../levels/levels.h"
#include "./scene.h"
#include "../savefile/savefile.h"
#define HUD_CENTER_WIDTH 6
#define HUD_CENTER_HEIGHT 8
@ -35,6 +36,7 @@
void hudInit(struct Hud* hud) {
hud->promptType = CutscenePromptTypeNone;
hud->promptOpacity = 0.0f;
hud->subtitleOpacity = 0.0f;
hud->flags = 0;
hud->resolvedPrompts = 0;
@ -58,14 +60,20 @@ void hudUpdate(struct Hud* hud) {
}
float targetPromptOpacity = (hud->flags & HudFlagsShowingPrompt) ? 1.0 : 0.0f;
float targetSubtitleOpacity = (hud->flags & HudFlagsShowingSubtitle) ? 0.7: 0.0f;
if (targetPromptOpacity != hud->promptOpacity) {
hud->promptOpacity = mathfMoveTowards(hud->promptOpacity, targetPromptOpacity, FIXED_DELTA_TIME / PROMPT_FADE_TIME);
}
if (targetSubtitleOpacity != hud->subtitleOpacity) {
hud->subtitleOpacity = mathfMoveTowards(hud->subtitleOpacity, targetSubtitleOpacity, FIXED_DELTA_TIME / PROMPT_FADE_TIME);
}
if (targetPromptOpacity && (hud->resolvedPrompts & (1 << hud->promptType)) != 0) {
hudShowActionPrompt(hud, CutscenePromptTypeNone);
}
}
void hudUpdatePortalIndicators(struct Hud* hud, struct Ray* raycastRay, struct Vector3* playerUp) {
@ -117,6 +125,71 @@ char* gPromptText[] = {
"TO JUMP",
};
char* gSubtitleText[] = {
"",
"Hello and, again, welcome to the Aperture Science \ncomputer-aided enrichment center.",
"We hope your brief detention in the relaxation \nvault has been a pleasant one.",
"Your specimen has been processed and we are now\nready to begin the test proper.",
"Before we start, however, keep in mind that \nalthough fun and learning are the primary goals of\nall enrichment center activities, serious\ninjuries may occur.",
"For your own safety and the safety of others, \nplease refrain from t-*bzzzzzt*",
"Por favor bordón de fallar. Muchos gracias de \nfallar gra-*bzzt*",
"Stand back. The portal will open in three, two, one.",
"Excellent. Please proceed into the chamberlock\nafter completing each test.",
"First, however, note the incandescent particle\nfield across the exit.",
"This Aperture Science Material Emancipation Grid\nwill vaporize any unauthorized equipment that\npasses through it - for instance, the Aperture\nScience Weighted Storage Cube.",
"Please place the Weighted Storage Cube on the \nFifteen Hundred Megawatt Aperture Science Heavy \nDuty Super-Colliding Super Button.",
"Perfect. Please move quickly to the chamberlock,\nas the effects of prolonged exposure to the \nbutton are not part of this test.",
"You're doing very well!",
"Please be advised that a noticeable taste of blood\nis not part of any test protocol but is an \nunintended side effect of the Aperture Science \nMaterial Emancipation Grill, which may,\nin semi-rare cases, emancipate dental \nfillings, crowns, tooth enamel and teeth.",
"Very good! You are now in possession of the \nAperture Science Handheld Portal Device.",
"With it, you can create your own portals.",
"These intra dimensional gates have proven to \nbe completely safe.",
"The device, however, has not.",
"Do not touch the operational end of the device.",
"Do not look directly at the operational end of the\ndevice.",
"Do not submerge the device in liquid, even partially.",
"Most importantly, under no circumstances should \nyou-*bzzzpt*",
"Please proceed to the chamberlock. Mind the gap.",
"Well done! Remember: The Aperture Science Bring \nYour Daughter to Work Day is the perfect time to\nhave her tested.",
"Welcome to test chamber four.",
"You're doing quite well.",
"Once again, excellent work.",
"As part of a required test protocol, we will not \nmonitor the next test chamber. You will be \nentirely on your own.Good luck.",
"You're not a good person. You know that, right?",
"As part of a required test protocol, our previous\nstatement suggesting that we would not monitor \nthis chamber was an outright fabrication.",
"Good job! As part of a required test protocol, we\nwill stop enhancing the truth in three, two, o-\n*bzzt*",
"Warning devices are required on all mobile \nequipment. However, alarms and flashing hazard lights \nhave been found to agitate the high energy pellet\nand have therefore been disabled for \nyour safety.",
"Good. Now use the Aperture Science Unstationary\nScaffold to reach the chamberlock.",
"While safety is one of many Enrichment Center goals,\nthe Aperture Science High Energy Pellet, seen \nto the left of the chamber, can and has \ncaused permanent disabilities such as \nvaporization.",
"Please be careful.",
"Unbelievable! You, <B>Subject Name Here<B>, must be\nthe pride of <B>Subject Hometown Here<B>.",
"Very impressive. Please note that any appearance of\ndanger is merely a device to enhance your \ntesting experience.",
"Please note that we have added a consequence for \nfailure. Any contact with the chamber floor will \nresult in an 'unsatisfactory' mark on your \nofficial testing record followed by \ndeath. Good luck!",
"The Enrichment Center regrets to inform you that\nthis next test is impossible.",
"Make no attempt to solve it.",
"Fantastic! You remained resolute and resourceful in\nan atmosphere of extreme pessimism.",
"The Enrichment Center apologizes for this clearly \nbroken test chamber.",
"Once again, the Enrichment Center offers its most \nsincere apologies on the occasion of this \nunsolvable test environment.",
"Frankly, this chamber was a mistake. If we were you,\nwe would quit now.",
"No one will blame you for giving up. In fact, quitting\nat this point is a perfectly reasonable \nresponse.",
"Quit now and cake will be served immediately.",
"Hello again. To reiterate our previous warning: This\ntest (garbled) -ard momentum.",
"Momentum, a function of mass and velocity, is\nconserved between portals. In layman's terms: speedy\nthing goes in, speedy thing comes out.",
"Spectacular. You appear to understand how a portal\naffects forward momentum, or to be more precise,\nhow it does not.",
"The Enrichment Center promises to always provide a\nsafe testing environment.",
"In dangerous testing environments, the Enrichment \nCenter promises to always provide useful advice.",
"For instance, the floor here will kill you - try to \navoid it.",
"Get ot ydaer f-f-fling yourself. F-Fling into sp\n-*bzzt*",
"Weeeeeeeeeeeeeeeeeeeeee-*bzzt*",
"The device has been modified so that it can now \nmanufacture two linked portals at once.",
"As part of an optional test protocol, we are pleased\nto present an amusing fact:",
"The device is now more valuable than the organs \nand combined incomes of everyone in <B>Subject \nHometown Here<B>.",
"Through no fault of the Enrichment Center, you \nhave managed to trap yourself in this room.",
"An escape hatch will open in three, two, one."
};
void hudShowActionPrompt(struct Hud* hud, enum CutscenePromptType promptType) {
if (promptType == CutscenePromptTypeNone) {
hud->flags &= ~HudFlagsShowingPrompt;
@ -127,10 +200,24 @@ void hudShowActionPrompt(struct Hud* hud, enum CutscenePromptType promptType) {
hud->promptType = promptType;
}
void hudShowSubtitle(struct Hud* hud, enum CutsceneSubtitleType subtitleType) {
if (subtitleType == CutsceneSubtitleTypeNone) {
hud->flags &= ~HudFlagsShowingSubtitle;
return;
}
hud->flags |= HudFlagsShowingSubtitle;
hud->subtitleType = subtitleType;
}
void hudResolvePrompt(struct Hud* hud, enum CutscenePromptType promptType) {
hud->resolvedPrompts |= (1 << promptType);
}
void hudResolveSubtitle(struct Hud* hud) {
hud->flags &= ~HudFlagsShowingSubtitle;
}
void hudRender(struct Hud* hud, struct Player* player, struct RenderState* renderState) {
if (player->flags & PlayerIsDead) {
gSPDisplayList(renderState->dl++, hud_death_overlay);
@ -245,4 +332,8 @@ void hudRender(struct Hud* hud, struct Player* player, struct RenderState* rende
if (hud->promptOpacity > 0.0f && hud->promptType != CutscenePromptTypeNone) {
controlsRenderPrompt(gPromptActions[hud->promptType], gPromptText[hud->promptType], hud->promptOpacity, renderState);
}
if (hud->subtitleOpacity > 0.0f && gSaveData.controls.flags & ControlSaveSubtitlesEnabled) {
controlsRenderSubtitle(gSubtitleText[hud->subtitleType], hud->subtitleOpacity, renderState);
}
}

View file

@ -13,11 +13,14 @@ enum HudFlags {
HudFlagsLookedPortalable0 = (1 << 0),
HudFlagsLookedPortalable1 = (1 << 1),
HudFlagsShowingPrompt = (1 << 2),
HudFlagsShowingSubtitle= (1 << 3),
};
struct Hud {
enum CutscenePromptType promptType;
enum CutsceneSubtitleType subtitleType;
float promptOpacity;
float subtitleOpacity;
float fadeInTimer;
@ -35,6 +38,8 @@ void hudUpdatePortalIndicators(struct Hud* hud, struct Ray* raycastRay, struct
void hudPortalFired(struct Hud* hud, int index);
void hudShowActionPrompt(struct Hud* hud, enum CutscenePromptType promptType);
void hudResolvePrompt(struct Hud* hud, enum CutscenePromptType promptType);
void hudShowSubtitle(struct Hud* hud, enum CutsceneSubtitleType subtitleType);
void hudResolveSubtitle(struct Hud* hud);
void hudRender(struct Hud* hud, struct Player* player, struct RenderState* renderState);

View file

@ -171,7 +171,7 @@ void securityCamerasCheckPortal(struct SecurityCamera* securityCameras, int came
if (!cutsceneRunnerIsChannelPlaying(CH_GLADOS)) {
short clipIndex = randomInRange(0, sizeof(gCameraDestroyClips) / sizeof(*gCameraDestroyClips));
cutsceneQueueSoundInChannel(gCameraDestroyClips[clipIndex], 1.0f, CH_GLADOS);
cutsceneQueueSoundInChannel(gCameraDestroyClips[clipIndex], 1.0f, CH_GLADOS, CutsceneSubtitleTypeNone);
}
}
}

View file

@ -99,12 +99,13 @@ local function generate_cutscene_step(cutscene_name, step, step_index, label_loc
tonumber(step.args[2] or "1") * 255,
math.floor(tonumber(step.args[3] or "1") * 64 + 0.5),
}
elseif step.command == "q_sound" and #step.args >= 2 then
elseif step.command == "q_sound" and #step.args >= 3 then
result.type = sk_definition_writer.raw('CutsceneStepTypeQueueSound')
result.queueSound = {
sk_definition_writer.raw(string_starts_with(step.args[1], "SOUNDS_") and step.args[1] or ("SOUNDS_" .. step.args[1])),
sk_definition_writer.raw(step.args[2]),
tonumber(step.args[3] or "1") * 255,
sk_definition_writer.raw(step.args[3]),
tonumber(step.args[4] or "1") * 255,
}
elseif step.command == "wait_for_channel" and #step.args >= 1 then
result.type = sk_definition_writer.raw('CutsceneStepTypeWaitForChannel')