New dialogue system powered by coroutines
This commit is contained in:
parent
4aa6ba5b3f
commit
fb19028ed5
33 changed files with 1180 additions and 969 deletions
|
@ -50,6 +50,10 @@ DEFINE_EXTERN_TASK(common_call_func) {
|
|||
ARGS.func();
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(common_start_bgm) {
|
||||
stage_start_bgm(ARGS.bgm);
|
||||
}
|
||||
|
||||
cmplx common_wander(cmplx origin, double dist, Rect bounds) {
|
||||
int attempts = 32;
|
||||
double angle;
|
||||
|
|
|
@ -37,6 +37,11 @@ DECLARE_EXTERN_TASK(
|
|||
{ void (*func)(void); }
|
||||
);
|
||||
|
||||
DECLARE_EXTERN_TASK(
|
||||
common_start_bgm,
|
||||
{ const char *bgm; }
|
||||
);
|
||||
|
||||
void common_move_loop(cmplx *restrict pos, MoveParams *restrict mp);
|
||||
|
||||
INLINE Rect viewport_bounds(double margin) {
|
||||
|
|
537
src/dialog.c
537
src/dialog.c
|
@ -11,132 +11,262 @@
|
|||
#include "dialog.h"
|
||||
#include "global.h"
|
||||
|
||||
Dialog *dialog_create(void) {
|
||||
Dialog *d = calloc(1, sizeof(Dialog));
|
||||
d->page_time = global.frames;
|
||||
d->birthtime = global.frames;
|
||||
return d;
|
||||
void dialog_init(Dialog *d) {
|
||||
memset(d, 0, sizeof(*d));
|
||||
d->state = DIALOG_STATE_IDLE;
|
||||
d->text.current = &d->text.buffers[0];
|
||||
d->text.fading_out = &d->text.buffers[1];
|
||||
COEVENT_INIT_ARRAY(d->events);
|
||||
}
|
||||
|
||||
void dialog_set_base(Dialog *d, DialogSide side, const char *sprite) {
|
||||
d->spr_base[side] = sprite ? get_sprite(sprite) : NULL;
|
||||
d->valid_composites &= ~(1 << side);
|
||||
void dialog_deinit(Dialog *d) {
|
||||
COEVENT_CANCEL_ARRAY(d->events);
|
||||
|
||||
for(DialogActor *a = d->actors.first; a; a = a->next) {
|
||||
if(a->composite.tex) {
|
||||
r_texture_destroy(a->composite.tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dialog_set_base_p(Dialog *d, DialogSide side, Sprite *sprite) {
|
||||
d->spr_base[side] = sprite;
|
||||
d->valid_composites &= ~(1 << side);
|
||||
void dialog_add_actor(Dialog *d, DialogActor *a, const char *name, DialogSide side) {
|
||||
memset(a, 0, sizeof(*a));
|
||||
a->name = name;
|
||||
a->face = "normal";
|
||||
a->side = side;
|
||||
a->target_opacity = 1;
|
||||
a->composite_dirty = true;
|
||||
|
||||
if(side == DIALOG_SIDE_RIGHT) {
|
||||
a->speech_color = *RGB(0.6, 0.6, 1.0);
|
||||
} else {
|
||||
a->speech_color = *RGB(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
alist_append(&d->actors, a);
|
||||
}
|
||||
|
||||
void dialog_set_face(Dialog *d, DialogSide side, const char *sprite) {
|
||||
d->spr_face[side] = sprite ? get_sprite(sprite) : NULL;
|
||||
d->valid_composites &= ~(1 << side);
|
||||
void dialog_actor_set_face(DialogActor *a, const char *face) {
|
||||
log_debug("[%s] %s --> %s", a->name, a->face, face);
|
||||
if(a->face != face) {
|
||||
a->face = face;
|
||||
a->composite_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dialog_set_face_p(Dialog *d, DialogSide side, Sprite *sprite) {
|
||||
d->spr_face[side] = sprite;
|
||||
d->valid_composites &= ~(1 << side);
|
||||
void dialog_actor_set_variant(DialogActor *a, const char *variant) {
|
||||
log_debug("[%s] %s --> %s", a->name, a->variant, variant);
|
||||
if(a->variant != variant) {
|
||||
a->variant = variant;
|
||||
a->composite_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dialog_set_char(Dialog *d, DialogSide side, const char *char_name, const char *char_face, const char *char_variant) {
|
||||
size_t name_len = strlen(char_name);
|
||||
size_t face_len = strlen(char_face);
|
||||
void dialog_update(Dialog *d) {
|
||||
if(d->text.current->text) {
|
||||
fapproach_p(&d->text.current->opacity, 1, 1/120.0f);
|
||||
} else {
|
||||
d->text.current->opacity = 0;
|
||||
}
|
||||
|
||||
if(d->text.fading_out->text) {
|
||||
fapproach_p(&d->text.fading_out->opacity, 0, 1/60.0f);
|
||||
} else {
|
||||
d->text.fading_out->opacity = 0;
|
||||
}
|
||||
|
||||
if(
|
||||
d->state == DIALOG_STATE_FADEOUT ||
|
||||
(
|
||||
d->text.current->opacity == 0 &&
|
||||
d->text.fading_out->opacity < 0.25
|
||||
)
|
||||
) {
|
||||
fapproach_asymptotic_p(&d->opacity, 0, 0.1, 1e-3);
|
||||
} else {
|
||||
fapproach_asymptotic_p(&d->opacity, 1, 0.05, 1e-3);
|
||||
}
|
||||
|
||||
for(DialogActor *a = d->actors.first; a; a = a->next) {
|
||||
if(d->state == DIALOG_STATE_FADEOUT) {
|
||||
fapproach_asymptotic_p(&a->opacity, 0, 0.12, 1e-3);
|
||||
} else {
|
||||
fapproach_asymptotic_p(&a->opacity, a->target_opacity, 0.04, 1e-3);
|
||||
}
|
||||
fapproach_asymptotic_p(&a->focus, a->target_focus, 0.12, 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
void dialog_skippable_wait(Dialog *d, int timeout) {
|
||||
CoEventSnapshot snap = coevent_snapshot(&d->events.skip_requested);
|
||||
|
||||
assert(d->state == DIALOG_STATE_IDLE);
|
||||
d->state = DIALOG_STATE_WAITING_FOR_SKIP;
|
||||
|
||||
while(timeout > 0) {
|
||||
dialog_update(d);
|
||||
|
||||
--timeout;
|
||||
YIELD;
|
||||
|
||||
if(coevent_poll(&d->events.skip_requested, &snap) != CO_EVENT_PENDING) {
|
||||
log_debug("Skipped with %i remaining", timeout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(d->state == DIALOG_STATE_WAITING_FOR_SKIP);
|
||||
d->state = DIALOG_STATE_IDLE;
|
||||
|
||||
if(timeout == 0) {
|
||||
log_debug("Timed out");
|
||||
}
|
||||
}
|
||||
|
||||
int dialog_util_estimate_wait_timeout_from_text(const char *text) {
|
||||
return 1800;
|
||||
}
|
||||
|
||||
static void dialog_set_text(Dialog *d, const char *text, const Color *clr) {
|
||||
DialogTextBuffer *temp = d->text.current;
|
||||
d->text.current = d->text.fading_out;
|
||||
d->text.fading_out = temp;
|
||||
|
||||
d->text.current->color = *clr;
|
||||
d->text.current->text = text;
|
||||
}
|
||||
|
||||
void dialog_focus_actor(Dialog *d, DialogActor *actor) {
|
||||
for(DialogActor *a = d->actors.first; a; a = a->next) {
|
||||
a->target_focus = 0;
|
||||
}
|
||||
|
||||
actor->target_focus = 1;
|
||||
|
||||
// make focused actor drawn on top of everyone else
|
||||
alist_unlink(&d->actors, actor);
|
||||
alist_append(&d->actors, actor);
|
||||
}
|
||||
|
||||
void dialog_message_ex(Dialog *d, const DialogMessageParams *params) {
|
||||
assume(params->actor != NULL);
|
||||
assume(params->text != NULL);
|
||||
|
||||
log_debug("%s: %s", params->actor->name, params->text);
|
||||
|
||||
dialog_set_text(d, params->text, ¶ms->actor->speech_color);
|
||||
dialog_focus_actor(d, params->actor);
|
||||
|
||||
if(params->implicit_wait) {
|
||||
assume(params->wait_timeout > 0);
|
||||
|
||||
if(params->wait_skippable) {
|
||||
dialog_skippable_wait(d, params->wait_timeout);
|
||||
} else {
|
||||
WAIT(params->wait_timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _dialog_message(Dialog *d, DialogActor *actor, const char *text, bool skippable, int delay) {
|
||||
DialogMessageParams p = { 0 };
|
||||
p.actor = actor;
|
||||
p.text = text;
|
||||
p.implicit_wait = true;
|
||||
p.wait_skippable = skippable;
|
||||
p.wait_timeout = delay;
|
||||
dialog_message_ex(d, &p);
|
||||
}
|
||||
|
||||
void dialog_message(Dialog *d, DialogActor *actor, const char *text) {
|
||||
_dialog_message(d, actor, text, true, dialog_util_estimate_wait_timeout_from_text(text));
|
||||
}
|
||||
|
||||
void dialog_message_unskippable(Dialog *d, DialogActor *actor, const char *text, int delay) {
|
||||
_dialog_message(d, actor, text, false, delay);
|
||||
}
|
||||
|
||||
void dialog_end(Dialog *d) {
|
||||
d->state = DIALOG_STATE_FADEOUT;
|
||||
coevent_signal(&d->events.fadeout_began);
|
||||
|
||||
for(DialogActor *a = d->actors.first; a; a = a->next) {
|
||||
a->target_opacity = 0;
|
||||
}
|
||||
|
||||
wait_for_fadeout: {
|
||||
if(d->opacity > 0) {
|
||||
YIELD;
|
||||
goto wait_for_fadeout;
|
||||
}
|
||||
|
||||
for(DialogActor *a = d->actors.first; a; a = a->next) {
|
||||
if(a->opacity > 0) {
|
||||
YIELD;
|
||||
goto wait_for_fadeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
coevent_signal(&d->events.fadeout_ended);
|
||||
dialog_deinit(d);
|
||||
}
|
||||
|
||||
static void dialog_actor_update_composite(DialogActor *a) {
|
||||
assume(a->name != NULL);
|
||||
assume(a->face != NULL);
|
||||
|
||||
if(!a->composite_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("%s (%p) is dirty; face=%s; variant=%s", a->name, (void*)a, a->face, a->variant);
|
||||
|
||||
Sprite *spr_base, *spr_face;
|
||||
|
||||
size_t name_len = strlen(a->name);
|
||||
size_t face_len = strlen(a->face);
|
||||
size_t variant_len;
|
||||
|
||||
size_t lenfull_base = sizeof("dialog/") + name_len - 1;
|
||||
size_t lenfull_face = lenfull_base + sizeof("_face_") + face_len - 1;
|
||||
|
||||
if(char_variant) {
|
||||
variant_len = strlen(char_variant);
|
||||
if(a->variant) {
|
||||
variant_len = strlen(a->variant);
|
||||
lenfull_base += sizeof("_variant_") + variant_len - 1;
|
||||
}
|
||||
|
||||
char buf[imax(lenfull_base, lenfull_face) + 1];
|
||||
char *dst = buf;
|
||||
char *variant_dst;
|
||||
dst = memcpy(dst, "dialog/", sizeof("dialog/") - 1);
|
||||
dst = memcpy(dst + sizeof("dialog/") - 1, char_name, name_len + 1);
|
||||
dst = memcpy(dst + sizeof("dialog/") - 1, a->name, name_len + 1);
|
||||
|
||||
if(char_variant) {
|
||||
variant_dst = dst + name_len;
|
||||
} else {
|
||||
d->spr_base[side] = get_sprite(buf);
|
||||
if(a->variant) {
|
||||
char *tmp = dst;
|
||||
dst = memcpy(dst + name_len, "_variant_", sizeof("_variant_") - 1);
|
||||
dst = memcpy(dst + sizeof("_variant_") - 1, a->variant, variant_len + 1);
|
||||
dst = tmp;
|
||||
}
|
||||
|
||||
spr_base = get_sprite(buf);
|
||||
log_debug("base: %s", buf);
|
||||
assume(spr_base != NULL);
|
||||
|
||||
dst = memcpy(dst + name_len, "_face_", sizeof("_face_") - 1);
|
||||
dst = memcpy(dst + sizeof("_face_") - 1, char_face, face_len + 1);
|
||||
d->spr_face[side] = get_sprite(buf);
|
||||
dst = memcpy(dst + sizeof("_face_") - 1, a->face, face_len + 1);
|
||||
|
||||
if(!char_variant) {
|
||||
return;
|
||||
spr_face = get_sprite(buf);
|
||||
log_debug("face: %s", buf);
|
||||
assume(spr_face != NULL);
|
||||
|
||||
if(a->composite.tex != NULL) {
|
||||
log_debug("destroyed texture at %p", (void*)a->composite.tex);
|
||||
r_texture_destroy(a->composite.tex);
|
||||
}
|
||||
|
||||
dst = memcpy(variant_dst, "_variant_", sizeof("_variant_") - 1);
|
||||
dst = memcpy(dst + sizeof("_variant_") - 1, char_variant, variant_len + 1);
|
||||
d->spr_base[side] = get_sprite(buf);
|
||||
|
||||
d->valid_composites &= ~(1 << side);
|
||||
}
|
||||
|
||||
static int message_index(Dialog *d, int offset) {
|
||||
int idx = d->pos + offset;
|
||||
|
||||
if(idx >= d->count) {
|
||||
idx = d->count - 1;
|
||||
}
|
||||
|
||||
while(
|
||||
idx >= 0 &&
|
||||
d->actions[idx].type != DIALOG_MSG_LEFT &&
|
||||
d->actions[idx].type != DIALOG_MSG_RIGHT
|
||||
) {
|
||||
--idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
DialogAction *dialog_add_action(Dialog *d, const DialogAction *action) {
|
||||
d->actions = realloc(d->actions, (++d->count)*sizeof(DialogAction));
|
||||
d->actions[d->count - 1] = *action;
|
||||
return d->actions + d->count - 1;
|
||||
}
|
||||
|
||||
static void update_composite(Dialog *d, DialogSide side) {
|
||||
if(d->valid_composites & (1 << side)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sprite *composite = d->spr_composite + side;
|
||||
Sprite *spr_base = d->spr_base[side];
|
||||
Sprite *spr_face = d->spr_face[side];
|
||||
|
||||
if(composite->tex != NULL) {
|
||||
r_texture_destroy(composite->tex);
|
||||
}
|
||||
|
||||
if(spr_base != NULL) {
|
||||
assert(spr_face != NULL);
|
||||
render_character_portrait(spr_base, spr_face, composite);
|
||||
} else {
|
||||
composite->tex = NULL;
|
||||
}
|
||||
|
||||
d->valid_composites |= (1 << side);
|
||||
}
|
||||
|
||||
static void update_composites(Dialog *d) {
|
||||
update_composite(d, DIALOG_LEFT);
|
||||
update_composite(d, DIALOG_RIGHT);
|
||||
}
|
||||
|
||||
void dialog_destroy(Dialog *d) {
|
||||
memset(&d->spr_base, 0, sizeof(d->spr_base));
|
||||
memset(&d->spr_face, 0, sizeof(d->spr_face));
|
||||
d->valid_composites = 0;
|
||||
update_composites(d);
|
||||
free(d->actions);
|
||||
free(d);
|
||||
render_character_portrait(spr_base, spr_face, &a->composite);
|
||||
log_debug("created texture at %p", (void*)a->composite.tex);
|
||||
a->composite_dirty = false;
|
||||
}
|
||||
|
||||
void dialog_draw(Dialog *dialog) {
|
||||
|
@ -146,12 +276,10 @@ void dialog_draw(Dialog *dialog) {
|
|||
|
||||
float o = dialog->opacity;
|
||||
|
||||
if(o == 0) {
|
||||
return;
|
||||
for(DialogActor *a = dialog->actors.first; a; a = a->next) {
|
||||
dialog_actor_update_composite(a);
|
||||
}
|
||||
|
||||
update_composites(dialog);
|
||||
|
||||
r_state_push();
|
||||
r_state_push();
|
||||
r_shader("sprite_default");
|
||||
|
@ -164,76 +292,47 @@ void dialog_draw(Dialog *dialog) {
|
|||
r_mat_mv_push();
|
||||
r_mat_mv_translate(dialog_width/2.0, 64, 0);
|
||||
|
||||
int cur_idx = message_index(dialog, 0);
|
||||
int pre_idx = message_index(dialog, -1);
|
||||
|
||||
assume(cur_idx >= 0);
|
||||
|
||||
int cur_side = dialog->actions[cur_idx].type;
|
||||
int pre_side = pre_idx >= 0 ? dialog->actions[pre_idx].type : 2;
|
||||
|
||||
Color clr = { 0 };
|
||||
|
||||
const float page_time = 10;
|
||||
float page_alpha = min(global.frames - (dialog->page_time), page_time) / page_time;
|
||||
|
||||
const float page_text_time = 60;
|
||||
float page_text_alpha = min(global.frames - dialog->page_time, page_text_time) / page_text_time;
|
||||
|
||||
int loop_start = 1;
|
||||
int loop_incr = 1;
|
||||
|
||||
if(cur_side == 0) {
|
||||
loop_start = 1;
|
||||
loop_incr = -1;
|
||||
} else {
|
||||
loop_start = 0;
|
||||
loop_incr = 1;
|
||||
}
|
||||
|
||||
for(int i = loop_start; i < 2 && i >= 0; i += loop_incr) {
|
||||
Sprite *portrait = dialog->spr_composite + i;
|
||||
|
||||
if(portrait->tex == NULL) {
|
||||
for(DialogActor *a = dialog->actors.first; a; a = a->next) {
|
||||
if(a->opacity <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dialog_actor_update_composite(a);
|
||||
Sprite *portrait = &a->composite;
|
||||
assume(portrait->tex != NULL);
|
||||
|
||||
float portrait_w = sprite_padded_width(portrait);
|
||||
float portrait_h = sprite_padded_height(portrait);
|
||||
|
||||
r_mat_mv_push();
|
||||
|
||||
if(i == DIALOG_MSG_LEFT) {
|
||||
if(a->side == DIALOG_SIDE_LEFT) {
|
||||
r_cull(CULL_FRONT);
|
||||
r_mat_mv_scale(-1, 1, 1);
|
||||
} else {
|
||||
r_cull(CULL_BACK);
|
||||
}
|
||||
|
||||
if(o < 1) {
|
||||
r_mat_mv_translate(120 * (1 - o), 0, 0);
|
||||
if(a->opacity < 1) {
|
||||
r_mat_mv_translate(120 * (1 - a->opacity), 0, 0);
|
||||
}
|
||||
|
||||
float dir = (1 - 2 * (i == cur_side));
|
||||
float ofs = 10 * dir;
|
||||
float ofs = 10 * (1 - a->focus);
|
||||
r_mat_mv_translate(ofs, ofs, 0);
|
||||
float brightness = 0.5 + 0.5 * a->focus;
|
||||
clr.r = clr.g = clr.b = brightness;
|
||||
clr.a = 1;
|
||||
|
||||
if(page_alpha < 10 && ((i != pre_side && i == cur_side) || (i == pre_side && i != cur_side))) {
|
||||
r_mat_mv_translate(ofs * page_alpha, ofs * page_alpha, 0);
|
||||
float brightness = min(1.0 - 0.5 * page_alpha * dir, 1);
|
||||
clr.r = clr.g = clr.b = brightness;
|
||||
clr.a = 1;
|
||||
} else {
|
||||
r_mat_mv_translate(ofs, ofs, 0);
|
||||
clr = *RGB(1 - (dir > 0) * 0.5, 1 - (dir > 0) * 0.5, 1 - (dir > 0) * 0.5);
|
||||
}
|
||||
|
||||
color_mul_scalar(&clr, o);
|
||||
color_mul_scalar(&clr, a->opacity);
|
||||
|
||||
r_flush_sprites();
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.blend = BLEND_PREMUL_ALPHA,
|
||||
.color = &clr,
|
||||
.pos.x = (dialog_width - portrait_w) / 2 + 32,
|
||||
.pos.y = VIEWPORT_H - portrait_h / 2,
|
||||
.pos.x = (dialog_width - portrait_w) / 2 + 32 + a->offset.x,
|
||||
.pos.y = VIEWPORT_H - portrait_h / 2 + a->offset.y,
|
||||
.sprite_ptr = portrait,
|
||||
});
|
||||
|
||||
|
@ -243,8 +342,6 @@ void dialog_draw(Dialog *dialog) {
|
|||
r_mat_mv_pop();
|
||||
r_state_pop();
|
||||
|
||||
o *= smooth(clamp((global.frames - dialog->birthtime - 10) / 30.0, 0, 1));
|
||||
|
||||
FloatRect dialog_bg_rect = {
|
||||
.extent = { VIEWPORT_W-40, 110 },
|
||||
.offset = { VIEWPORT_W/2, VIEWPORT_H-55 },
|
||||
|
@ -265,27 +362,19 @@ void dialog_draw(Dialog *dialog) {
|
|||
Font *font = get_font("standard");
|
||||
|
||||
r_mat_tex_push();
|
||||
// r_mat_tex_scale(2, 0.2, 0);
|
||||
// r_mat_tex_translate(0, -global.frames/page_text_time, 0);
|
||||
|
||||
dialog_bg_rect.w = VIEWPORT_W * 0.86;
|
||||
dialog_bg_rect.x -= dialog_bg_rect.w * 0.5;
|
||||
dialog_bg_rect.y -= dialog_bg_rect.h * 0.5;
|
||||
// dialog_bg_rect.h = dialog_bg_rect.w;
|
||||
|
||||
if(pre_idx >= 0 && page_text_alpha < 1) {
|
||||
if(pre_side == DIALOG_MSG_RIGHT) {
|
||||
clr = *RGB(0.6, 0.6, 1.0);
|
||||
} else {
|
||||
clr = *RGB(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
if(dialog->text.fading_out->opacity > 0) {
|
||||
clr = dialog->text.fading_out->color;
|
||||
color_mul_scalar(&clr, o);
|
||||
|
||||
text_draw_wrapped(dialog->actions[pre_idx].data, VIEWPORT_W * 0.86, &(TextParams) {
|
||||
text_draw_wrapped(dialog->text.fading_out->text, dialog_bg_rect.w, &(TextParams) {
|
||||
.shader = "text_dialog",
|
||||
.aux_textures = { get_tex("cell_noise") },
|
||||
.shader_params = &(ShaderCustomParams) {{ o * (1.0 - (0.2 + 0.8 * page_text_alpha)), 1 }},
|
||||
.shader_params = &(ShaderCustomParams) {{ o * (1.0 - (0.2 + 0.8 * (1 - dialog->text.fading_out->opacity))), 1 }},
|
||||
.color = &clr,
|
||||
.pos = { VIEWPORT_W/2, VIEWPORT_H-110 + font_get_lineskip(font) },
|
||||
.align = ALIGN_CENTER,
|
||||
|
@ -294,121 +383,39 @@ void dialog_draw(Dialog *dialog) {
|
|||
});
|
||||
}
|
||||
|
||||
if(cur_side == DIALOG_MSG_RIGHT) {
|
||||
clr = *RGB(0.6, 0.6, 1.0);
|
||||
} else {
|
||||
clr = *RGB(1.0, 1.0, 1.0);
|
||||
if(dialog->text.current->opacity > 0) {
|
||||
clr = dialog->text.current->color;
|
||||
color_mul_scalar(&clr, o);
|
||||
|
||||
text_draw_wrapped(dialog->text.current->text, dialog_bg_rect.w, &(TextParams) {
|
||||
.shader = "text_dialog",
|
||||
.aux_textures = { get_tex("cell_noise") },
|
||||
.shader_params = &(ShaderCustomParams) {{ o * dialog->text.current->opacity, 0 }},
|
||||
.color = &clr,
|
||||
.pos = { VIEWPORT_W/2, VIEWPORT_H-110 + font_get_lineskip(font) },
|
||||
.align = ALIGN_CENTER,
|
||||
.font_ptr = font,
|
||||
.overlay_projection = &dialog_bg_rect,
|
||||
});
|
||||
}
|
||||
|
||||
color_mul_scalar(&clr, o);
|
||||
|
||||
text_draw_wrapped(dialog->actions[cur_idx].data, VIEWPORT_W * 0.86, &(TextParams) {
|
||||
.shader = "text_dialog",
|
||||
.aux_textures = { get_tex("cell_noise") },
|
||||
.shader_params = &(ShaderCustomParams) {{ o * page_text_alpha, 0 }},
|
||||
.color = &clr,
|
||||
.pos = { VIEWPORT_W/2, VIEWPORT_H-110 + font_get_lineskip(font) },
|
||||
.align = ALIGN_CENTER,
|
||||
.font_ptr = font,
|
||||
.overlay_projection = &dialog_bg_rect,
|
||||
});
|
||||
|
||||
r_mat_tex_pop();
|
||||
r_mat_mv_pop();
|
||||
r_mat_mv_pop();
|
||||
r_state_pop();
|
||||
}
|
||||
|
||||
bool dialog_page(Dialog **pdialog) {
|
||||
Dialog *d = *pdialog;
|
||||
|
||||
if(!d || d->pos >= d->count) {
|
||||
return false;
|
||||
bool dialog_page(Dialog *d) {
|
||||
if(d->state == DIALOG_STATE_WAITING_FOR_SKIP) {
|
||||
coevent_signal(&d->events.skip_requested);
|
||||
return true;
|
||||
}
|
||||
|
||||
int to = d->actions[d->pos].timeout;
|
||||
|
||||
if(to && to > global.frames) {
|
||||
assert(d->actions[d->pos].type == DIALOG_MSG_LEFT || d->actions[d->pos].type == DIALOG_MSG_RIGHT);
|
||||
return false;
|
||||
}
|
||||
|
||||
DialogAction *a = d->actions + d->pos;
|
||||
d->pos++;
|
||||
d->page_time = global.frames;
|
||||
|
||||
if(d->pos >= d->count) {
|
||||
// XXX: maybe this can be handled elsewhere?
|
||||
if(!global.boss)
|
||||
global.timer++;
|
||||
}
|
||||
|
||||
switch(a->type) {
|
||||
case DIALOG_SET_BGM:
|
||||
stage_start_bgm(a->data);
|
||||
break;
|
||||
|
||||
case DIALOG_SET_FACE_RIGHT:
|
||||
case DIALOG_SET_FACE_LEFT: {
|
||||
DialogSide side = (
|
||||
a->type == DIALOG_SET_FACE_RIGHT
|
||||
? DIALOG_RIGHT
|
||||
: DIALOG_LEFT
|
||||
);
|
||||
|
||||
dialog_set_face(d, side, a->data);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dialog_update(Dialog **d) {
|
||||
if(!*d) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(dialog_is_active(*d)) {
|
||||
while((*d)->pos < (*d)->count) {
|
||||
if(
|
||||
(*d)->actions[(*d)->pos].type != DIALOG_MSG_LEFT &&
|
||||
(*d)->actions[(*d)->pos].type != DIALOG_MSG_RIGHT
|
||||
) {
|
||||
dialog_page(d);
|
||||
} else {
|
||||
int to = (*d)->actions[(*d)->pos].timeout;
|
||||
|
||||
if(
|
||||
(to && to >= global.frames) ||
|
||||
((global.plr.inputflags & INFLAG_SKIP) && global.frames - (*d)->page_time > 3)
|
||||
) {
|
||||
dialog_page(d);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// important to check this again; the dialog_page call may have ended the dialog
|
||||
|
||||
if(dialog_is_active(*d)) {
|
||||
fapproach_asymptotic_p(&(*d)->opacity, 1, 0.05, 1e-3);
|
||||
} else {
|
||||
fapproach_asymptotic_p(&(*d)->opacity, 0, 0.1, 1e-3);
|
||||
if((*d)->opacity == 0) {
|
||||
dialog_destroy(*d);
|
||||
*d = NULL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dialog_is_active(Dialog *d) {
|
||||
return d && (d->pos < d->count);
|
||||
return d && d->state != DIALOG_STATE_FADEOUT;
|
||||
}
|
||||
|
||||
void dialog_preload(void) {
|
||||
|
|
155
src/dialog.h
155
src/dialog.h
|
@ -11,94 +11,129 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "resource/sprite.h"
|
||||
#include "coroutine.h"
|
||||
|
||||
struct DialogAction;
|
||||
|
||||
typedef enum {
|
||||
DIALOG_RIGHT,
|
||||
DIALOG_LEFT,
|
||||
typedef enum DialogSide {
|
||||
DIALOG_SIDE_RIGHT,
|
||||
DIALOG_SIDE_LEFT,
|
||||
} DialogSide;
|
||||
|
||||
typedef enum {
|
||||
DIALOG_MSG_RIGHT = DIALOG_RIGHT,
|
||||
DIALOG_MSG_LEFT = DIALOG_LEFT,
|
||||
DIALOG_SET_BGM,
|
||||
DIALOG_SET_FACE_RIGHT,
|
||||
DIALOG_SET_FACE_LEFT,
|
||||
} DialogActionType;
|
||||
typedef enum DialogState {
|
||||
DIALOG_STATE_IDLE,
|
||||
DIALOG_STATE_WAITING_FOR_SKIP,
|
||||
DIALOG_STATE_FADEOUT,
|
||||
} DialogState;
|
||||
|
||||
typedef struct DialogAction {
|
||||
DialogActionType type;
|
||||
const char *data;
|
||||
int timeout;
|
||||
} DialogAction;
|
||||
typedef struct DialogActor {
|
||||
LIST_INTERFACE(struct DialogActor);
|
||||
|
||||
const char *name;
|
||||
const char *variant;
|
||||
const char *face;
|
||||
|
||||
Sprite composite;
|
||||
|
||||
float opacity;
|
||||
float target_opacity;
|
||||
|
||||
float focus;
|
||||
float target_focus;
|
||||
|
||||
Color speech_color;
|
||||
|
||||
FloatOffset offset;
|
||||
DialogSide side;
|
||||
|
||||
bool composite_dirty;
|
||||
} DialogActor;
|
||||
|
||||
typedef struct DialogTextBuffer {
|
||||
const char *text;
|
||||
Color color;
|
||||
float opacity;
|
||||
} DialogTextBuffer;
|
||||
|
||||
typedef struct Dialog {
|
||||
DialogAction *actions;
|
||||
LIST_ANCHOR(DialogActor) actors;
|
||||
|
||||
Sprite *spr_base[2];
|
||||
Sprite *spr_face[2];
|
||||
struct {
|
||||
DialogTextBuffer buffers[2];
|
||||
DialogTextBuffer *current;
|
||||
DialogTextBuffer *fading_out;
|
||||
} text;
|
||||
|
||||
Sprite spr_composite[2];
|
||||
uint valid_composites;
|
||||
COEVENTS_ARRAY(
|
||||
skip_requested,
|
||||
fadeout_began,
|
||||
fadeout_ended
|
||||
) events;
|
||||
|
||||
int count;
|
||||
int pos;
|
||||
int page_time;
|
||||
int birthtime;
|
||||
DialogState state;
|
||||
|
||||
float opacity;
|
||||
} Dialog;
|
||||
|
||||
Dialog *dialog_create(void)
|
||||
attr_returns_allocated;
|
||||
typedef struct DialogMessageParams {
|
||||
const char *text;
|
||||
DialogActor *actor;
|
||||
int wait_timeout;
|
||||
bool implicit_wait;
|
||||
bool wait_skippable;
|
||||
} DialogMessageParams;
|
||||
|
||||
void dialog_set_base(Dialog *d, DialogSide side, const char *sprite)
|
||||
void dialog_init(Dialog *d)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_deinit(Dialog *d)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_add_actor(Dialog *d, DialogActor *a, const char *name, DialogSide side)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_actor_set_face(DialogActor *a, const char *face)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_actor_set_variant(DialogActor *a, const char *variant)
|
||||
attr_nonnull(1);
|
||||
|
||||
void dialog_set_base_p(Dialog *d, DialogSide side, Sprite *sprite)
|
||||
attr_nonnull(1);
|
||||
attr_nonnull_all INLINE void dialog_actor_show(DialogActor *a) { a->target_opacity = 1; }
|
||||
attr_nonnull_all INLINE void dialog_actor_hide(DialogActor *a) { a->target_opacity = 0; }
|
||||
|
||||
void dialog_set_face(Dialog *d, DialogSide side, const char *sprite)
|
||||
attr_nonnull(1);
|
||||
void dialog_skippable_wait(Dialog *d, int timeout)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_set_face_p(Dialog *d, DialogSide side, Sprite *sprite)
|
||||
attr_nonnull(1);
|
||||
int dialog_util_estimate_wait_timeout_from_text(const char *text)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_set_char(Dialog *d, DialogSide side, const char *char_name, const char *char_face, const char *char_variant)
|
||||
attr_nonnull(1, 3, 4);
|
||||
void dialog_message(Dialog *d, DialogActor *actor, const char *text)
|
||||
attr_nonnull_all;
|
||||
|
||||
DialogAction *dialog_add_action(Dialog *d, const DialogAction *action)
|
||||
attr_nonnull(1, 2);
|
||||
void dialog_message_unskippable(Dialog *d, DialogActor *actor, const char *text, int delay)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_destroy(Dialog *d)
|
||||
attr_nonnull(1);
|
||||
void dialog_message_ex(Dialog *d, const DialogMessageParams *params)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_draw(Dialog *dialog);
|
||||
void dialog_focus_actor(Dialog *d, DialogActor *actor)
|
||||
attr_nonnull_all;
|
||||
|
||||
bool dialog_page(Dialog **d) attr_nonnull(1);
|
||||
void dialog_update(Dialog **d) attr_nonnull(1);
|
||||
void dialog_end(Dialog *d)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_update(Dialog *d)
|
||||
attr_nonnull_all;
|
||||
|
||||
void dialog_draw(Dialog *d);
|
||||
|
||||
bool dialog_page(Dialog *d)
|
||||
attr_nonnull_all;
|
||||
|
||||
bool dialog_is_active(Dialog *d);
|
||||
|
||||
void dialog_preload(void);
|
||||
|
||||
// FIXME: might not be the best place for this
|
||||
typedef struct PlayerDialogProcs {
|
||||
void (*stage1_pre_boss)(Dialog *d);
|
||||
void (*stage1_post_boss)(Dialog *d);
|
||||
void (*stage2_pre_boss)(Dialog *d);
|
||||
void (*stage2_post_boss)(Dialog *d);
|
||||
void (*stage3_pre_boss)(Dialog *d);
|
||||
void (*stage3_post_boss)(Dialog *d);
|
||||
void (*stage4_pre_boss)(Dialog *d);
|
||||
void (*stage4_post_boss)(Dialog *d);
|
||||
void (*stage5_post_midboss)(Dialog *d);
|
||||
void (*stage5_pre_boss)(Dialog *d);
|
||||
void (*stage5_post_boss)(Dialog *d);
|
||||
void (*stage6_pre_boss)(Dialog *d);
|
||||
void (*stage6_pre_final)(Dialog *d);
|
||||
} PlayerDialogProcs;
|
||||
#include "dialog/dialog_interface.h"
|
||||
|
||||
#endif // IGUARD_dialog_h
|
||||
|
|
79
src/dialog/dialog_interface.h
Normal file
79
src/dialog/dialog_interface.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_stages_dialog_interface_h
|
||||
#define IGUARD_stages_dialog_interface_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
|
||||
#define DIALOG_SCRIPTS \
|
||||
WITH_EVENTS (Stage1PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage1PostBoss) \
|
||||
WITH_EVENTS (Stage2PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage2PostBoss) \
|
||||
WITH_EVENTS (Stage3PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage3PostBoss) \
|
||||
WITH_EVENTS (Stage4PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage4PostBoss) \
|
||||
WITH_EVENTS (Stage5PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage5PostMidBoss) \
|
||||
WITHOUT_EVENTS (Stage5PostBoss) \
|
||||
WITH_EVENTS (Stage6PreBoss, (boss_appears, music_changes)) \
|
||||
WITHOUT_EVENTS (Stage6PreFinal) \
|
||||
|
||||
|
||||
|
||||
#define WITH_EVENTS(_name, _events) \
|
||||
typedef COEVENTS_ARRAY _events _name##DialogEvents; \
|
||||
DEFINE_TASK_INTERFACE(_name##Dialog, { _name##DialogEvents **out_events; });
|
||||
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
WITH_EVENTS(_name, (_dummy_fake_event_))
|
||||
|
||||
/*
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
typedef struct { char there_are_no_events; } _name##DialogEvents; \
|
||||
DEFINE_TASK_INTERFACE(_name##Dialog, { _name##DialogEvents **out_events; });
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPTS
|
||||
#undef WITH_EVENTS
|
||||
#undef WITHOUT_EVENTS
|
||||
|
||||
#define WITH_EVENTS(_name, _events) WITHOUT_EVENTS(_name)
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
TASK_INDIRECT_TYPE(_name##Dialog) _name;
|
||||
|
||||
typedef struct PlayerDialogTasks {
|
||||
DIALOG_SCRIPTS
|
||||
} PlayerDialogTasks;
|
||||
|
||||
#undef WITH_EVENTS
|
||||
#undef WITHOUT_EVENTS
|
||||
|
||||
// FIXME: might not be the best place for this
|
||||
typedef struct PlayerDialogProcs {
|
||||
void (*stage1_pre_boss)(Dialog *d);
|
||||
void (*stage1_post_boss)(Dialog *d);
|
||||
void (*stage2_pre_boss)(Dialog *d);
|
||||
void (*stage2_post_boss)(Dialog *d);
|
||||
void (*stage3_pre_boss)(Dialog *d);
|
||||
void (*stage3_post_boss)(Dialog *d);
|
||||
void (*stage4_pre_boss)(Dialog *d);
|
||||
void (*stage4_post_boss)(Dialog *d);
|
||||
void (*stage5_post_midboss)(Dialog *d);
|
||||
void (*stage5_pre_boss)(Dialog *d);
|
||||
void (*stage5_post_boss)(Dialog *d);
|
||||
void (*stage6_pre_boss)(Dialog *d);
|
||||
void (*stage6_pre_final)(Dialog *d);
|
||||
} PlayerDialogProcs;
|
||||
|
||||
#endif // IGUARD_stages_dialog_interface_h
|
|
@ -12,33 +12,39 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "dialog.h"
|
||||
#include "stage.h"
|
||||
|
||||
#define DIALOG_SCRIPT(name) static void dialog_##name(Dialog *d)
|
||||
#define MSG(_side, _text) \
|
||||
dialog_add_action(d, &(DialogAction) { .type = (_side), .data = (_text) })
|
||||
#define FACE(_side, _chr, _face) \
|
||||
dialog_add_action(d, &(DialogAction) { .type = (_side), .data = "dialog/" #_chr "_face_" #_face })
|
||||
#define LEFT(text) MSG(DIALOG_MSG_LEFT, text)
|
||||
#define RIGHT(text) MSG(DIALOG_MSG_RIGHT, text)
|
||||
#define DIALOG_EVAL(a, b) a b
|
||||
#define LEFT_FACE(face) DIALOG_EVAL(FACE, (DIALOG_SET_FACE_LEFT, LEFT_BASE, face))
|
||||
#define RIGHT_FACE(face) DIALOG_EVAL(FACE, (DIALOG_SET_FACE_RIGHT, RIGHT_BASE, face))
|
||||
#define DIALOG_BEGIN(_interface) \
|
||||
Dialog dialog; \
|
||||
stage_begin_dialog(&dialog); \
|
||||
_interface##DialogEvents events = { 0 }; \
|
||||
COEVENT_INIT_ARRAY(events); \
|
||||
if(ARGS.out_events) *ARGS.out_events = &events; \
|
||||
YIELD \
|
||||
|
||||
#define EXPORT_DIALOG_SCRIPT(name) \
|
||||
PlayerDialogProcs dialog_##name = { \
|
||||
.stage1_pre_boss = dialog_##name##_stage1_pre_boss, \
|
||||
.stage1_post_boss = dialog_##name##_stage1_post_boss, \
|
||||
.stage2_pre_boss = dialog_##name##_stage2_pre_boss, \
|
||||
.stage2_post_boss = dialog_##name##_stage2_post_boss, \
|
||||
.stage3_pre_boss = dialog_##name##_stage3_pre_boss, \
|
||||
.stage3_post_boss = dialog_##name##_stage3_post_boss, \
|
||||
.stage4_pre_boss = dialog_##name##_stage4_pre_boss, \
|
||||
.stage4_post_boss = dialog_##name##_stage4_post_boss, \
|
||||
.stage5_post_midboss = dialog_##name##_stage5_post_midboss, \
|
||||
.stage5_pre_boss = dialog_##name##_stage5_pre_boss, \
|
||||
.stage5_post_boss = dialog_##name##_stage5_post_boss, \
|
||||
.stage6_pre_boss = dialog_##name##_stage6_pre_boss, \
|
||||
.stage6_pre_final = dialog_##name##_stage6_pre_final, \
|
||||
};
|
||||
#define DIALOG_END() \
|
||||
dialog_end(&dialog); \
|
||||
COEVENT_CANCEL_ARRAY(events)
|
||||
|
||||
#define ACTOR(_name, _side) \
|
||||
DialogActor _name; \
|
||||
dialog_add_actor(&dialog, &_name, #_name, _side)
|
||||
|
||||
#define ACTOR_LEFT(_name) ACTOR(_name, DIALOG_SIDE_LEFT)
|
||||
#define ACTOR_RIGHT(_name) ACTOR(_name, DIALOG_SIDE_RIGHT)
|
||||
|
||||
#define MSG(_actor, _text) dialog_message(&dialog, &_actor, _text)
|
||||
#define MSG_UNSKIPPABLE(_actor, _delay, _text) dialog_message_unskippable(&dialog, &_actor, _text, _delay)
|
||||
#define FACE(_actor, _face) dialog_actor_set_face(&_actor, #_face)
|
||||
#define VARIANT(_actor, _variant) dialog_actor_set_variant(&_actor, #_variant)
|
||||
#define SHOW(_actor) dialog_actor_show(&_actor)
|
||||
#define HIDE(_actor) dialog_actor_hide(&_actor)
|
||||
#define FOCUS(_actor) dialog_focus_actor(&dialog, &_actor)
|
||||
#define WAIT_SKIPPABLE(_delay) dialog_skippable_wait(&dialog, _delay)
|
||||
#define EVENT(_name) coevent_signal(&events._name)
|
||||
#define TITLE(_actor, _name, _title) log_warn("TITLE(%s, %s, %s) not yet implemented", #_actor, #_name, #_title)
|
||||
|
||||
#define DIALOG_TASK(_protag, _interface) \
|
||||
TASK_WITH_INTERFACE(_protag##_##_interface##Dialog, _interface##Dialog)
|
||||
|
||||
#endif // IGUARD_dialog_dialog_macros_h
|
||||
|
|
28
src/dialog/export_dialog_tasks.inc.h
Normal file
28
src/dialog/export_dialog_tasks.inc.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
// this needs an extra indirection to expand EXPORT_DIALOG_TASKS_CHARACTER
|
||||
#define EDT_CONCAT(a, b) MACROHAX_CONCAT(a, b)
|
||||
|
||||
// Fill the global dialog_tasks_<character> struct
|
||||
|
||||
#define WITH_EVENTS(_name, _events) WITHOUT_EVENTS(_name)
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
._name = MACROHAX_EXPAND(MACROHAX_DEFER(TASK_INDIRECT_INIT)(_name##Dialog, EDT_CONCAT(EXPORT_DIALOG_TASKS_CHARACTER, _##_name##Dialog))),
|
||||
|
||||
PlayerDialogTasks EDT_CONCAT(dialog_tasks_, EXPORT_DIALOG_TASKS_CHARACTER) = {
|
||||
DIALOG_SCRIPTS
|
||||
};
|
||||
|
||||
// Let the compiler know that the tasks are "used". TASK_INDIRECT_INIT can't do that.
|
||||
|
||||
#undef WITHOUT_EVENTS
|
||||
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
attr_unused static char MACROHAX_EXPAND(MACROHAX_DEFER(EDT_CONCAT)(COTASK_UNUSED_CHECK_, EDT_CONCAT(EXPORT_DIALOG_TASKS_CHARACTER, _##_name##Dialog)));
|
||||
|
||||
DIALOG_SCRIPTS
|
||||
|
||||
#undef WITH_EVENTS
|
||||
#undef WITHOUT_EVENTS
|
||||
#undef EDT_CONTAT
|
||||
|
||||
#undef EXPORT_DIALOG_TASKS_CHARACTER
|
|
@ -10,190 +10,183 @@
|
|||
|
||||
#include "dialog_macros.h"
|
||||
|
||||
#define LEFT_BASE marisa
|
||||
/*
|
||||
* Stage 1
|
||||
*/
|
||||
|
||||
#define RIGHT_BASE cirno
|
||||
DIALOG_TASK(marisa, Stage1PreBoss) {
|
||||
DIALOG_BEGIN(Stage1PreBoss);
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage1_pre_boss) {
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(angry);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(cirno);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage1_post_boss) {
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage1PostBoss) {
|
||||
DIALOG_BEGIN(Stage1PostBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(cirno);
|
||||
VARIANT(cirno, defeated);
|
||||
FACE(cirno, defeated);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
#undef RIGHT_BASE
|
||||
#define RIGHT_BASE hina
|
||||
/*
|
||||
* Stage 2
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage2_pre_boss) {
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(concerned);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(unamused);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(serious);
|
||||
LEFT_FACE(puzzled);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage2PreBoss) {
|
||||
DIALOG_BEGIN(Stage2PreBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(hina);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage2_post_boss) {
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage2PostBoss) {
|
||||
DIALOG_BEGIN(Stage2PostBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(hina);
|
||||
VARIANT(hina, defeated);
|
||||
FACE(hina, defeated);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
#undef RIGHT_BASE
|
||||
#define RIGHT_BASE wriggle
|
||||
/*
|
||||
* Stage 3
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage3_pre_boss) {
|
||||
LEFT_FACE(puzzled);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(outraged);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(proud);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
RIGHT_FACE(calm);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(proud);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage3PreBoss) {
|
||||
DIALOG_BEGIN(Stage3PreBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(wriggle);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage3_post_boss) {
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(outraged_unlit);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
RIGHT_FACE(defeated);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage3PostBoss) {
|
||||
DIALOG_BEGIN(Stage3PostBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(wriggle);
|
||||
VARIANT(wriggle, defeated);
|
||||
FACE(wriggle, defeated);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
#undef RIGHT_BASE
|
||||
#define RIGHT_BASE kurumi
|
||||
/*
|
||||
* Stage 4
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage4_pre_boss) {
|
||||
LEFT_FACE(surprised);
|
||||
RIGHT_FACE(tsun);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(normal);
|
||||
LEFT_FACE(normal);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(tsun_blush);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(dissatisfied);
|
||||
LEFT_FACE(happy);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(tsun);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(sweat_smile);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage4PreBoss) {
|
||||
DIALOG_BEGIN(Stage4PreBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(kurumi);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage4_post_boss) {
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(dissatisfied);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage4PostBoss) {
|
||||
DIALOG_BEGIN(Stage4PostBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(kurumi);
|
||||
VARIANT(kurumi, defeated);
|
||||
FACE(kurumi, defeated);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
#undef RIGHT_BASE
|
||||
#define RIGHT_BASE iku
|
||||
/*
|
||||
* Stage 5
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage5_pre_boss) {
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(puzzled);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(serious);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(eyes_closed);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
RIGHT_FACE(normal);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
RIGHT_FACE(eyes_closed);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(smile);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(surprised);
|
||||
RIGHT_FACE(serious);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage5PreBoss) {
|
||||
DIALOG_BEGIN(Stage5PreBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(iku);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage5_post_midboss) {
|
||||
// this dialog must contain only one page
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage5PostMidBoss) {
|
||||
DIALOG_BEGIN(Stage5PostMidBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
FACE(marisa, surprised);
|
||||
|
||||
// should be only one message with a fixed 120-frames timeout
|
||||
MSG_UNSKIPPABLE(marisa, 120, "changeme");
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage5_post_boss) {
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(happy);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(sweat_smile);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage5PostBoss) {
|
||||
DIALOG_BEGIN(Stage5PostBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(iku);
|
||||
VARIANT(iku, defeated);
|
||||
FACE(iku, defeated);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
#undef RIGHT_BASE
|
||||
#define RIGHT_BASE elly
|
||||
/*
|
||||
* Stage 6
|
||||
*/
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage6_pre_boss) {
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(surprised);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(puzzled);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(normal);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(angry);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(smug);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage6PreBoss) {
|
||||
DIALOG_BEGIN(Stage6PreBoss);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(elly);
|
||||
|
||||
EVENT(boss_appears);
|
||||
EVENT(music_changes);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
DIALOG_SCRIPT(marisa_stage6_pre_final) {
|
||||
RIGHT_FACE(angry);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(puzzled);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(surprised);
|
||||
RIGHT_FACE(shouting);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
DIALOG_TASK(marisa, Stage6PreFinal) {
|
||||
DIALOG_BEGIN(Stage6PreFinal);
|
||||
|
||||
ACTOR_LEFT(marisa);
|
||||
ACTOR_RIGHT(elly);
|
||||
VARIANT(elly, beaten);
|
||||
FACE(elly, angry);
|
||||
|
||||
DIALOG_END();
|
||||
}
|
||||
|
||||
EXPORT_DIALOG_SCRIPT(marisa)
|
||||
/*
|
||||
* Register the tasks
|
||||
*/
|
||||
|
||||
#define EXPORT_DIALOG_TASKS_CHARACTER marisa
|
||||
#include "export_dialog_tasks.inc.h"
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
|
||||
#include "dialog.h"
|
||||
|
||||
extern PlayerDialogProcs dialog_marisa;
|
||||
extern PlayerDialogTasks dialog_tasks_marisa;
|
||||
|
||||
#endif // IGUARD_dialog_marisa_h
|
||||
|
|
|
@ -10,196 +10,248 @@
|
|||
|
||||
#include "dialog_macros.h"
|
||||
|
||||
#define LEFT_BASE reimu
|
||||
/*
|
||||
* Stage 1
|
||||
*/
|
||||
|
||||
#define RIGHT_BASE cirno
|
||||
DIALOG_TASK(reimu, Stage1PreBoss) {
|
||||
// Initialization, must be at the very top.
|
||||
DIALOG_BEGIN(Stage1PreBoss);
|
||||
|
||||
DIALOG_SCRIPT(reimu_stage1_pre_boss) {
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
LEFT_FACE(unamused);
|
||||
LEFT("FIXME: Removed due to issue #179");
|
||||
RIGHT_FACE(angry);
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
RIGHT("FIXME: Removed due to issue #179");
|
||||
ACTOR_LEFT(reimu);
|
||||
ACTOR_RIGHT(cirno);
|
||||
|
||||
// Hide cirno for now, to be revealed later.
|
||||
HIDE(cirno);
|
||||
|
||||
// "normal" is the default face.
|
||||
// FACE(reimu, normal);
|
||||
|
||||
// FOCUS() to make an actor stand out.
|
||||
// Focused actors are fully bright and appear in front of the rest.
|
||||
// Only one actor can be focused at a time.
|
||||