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 std::{collections::HashMap, fs::File, io::prelude::*, net::TcpStream, path::Path};
|
||||||
|
|
||||||
use dialogi::DialogBlock;
|
use dialogi::{DialogBlock, DialogSequence, ParsingError};
|
||||||
use event_simulation::Simulation;
|
use event_simulation::Simulation;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use maud::{Markup, html};
|
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! {
|
html! {
|
||||||
nav .nav-controls {
|
form method="POST" {
|
||||||
button .nav-button onclick="prev()" { "←" }
|
input type="hidden" name="progress" value=(progress);
|
||||||
span #section-counter { "1/" (total_sections) }
|
input type="hidden" name="choice" value=(index);
|
||||||
button .nav-button onclick="next()" { "→" }
|
|
||||||
|
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 {
|
fn global_styles() -> Markup {
|
||||||
const BASE_STYLES: &str = r"
|
const BASE_STYLES: &str = r"
|
||||||
:root {
|
:root {
|
||||||
@ -304,36 +351,60 @@ fn interactive_script(total_sections: usize) -> Markup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_multilinear(mld_path: &Path) -> Option<NamedMultilinearInfo> {
|
fn process_dialog(
|
||||||
let Ok(file) = File::open(mld_path) else {
|
dialog_sequence: &DialogSequence<Change, Parameter>,
|
||||||
return None;
|
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 {
|
fn initialize_change_states(
|
||||||
let mut content = Vec::new();
|
changes: &HashMap<Parameter, Vec<Change>>,
|
||||||
convert(std::iter::once(&block.lines[0].text), &mut content);
|
) -> HashMap<Parameter, usize> {
|
||||||
|
changes.keys().map(|k| (k.clone(), 0)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
html! {
|
fn apply_block_changes(
|
||||||
form method="POST" {
|
block: &DialogBlock<Parameter>,
|
||||||
input type="hidden" name="progress" value=(progress);
|
changes: &HashMap<Parameter, Vec<Change>>,
|
||||||
input type="hidden" name="choice" value=(index);
|
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 {
|
fn load_multilinear(mld_path: &Path) -> Option<NamedMultilinearInfo> {
|
||||||
fieldset .choice-box {
|
parse_multilinear(File::open(mld_path).ok()?).ok()
|
||||||
@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}"))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_novel(
|
pub fn render_novel(
|
||||||
@ -343,7 +414,7 @@ pub fn render_novel(
|
|||||||
stream: &mut TcpStream,
|
stream: &mut TcpStream,
|
||||||
choice: usize,
|
choice: usize,
|
||||||
progress: &str,
|
progress: &str,
|
||||||
) -> Result<(), dialogi::ParsingError> {
|
) -> Result<(), ParsingError> {
|
||||||
let mut settings_context = SettingsContext::new();
|
let mut settings_context = SettingsContext::new();
|
||||||
extract_layers(&mut settings_context.layers, &mut config_map);
|
extract_layers(&mut settings_context.layers, &mut config_map);
|
||||||
|
|
||||||
@ -401,80 +472,3 @@ pub fn render_novel(
|
|||||||
|
|
||||||
Ok(())
|
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