music! random dialogue!

This commit is contained in:
maksw committed 2026-03-02 20:05:04 +01:00
1 parent 02b5bc8b52
commit 469f0db39c
6 files changed
+56 -31

No files matched your search

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+56 -31
View File
@@ -187,6 +187,16 @@ static void cmd_line(Script& s, text_t* dialogue,
} });
}
static void cmd_clear(Script& s, text_t* dialogue,
element_handle_t dialogue_id, compositor_t* comp)
{
s.push_back({ "CLEAR", [=]() -> bool {
text_clear(dialogue);
compositor_mark_content_dirty(comp, dialogue_id);
return false;
} });
}
static void cmd_wait_click(Script& s, Interpreter& interp)
{
s.push_back({ "WAIT_CLICK", [&interp]() -> bool {
@@ -302,6 +312,8 @@ static void cmd_end(Script& s, Interpreter& interp)
// ---------------------------------------------------------------------------
int main() {
srand((unsigned int)time(NULL));
const int WIDTH = 1280;
const int HEIGHT = 720;
const int CHAR_WIDTH = 400;
@@ -327,9 +339,26 @@ int main() {
audio_set_global_volume(audio, 1.0f);
typedef struct {
const char* title;
const char* composer;
const char* file;
} music_track_t;
static const music_track_t strauss_tracks[] = {
{"Freikugeln", "Johann Strauss II", "assets/Freikugeln.wav"},
{"Perpetuum Mobile", "Johann Strauss II", "assets/Perpetuum_Mobile.wav"},
{"Ohne Sorgen!", "Josef Strauss", "assets/Ohne_Sorgen!.wav"},
{"Auf Ferienreisen", "Josef Strauss", "assets/Auf_Ferienreisen.wav"},
{"Dynamiden", "Josef Strauss", "assets/Dynamiden.wav"}
};
int track_idx = rand() % (sizeof(strauss_tracks) / sizeof(strauss_tracks[0]));
const music_track_t* track = &strauss_tracks[track_idx];
int music_size, music_channels, music_rate, music_total_samples;
AudioDataHandle music_data(audio_load_madpcm(
"assets/Freikugeln.wav",
track->file,
&music_size, &music_channels, &music_rate, &music_total_samples));
if (!music_data) { printf("Failed to load audio\n"); return 1; }
@@ -415,6 +444,7 @@ int main() {
auto line = [&](const char* text, float speed = 30.0f) {
cmd_line(S, dlg, dlg_id, comp, text, speed);
};
auto clear = [&]() { cmd_clear(S, dlg, dlg_id, comp); };
auto wait_click = [&]() { cmd_wait_click(S, interp); };
auto wait_anim_all = [&]() { cmd_wait_anim_all(S, interp); };
auto wait_anim = [&](element_handle_t e) { cmd_wait_anim_elem(S, interp, e); };
@@ -440,9 +470,6 @@ int main() {
// Scene 1 - maksw slides in, introduces the engine
// ------------------------------------------------------------------
// Slide maksw_happy in from off-screen, bob on arrival, scale up as
// "active speaker". No WAIT_ANIM here - dialogue starts immediately
// and the animation plays alongside the typewriter, which feels natural.
anim_move(maksw_happy_id, CENTER_X, CHAR_BASELINE_Y,
1.5f, EASE_OUT_CUBIC, true);
anim_scale(maksw_happy_id, 1.1f, 0.3f, EASE_IN_OUT_CUBIC, /*queue=*/true, /*parallel=*/false);
@@ -463,10 +490,25 @@ int main() {
line("Yeah, hello to you too.");
wait_click();
const char* greetings[] = {
"Oh Wiktor, what a nice surprise!",
"Oh hey Wiktor, didn't expect to see you!",
"Wiktor! What brings you here?"
};
const char* responses[] = {
"No, I was just walking by.",
"Nah, just passing through.",
"Not really, just wandering."
};
int greeting_idx = rand() % 3;
int response_idx = rand() % 3;
anim_scale(wikor_id, 1.0f, 0.3f, EASE_IN_OUT_CUBIC);
anim_scale(maksw_happy_id, 1.05f, 0.3f, EASE_IN_OUT_CUBIC);
speaker("maksw");
line("Oh Wiktor, what a nice surprise!");
line(greetings[greeting_idx]);
wait_click();
line("...Do you need anything?");
@@ -475,48 +517,28 @@ int main() {
anim_scale(maksw_happy_id, 1.0f, 0.3f, EASE_IN_OUT_CUBIC);
anim_scale(wikor_id, 1.05f, 0.3f, EASE_IN_OUT_CUBIC);
speaker("wikor");
line("No, I was just walking by.");
line(responses[response_idx]);
wait_click();
line("Cool engine though.");
wait_click();
// ------------------------------------------------------------------
// Transition - wipe in, swap scene, wipe out
//
// Phase 1: mask slides down from above to cover the screen.
// We WAIT on that specific element so we know exactly when
// the screen is fully hidden - no guessing, no hack cases.
//
// Phase 2: while hidden, swap sprites and set up the new scene state.
// All of this is instant (no animation), which is fine because
// the mask is covering everything.
//
// Phase 3: hide mask, show mask2 (already covering screen at y=0),
// slide mask2 downward to reveal the new scene.
// We don't WAIT here - dialogue runs alongside the wipe-out,
// which looks intentional and cinematic.
// ------------------------------------------------------------------
// Phase 1 - cover
finish_all();
show(mask_id);
anim_move(mask_id, 0, 0, 0.5f, EASE_OUT_CUBIC);
wait_anim(mask_id); // block until mask fully covers the screen
wait_anim(mask_id);
// Phase 2 - swap (mask is covering, player sees nothing)
hide(maksw_happy_id);
show(maksw_neutral_id);
scale(maksw_neutral_id, 1.0f);
scale(wikor_id, 1.05f);
// Phase 3 - uncover
hide(mask_id);
show(mask2_id);
// mask2 starts at y=0 (covering screen), animate it off downward
anim_move(mask2_id, 0, HEIGHT, 0.5f, EASE_OUT_CUBIC);
// Dialogue fires immediately - text appears as the wipe reveals the scene
speaker("wikor");
clear();
wait_anim(mask2_id);
line("Anyways, how's your day going?");
wait_click();
@@ -542,7 +564,10 @@ int main() {
anim_scale(wikor_id, 1.0f, 0.3f, EASE_IN_OUT_CUBIC);
anim_scale(maksw_neutral_id, 1.05f, 0.3f, EASE_IN_OUT_CUBIC);
speaker("maksw");
line("Yep! Freikugeln by Johann Strauss II!");
char music_line[256];
snprintf(music_line, sizeof(music_line),
"Yep! %s by %s!", track->title, track->composer);
line(music_line);
wait_click();
finish_all();
@@ -632,4 +657,4 @@ int main() {
audio_stop(audio, music_id);
return 0;
}
}