use super::*;
impl StorySystem {
pub(super) fn apply_page(&mut self, ctx: &mut PipelineContext) {
let page = self.story.nodes[self.node].pages[self.page].clone();
self.apply_ops(&page.ops);
self.render_page(ctx);
let entry = match &page.speaker {
Some(s) => format!("{}: {}", s.name, page.text),
None => page.text.clone(),
};
self.history.push(entry);
if self.history.len() > BACKLOG_ENTRIES {
self.history.remove(0);
}
for sound in &page.sounds {
play(ctx, Some(*sound), CueKind::Sound);
}
self.persist_position(ctx);
}
pub(super) fn render_page(&mut self, ctx: &mut PipelineContext) {
let (name_id, text_id) = {
let ids = self.ids.as_ref().expect("resolved at init");
(ids.name, ids.text)
};
let page = self.story.nodes[self.node].pages[self.page].clone();
let (speaker, color) = match &page.speaker {
Some(s) => (s.name.clone(), s.color),
None => (String::new(), [1.0, 1.0, 1.0]),
};
set_label(ctx, name_id, |l| {
l.content = speaker;
l.color = color;
});
self.typewriter = Typewriter {
full: page.text.chars().collect(),
shown: 0,
budget: 0.0,
};
if self.story.text_speed <= 0.0 {
self.typewriter.shown = self.typewriter.full.len();
}
let text = self.typewriter.text();
set_label(ctx, text_id, |l| l.content = text);
apply_stage(
ctx,
self.ids.as_ref().expect("resolved at init"),
&page.stage,
);
play(ctx, page.music, CueKind::Music);
if self.skipping() {
self.reveal_all(ctx);
}
self.mode_timer = 0.0;
self.render_quick_row(ctx);
}
pub(super) fn render_quick_row(&mut self, ctx: &mut PipelineContext) {
let Some(ids) = self.ids.as_ref() else { return };
let rows = [
(ids.log_label, "Log", false),
(ids.auto_label, "Auto", self.auto),
(ids.skip_label, "Skip", self.skip || self.hold_skip),
(ids.save_label, "Save", false),
];
for (id, text, active) in rows {
set_label(ctx, id, |l| {
l.content = text.to_string();
l.color = if active { QUICK_ACTIVE } else { QUICK_IDLE };
});
}
}
pub(super) fn clear_quick_row(&mut self, ctx: &mut PipelineContext) {
let Some(ids) = self.ids.as_ref() else { return };
for id in [
ids.log_label,
ids.auto_label,
ids.skip_label,
ids.save_label,
] {
set_label(ctx, id, |l| l.content.clear());
}
set_sprite(ctx, ids.marker, |s| s.tint[3] = 0.0);
}
pub(super) fn enter_choice(&mut self, ctx: &mut PipelineContext) {
let node = self.story.nodes[self.node].clone();
self.apply_ops(&node.choice_ops);
self.skip = false;
self.render_choice(ctx);
for sound in &node.choice_sounds {
play(ctx, Some(*sound), CueKind::Sound);
}
}
pub(super) fn render_choice(&mut self, ctx: &mut PipelineContext) {
self.in_choice = true;
let node = self.story.nodes[self.node].clone();
self.menu = self.visible_choices(self.node);
let menu = self.menu.clone();
let ids = self.ids.as_ref().expect("resolved at init");
apply_stage(ctx, ids, &node.choice_stage);
play(ctx, node.choice_music, CueKind::Music);
set_label(ctx, ids.name, |l| l.content.clear());
set_label(ctx, ids.text, |l| l.content.clear());
set_sprite(ctx, ids.dialog_box, |s| s.tint = [0.0, 0.0, 0.0, 0.0]);
self.clear_quick_row(ctx);
let ids = self.ids.as_ref().expect("resolved at init");
let boxes = ids.option_boxes.clone();
for (i, label_id) in ids.options.iter().enumerate() {
let occupied = menu.get(i).is_some();
set_sprite(ctx, boxes.get(i).copied(), |s| {
s.visible = true;
s.tint = if occupied {
CHOICE_BOX_TINT
} else {
[
CHOICE_BOX_TINT[0],
CHOICE_BOX_TINT[1],
CHOICE_BOX_TINT[2],
0.0,
]
};
});
match menu.get(i).map(|&c| &node.choices[c]) {
Some(choice) => {
let text = choice.label.clone();
set_label(ctx, Some(*label_id), |l| {
l.content = text;
l.visible = true;
l.x = MENU_CENTER_X;
});
}
None => set_label(ctx, Some(*label_id), |l| l.content.clear()),
}
}
}
pub(super) fn exit_choice_ui(&mut self, ctx: &mut PipelineContext) {
self.in_choice = false;
let ids = self.ids.as_ref().expect("resolved at init");
set_sprite(ctx, ids.dialog_box, |s| s.tint = [0.0, 0.0, 0.0, 0.55]);
let boxes = ids.option_boxes.clone();
for box_id in boxes {
set_sprite(ctx, Some(box_id), |s| s.tint[3] = 0.0);
}
for label_id in &ids.options {
set_label(ctx, Some(*label_id), |l| l.content.clear());
}
}
}