Fix bugs in level transitions

This commit is contained in:
James Lambert 2022-08-11 19:04:13 -06:00
parent d48c57a19e
commit 338b197dcc
10 changed files with 169 additions and 13 deletions

View file

@ -183,7 +183,7 @@ ANIM_LIST = build/assets/models/pedestal_anim.o
MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h)
MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o)
build/assets/models/%.h build/assets/models/%_geo.c: build/assets/models/%.fbx assets/models/%.flags assets/materials/elevator.skm.yaml assets/materials/objects.skm.yaml assets/materials/static.skm.yaml $(SKELATOOL64)
build/assets/models/%.h build/assets/models/%_geo.c build/assets/models/%_anim.c: build/assets/models/%.fbx assets/models/%.flags assets/materials/elevator.skm.yaml assets/materials/objects.skm.yaml assets/materials/static.skm.yaml $(SKELATOOL64)
$(SKELATOOL64) --fixed-point-scale 256 --model-scale 0.01 --name $(<:build/assets/models/%.fbx=%) $(shell cat $(<:build/assets/models/%.fbx=assets/models/%.flags)) -o $(<:%.fbx=%.h) $<
build/src/models/models.o: $(MODEL_HEADERS)
@ -194,8 +194,6 @@ build/src/scene/portal.o: $(MODEL_HEADERS)
build/src/scene/signage.o: $(MODEL_HEADERS)
build/assets/models/%_anim.o: build/assets/models/%.h
build/anims.ld: $(ANIM_LIST) tools/generate_animation_ld.js
@mkdir -p $(@D)
node tools/generate_animation_ld.js $@ $(ANIM_LIST)

View file

@ -84,12 +84,15 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
## Current TODO list
- [ ] Prevent Glados from talking over herself
- [ ] It is too easy to fall through portals
- [ ] Elevator and door sounds
- [ ] Presort portal gun polygon order
- [ ] Change the way player standing logic works
- [ ] Cube dispenser
- [ ] Signage should not always be on
- [ ] Camera shake
- [x] crash on level transition
- [x] Prevent Glados from talking over herself
- [x] NAN in overlap
- [x] Turn level indicator board into a game object
- [x] kill plane

View file

@ -1 +1 @@
-r 90,0,0 -m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material button
-r 0,0,0 -m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material button

View file

@ -50,7 +50,12 @@ std::unique_ptr<StructureDataChunk> generateCutsceneStep(CutsceneStep& step, int
if ((step.command == "play_sound" || step.command == "start_sound") && step.args.size() >= 1) {
result->AddPrimitive<const char*>(step.command == "play_sound" ? "CutsceneStepTypePlaySound" : "CutsceneStepTypeStartSound");
std::unique_ptr<StructureDataChunk> playSound(new StructureDataChunk());
playSound->AddPrimitive(step.args[0]);
if (StartsWith(step.args[0], "SOUNDS_")) {
playSound->AddPrimitive(step.args[0]);
} else {
playSound->AddPrimitive(std::string("SOUNDS_") + step.args[0]);
}
if (step.args.size() >= 2) {
playSound->AddPrimitive((int)(std::atof(step.args[1].c_str()) * 255.0f));
@ -66,6 +71,35 @@ std::unique_ptr<StructureDataChunk> generateCutsceneStep(CutsceneStep& step, int
result->Add("playSound", std::move(playSound));
return result;
} else if (step.command == "q_sound" && step.args.size() >= 2) {
result->AddPrimitive<const char*>("CutsceneStepTypeQueueSound");
std::unique_ptr<StructureDataChunk> queueSound(new StructureDataChunk());
if (StartsWith(step.args[0], "SOUNDS_")) {
queueSound->AddPrimitive(step.args[0]);
} else {
queueSound->AddPrimitive(std::string("SOUNDS_") + step.args[0]);
}
// channel
queueSound->AddPrimitive(step.args[1]);
// volume
if (step.args.size() >= 3) {
queueSound->AddPrimitive((int)(std::atof(step.args[2].c_str()) * 255.0f));
} else {
queueSound->AddPrimitive(255);
}
result->Add("queueSound", std::move(queueSound));
return result;
} else if (step.command == "wait_for_channel" && step.args.size() >= 1) {
result->AddPrimitive<const char*>("CutsceneStepTypeWaitForChannel");
std::unique_ptr<StructureDataChunk> waitForChannel(new StructureDataChunk());
waitForChannel->AddPrimitive(step.args[0]);
result->Add("waitForChannel", std::move(waitForChannel));
return result;
} else if (step.command == "delay" && step.args.size() >= 1) {
result->AddPrimitive<const char*>("CutsceneStepTypeDelay");

View file

@ -9,6 +9,39 @@
struct CutsceneRunner* gRunningCutscenes;
struct CutsceneRunner* gUnusedRunners;
#define MAX_QUEUE_LENGTH 16
struct QueuedSound {
struct QueuedSound* next;
u16 soundId;
float volume;
};
struct QueuedSound gCutsceneSoundNodes[MAX_QUEUE_LENGTH];
struct QueuedSound* gCutsceneNextFreeSound;
struct QueuedSound* gCutsceneSoundQueues[CH_COUNT];
ALSndId gCutsceneCurrentSound[CH_COUNT];
float gCutsceneChannelPitch[CH_COUNT] = {
[CH_GLADOS] = 0.5f,
};
void cutsceneRunnerReset() {
gRunningCutscenes = NULL;
for (int i = 0; i < MAX_QUEUE_LENGTH; ++i) {
gCutsceneSoundNodes[i].next = (i + 1) < MAX_QUEUE_LENGTH ? &gCutsceneSoundNodes[i + 1] : NULL;
}
gCutsceneNextFreeSound = &gCutsceneSoundNodes[0];
for (int i = 0; i < CH_COUNT; ++i) {
gCutsceneSoundQueues[i] = NULL;
gCutsceneCurrentSound[i] = SOUND_ID_NONE;
}
}
struct CutsceneRunner* cutsceneRunnerNew() {
struct CutsceneRunner* result;
@ -31,6 +64,7 @@ void cutsceneRunnerCancel(struct CutsceneRunner* runner) {
switch (step->type) {
case CutsceneStepTypePlaySound:
case CutsceneStepTypeStartSound:
soundPlayerStop(runner->state.playSound.soundId);
break;
default:
@ -40,17 +74,50 @@ void cutsceneRunnerCancel(struct CutsceneRunner* runner) {
runner->currentCutscene = NULL;
}
ALSndId cutsceneRunnerPlaySound(struct CutsceneStep* step) {
return soundPlayerPlay(
step->playSound.soundId,
step->playSound.volume * (1.0f / 255.0f),
step->playSound.pitch * (1.0f / 64.0f),
NULL
);
}
void cutsceneQueueSound(int soundId, float volume, int channel) {
struct QueuedSound* next = gCutsceneNextFreeSound;
if (!next) {
return;
}
gCutsceneNextFreeSound = gCutsceneNextFreeSound->next;
next->next = NULL;
next->soundId = soundId;
next->volume = volume;
struct QueuedSound* tail = gCutsceneSoundQueues[channel];
while (tail && tail->next) {
tail = tail->next;
}
if (tail) {
tail->next = next;
} else {
gCutsceneSoundQueues[channel] = next;
}
}
void cutsceneRunnerStartStep(struct CutsceneRunner* runner) {
struct CutsceneStep* step = &runner->currentCutscene->steps[runner->currentStep];
switch (step->type) {
case CutsceneStepTypePlaySound:
case CutsceneStepTypeStartSound:
runner->state.playSound.soundId = soundPlayerPlay(
step->playSound.soundId,
step->playSound.volume * (1.0f / 255.0f),
step->playSound.pitch * (1.0f / 64.0f),
NULL
);
runner->state.playSound.soundId = cutsceneRunnerPlaySound(step);
break;
case CutsceneStepTypeQueueSound:
cutsceneQueueSound(step->queueSound.soundId, step->queueSound.volume * (1.0f / 255.0f), step->queueSound.channel);
break;
case CutsceneStepTypeDelay:
runner->state.delay = step->delay;
@ -114,6 +181,11 @@ int cutsceneRunnerUpdateCurrentStep(struct CutsceneRunner* runner) {
switch (step->type) {
case CutsceneStepTypePlaySound:
return !soundPlayerIsPlaying(runner->state.playSound.soundId);
case CutsceneStepTypeWaitForChannel:
{
int result = !soundPlayerIsPlaying(gCutsceneCurrentSound[step->waitForChannel.channel]) && gCutsceneSoundQueues[step->waitForChannel.channel] == NULL;
return result;
}
case CutsceneStepTypeDelay:
runner->state.delay -= FIXED_DELTA_TIME;
return runner->state.delay <= 0.0f;
@ -195,10 +267,30 @@ int cutsceneIsRunning(struct Cutscene* cutscene) {
return 0;
}
void cutscenesUpdateSounds() {
for (int i = 0; i < CH_COUNT; ++i) {
if (!soundPlayerIsPlaying(gCutsceneCurrentSound[i])) {
if (gCutsceneSoundQueues[i]) {
struct QueuedSound* curr = gCutsceneSoundQueues[i];
gCutsceneCurrentSound[i] = soundPlayerPlay(curr->soundId, curr->volume, gCutsceneChannelPitch[i], NULL);
gCutsceneSoundQueues[i] = curr->next;
curr->next = gCutsceneNextFreeSound;
gCutsceneNextFreeSound = curr;
} else {
gCutsceneCurrentSound[i] = SOUND_ID_NONE;
}
}
}
}
void cutscenesUpdate() {
struct CutsceneRunner* previousCutscene = NULL;
struct CutsceneRunner* current = gRunningCutscenes;
cutscenesUpdateSounds();
while (current) {
if (cutsceneRunnerIsRunning(current)) {
cutsceneRunnerUpdate(current);

View file

@ -18,7 +18,7 @@ struct CutsceneRunner {
struct CutsceneRunner* nextRunner;
};
void cutsceneRunnerReset();
void cutsceneStart(struct Cutscene* cutscene);
void cutsceneStop(struct Cutscene* cutscene);
int cutsceneIsRunning(struct Cutscene* cutscene);

View file

@ -26,6 +26,8 @@ enum CutsceneStepType {
CutsceneStepTypeNoop,
CutsceneStepTypePlaySound,
CutsceneStepTypeStartSound,
CutsceneStepTypeQueueSound,
CutsceneStepTypeWaitForChannel,
CutsceneStepTypeDelay,
CutsceneStepTypeOpenPortal,
CutsceneStepTypeSetSignal,
@ -40,6 +42,11 @@ enum CutsceneStepType {
CutsceneStepTypePointPedestal,
};
#define CH_NONE 0xFF
#define CH_GLADOS 0
#define CH_COUNT 1
struct CutsceneStep {
enum CutsceneStepType type;
@ -49,6 +56,14 @@ struct CutsceneStep {
u8 volume;
u8 pitch;
} playSound;
struct {
u16 soundId;
u8 channel;
u8 volume;
} queueSound;
struct {
u8 channel;
} waitForChannel;
struct {
u16 locationIndex;
u16 portalIndex;

View file

@ -15,6 +15,7 @@
#include "audio/audio.h"
#include "scene/portal_surface.h"
#include "sk64/skelatool_defs.h"
#include "levels/cutscene_runner.h"
#include "levels/levels.h"
@ -152,7 +153,9 @@ static void gameProc(void* arg) {
dynamicSceneInit();
contactSolverInit(&gContactSolver);
portalSurfaceCleanupQueueInit();
levelLoad(0);
cutsceneRunnerReset();
controllersInit();
initAudio();
soundPlayerInit();
@ -175,10 +178,13 @@ static void gameProc(void* arg) {
if (levelGetQueued() != NO_QUEUED_LEVEL) {
if (pendingGFX == 0) {
dynamicSceneInit();
contactSolverInit(&gContactSolver);
portalSurfaceRevert(1);
portalSurfaceRevert(0);
portalSurfaceCleanupQueueInit();
heapInit(_heapStart, memoryEnd);
levelLoad(levelGetQueued());
cutsceneRunnerReset();
sceneInit(&gScene);
}

View file

@ -45,6 +45,12 @@ void portalSurfaceCheckCleanupQueue() {
}
}
void portalSurfaceCleanupQueueInit() {
for (int searchIterator = 0; searchIterator < MAX_PENDING_PORTAL_CLEANUP; ++searchIterator) {
gPortalSurfaceCleanupQueue[searchIterator].shouldCleanup = 0;
}
}
struct PortalSurfaceReplacement gPortalSurfaceReplacements[2];
int portalSurfaceAreBothOnSameSurface() {

View file

@ -55,6 +55,8 @@ struct PortalSurfaceReplacement {
short roomIndex;
};
void portalSurfaceCleanupQueueInit();
int portalSurfaceAreBothOnSameSurface();
int portalSurfaceShouldSwapOrder(int portalToMove);
int portalSurfaceStaticIndexForReplacement(int portalIndex);