Sorted vn module better, small coding style improvements
This commit is contained in:
parent
8a9b5a681d
commit
cd61068f06
212
src/vn.rs
212
src/vn.rs
@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, fs::File, io::prelude::*, net::TcpStream, path::Path};
|
||||
|
||||
use dialogi::DialogBlock;
|
||||
use dialogi::{DialogBlock, DialogSequence, ParsingError};
|
||||
use event_simulation::Simulation;
|
||||
use indexmap::IndexMap;
|
||||
use maud::{Markup, html};
|
||||
@ -29,12 +29,49 @@ fn render_scene(settings: &PlayerSettings, name: &str) -> Markup {
|
||||
}
|
||||
}
|
||||
|
||||
fn navigation_controls(total_sections: usize) -> Markup {
|
||||
fn render_choice(block: &DialogBlock<Parameter>, index: usize, progress: &str) -> Markup {
|
||||
let mut content = Vec::new();
|
||||
convert(std::iter::once(&block.lines[0].text), &mut content);
|
||||
|
||||
html! {
|
||||
nav .nav-controls {
|
||||
button .nav-button onclick="prev()" { "←" }
|
||||
span #section-counter { "1/" (total_sections) }
|
||||
button .nav-button onclick="next()" { "→" }
|
||||
form method="POST" {
|
||||
input type="hidden" name="progress" value=(progress);
|
||||
input type="hidden" name="choice" value=(index);
|
||||
|
||||
button type="submit" .choice-button {
|
||||
fieldset .choice-box {
|
||||
@if !block.name.is_empty() {
|
||||
legend .choice-name { (block.name) }
|
||||
}
|
||||
@match String::from_utf8(content) {
|
||||
Ok(text) => (maud::PreEscaped(text)),
|
||||
Err(e) => (maud::PreEscaped(format!("Error: {e}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_dialog_block(block: &DialogBlock<Parameter>) -> Markup {
|
||||
if block.lines.is_empty() {
|
||||
return html! {};
|
||||
}
|
||||
|
||||
let mut content = Vec::new();
|
||||
convert(block.lines.iter().map(|l| l.text.as_ref()), &mut content);
|
||||
|
||||
html! {
|
||||
fieldset .visual-novel-box {
|
||||
@if !block.name.is_empty() {
|
||||
legend .character-name { (block.name) }
|
||||
}
|
||||
div .dialog-content {
|
||||
@match String::from_utf8(content) {
|
||||
Ok(text) => (maud::PreEscaped(text)),
|
||||
Err(e) => (maud::PreEscaped(format!("Error: {e}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,6 +98,16 @@ fn generate_html(sections: Vec<Markup>) -> Markup {
|
||||
}
|
||||
}
|
||||
|
||||
fn navigation_controls(total_sections: usize) -> Markup {
|
||||
html! {
|
||||
nav .nav-controls {
|
||||
button .nav-button onclick="prev()" { "←" }
|
||||
span #section-counter { "1/" (total_sections) }
|
||||
button .nav-button onclick="next()" { "→" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn global_styles() -> Markup {
|
||||
const BASE_STYLES: &str = r"
|
||||
:root {
|
||||
@ -304,36 +351,60 @@ fn interactive_script(total_sections: usize) -> Markup {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_multilinear(mld_path: &Path) -> Option<NamedMultilinearInfo> {
|
||||
let Ok(file) = File::open(mld_path) else {
|
||||
return None;
|
||||
};
|
||||
fn process_dialog(
|
||||
dialog_sequence: &DialogSequence<Change, Parameter>,
|
||||
player_settings: &mut PlayerSettings,
|
||||
) -> Vec<Markup> {
|
||||
let mut sections = Vec::new();
|
||||
let mut states = initialize_change_states(&dialog_sequence.changes);
|
||||
|
||||
parse_multilinear(file).ok()
|
||||
for block in &dialog_sequence.blocks {
|
||||
apply_block_changes(
|
||||
block,
|
||||
&dialog_sequence.changes,
|
||||
&mut states,
|
||||
player_settings,
|
||||
);
|
||||
|
||||
sections.push(html! {
|
||||
(render_scene(player_settings, &block.name))
|
||||
(render_dialog_block(block))
|
||||
});
|
||||
}
|
||||
|
||||
player_settings.reset();
|
||||
sections
|
||||
}
|
||||
|
||||
fn render_choice(block: &DialogBlock<Parameter>, index: usize, progress: &str) -> Markup {
|
||||
let mut content = Vec::new();
|
||||
convert(std::iter::once(&block.lines[0].text), &mut content);
|
||||
fn initialize_change_states(
|
||||
changes: &HashMap<Parameter, Vec<Change>>,
|
||||
) -> HashMap<Parameter, usize> {
|
||||
changes.keys().map(|k| (k.clone(), 0)).collect()
|
||||
}
|
||||
|
||||
html! {
|
||||
form method="POST" {
|
||||
input type="hidden" name="progress" value=(progress);
|
||||
input type="hidden" name="choice" value=(index);
|
||||
fn apply_block_changes(
|
||||
block: &DialogBlock<Parameter>,
|
||||
changes: &HashMap<Parameter, Vec<Change>>,
|
||||
states: &mut HashMap<Parameter, usize>,
|
||||
settings: &mut PlayerSettings,
|
||||
) {
|
||||
for parameter in block
|
||||
.lines
|
||||
.iter()
|
||||
.flat_map(|l| &l.actions)
|
||||
.chain(&block.final_actions)
|
||||
{
|
||||
if let Some(state) = states.get_mut(parameter) {
|
||||
if let Some(change) = changes[parameter].get(*state) {
|
||||
settings.change(change);
|
||||
*state += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button type="submit" .choice-button {
|
||||
fieldset .choice-box {
|
||||
@if !block.name.is_empty() {
|
||||
legend .choice-name { (block.name) }
|
||||
}
|
||||
@match String::from_utf8(content) {
|
||||
Ok(text) => (maud::PreEscaped(text)),
|
||||
Err(e) => (maud::PreEscaped(format!("Error: {e}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn load_multilinear(mld_path: &Path) -> Option<NamedMultilinearInfo> {
|
||||
parse_multilinear(File::open(mld_path).ok()?).ok()
|
||||
}
|
||||
|
||||
pub fn render_novel(
|
||||
@ -343,7 +414,7 @@ pub fn render_novel(
|
||||
stream: &mut TcpStream,
|
||||
choice: usize,
|
||||
progress: &str,
|
||||
) -> Result<(), dialogi::ParsingError> {
|
||||
) -> Result<(), ParsingError> {
|
||||
let mut settings_context = SettingsContext::new();
|
||||
extract_layers(&mut settings_context.layers, &mut config_map);
|
||||
|
||||
@ -401,80 +472,3 @@ pub fn render_novel(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_dialog(
|
||||
dialog_sequence: &dialogi::DialogSequence<Change, Parameter>,
|
||||
player_settings: &mut PlayerSettings,
|
||||
) -> Vec<Markup> {
|
||||
let mut sections = Vec::new();
|
||||
|
||||
let mut states = initialize_change_states(&dialog_sequence.changes);
|
||||
|
||||
for block in &dialog_sequence.blocks {
|
||||
apply_block_changes(
|
||||
block,
|
||||
&dialog_sequence.changes,
|
||||
&mut states,
|
||||
player_settings,
|
||||
);
|
||||
|
||||
sections.push(html! {
|
||||
(render_scene(player_settings, &block.name))
|
||||
(render_dialog_block(block))
|
||||
});
|
||||
}
|
||||
|
||||
player_settings.reset();
|
||||
|
||||
sections
|
||||
}
|
||||
|
||||
fn initialize_change_states(
|
||||
changes: &HashMap<Parameter, Vec<Change>>,
|
||||
) -> HashMap<Parameter, usize> {
|
||||
changes.keys().map(|k| (k.clone(), 0)).collect()
|
||||
}
|
||||
|
||||
fn apply_block_changes(
|
||||
block: &dialogi::DialogBlock<Parameter>,
|
||||
changes: &HashMap<Parameter, Vec<Change>>,
|
||||
states: &mut HashMap<Parameter, usize>,
|
||||
settings: &mut PlayerSettings,
|
||||
) {
|
||||
for parameter in block
|
||||
.lines
|
||||
.iter()
|
||||
.flat_map(|l| &l.actions)
|
||||
.chain(&block.final_actions)
|
||||
{
|
||||
if let Some(state) = states.get_mut(parameter) {
|
||||
if let Some(change) = changes[parameter].get(*state) {
|
||||
settings.change(change);
|
||||
*state += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_dialog_block(block: &dialogi::DialogBlock<Parameter>) -> Markup {
|
||||
if block.lines.is_empty() {
|
||||
return html! {};
|
||||
}
|
||||
|
||||
let mut content = Vec::new();
|
||||
convert(block.lines.iter().map(|l| l.text.as_ref()), &mut content);
|
||||
|
||||
html! {
|
||||
fieldset .visual-novel-box {
|
||||
@if !block.name.is_empty() {
|
||||
legend .character-name { (block.name) }
|
||||
}
|
||||
div .dialog-content {
|
||||
@match String::from_utf8(content) {
|
||||
Ok(text) => (maud::PreEscaped(text)),
|
||||
Err(e) => (maud::PreEscaped(format!("Error: {e}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user