From 6cbd458075af991f65a4e84a4cd60e02011e03b4 Mon Sep 17 00:00:00 2001 From: loomstyla Date: Mon, 2 Oct 2023 18:46:36 -0300 Subject: [PATCH 1/3] skip implementation --- cli/src/console.rs | 51 +++++++++++ runtime/src/runtime.rs | 197 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 231 insertions(+), 17 deletions(-) diff --git a/cli/src/console.rs b/cli/src/console.rs index dbaed14..56f4531 100644 --- a/cli/src/console.rs +++ b/cli/src/console.rs @@ -97,6 +97,8 @@ fn run_command(command: &str, parameters: Vec<&str>, runtime: &mut Runtime) -> S "set" => set_command(parameters, runtime), "->" => divert(parameters, runtime), "<->" => boomerang_divert(parameters, runtime), + "skip" => skip(runtime), + "skip-all" => skip_all(runtime), "reset" => reset_command(parameters, runtime), str => { if str.starts_with("->") { @@ -389,6 +391,34 @@ fn set_command(parameters: Vec<&str>, runtime: &mut Runtime) -> String { } } +fn skip(runtime: &mut Runtime) -> String { + match runtime.skip() { + Ok(output) => { + let mut output_string = output.text; + let choices_string = get_choices_string(output.choices); + if !choices_string.is_empty() { + output_string += &format!("\n{}", choices_string); + } + output_string + } + Err(error) => get_runtime_error_string(error, runtime), + } +} + +fn skip_all(runtime: &mut Runtime) -> String { + match runtime.skip_all() { + Ok(output) => { + let mut output_string = output.text; + let choices_string = get_choices_string(output.choices); + if !choices_string.is_empty() { + output_string += &format!("\n{}", choices_string); + } + output_string + } + Err(error) => get_runtime_error_string(error, runtime), + } +} + fn boomerang_divert(parameters: Vec<&str>, runtime: &mut Runtime) -> String { if parameters.is_empty() { return "Provide a section".to_string(); @@ -690,4 +720,25 @@ mod test { let stack_found = runtime.block_stack.clone(); assert_eq!(expected_stack, stack_found); } + + #[test] + fn skip_command() { + let mut runtime = Console::load_runtime("./fixtures/script"); + let mut rl = DefaultEditor::new().unwrap(); + + let expected_str = "You've just arrived in the bustling city, full of excitement and anticipation for your new job.\nThe skyline reaches for the clouds, and the sounds of traffic and people surround you.\nAs you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment.\n (1)I take a walk through a nearby park to relax and acclimate to the city.\n (2)I visit a popular street market to experience the city's unique flavors and energy.\n"; + let str_found = Console::process_line(Ok("skip".to_string()), &mut rl, &mut runtime).unwrap(); + assert_eq!(expected_str, &str_found); + } + + #[test] + fn skip_all_command() { + let mut runtime = Console::load_runtime("./fixtures/script"); + let mut rl = DefaultEditor::new().unwrap(); + + let expected_str = "As you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment.\n (1)I take a walk through a nearby park to relax and acclimate to the city.\n (2)I visit a popular street market to experience the city's unique flavors and energy.\n"; + let str_found = + Console::process_line(Ok("skip-all".to_string()), &mut rl, &mut runtime).unwrap(); + assert_eq!(expected_str, &str_found); + } } diff --git a/runtime/src/runtime.rs b/runtime/src/runtime.rs index 4633964..c37dccf 100644 --- a/runtime/src/runtime.rs +++ b/runtime/src/runtime.rs @@ -107,7 +107,7 @@ pub enum Block { }, } -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)] pub struct BlockSettings { pub id: BlockId, pub script: Script, @@ -226,7 +226,7 @@ impl Runtime { } pub fn boomerang_divert(&mut self, section: &Section) -> Result, RuntimeError> { - let new_stack = self.get_section_block_ids(section)?; + let new_stack: Vec = self.get_section_block_ids(section)?; let mut blocks_added = Vec::default(); for block in new_stack { @@ -263,6 +263,33 @@ impl Runtime { Output::from_blocks(blocks, self) } + pub fn skip(&mut self) -> Result { + let mut output = self.progress_story()?; + + while output.choices.is_empty() { + let mut new_output = self.progress_story()?; + output.blocks.append(&mut new_output.blocks); + output.choices = new_output.choices; + output.text += "\n"; + output.text += &new_output.text; + } + + Ok(output) + } + + pub fn skip_all(&mut self) -> Result { + let mut output = self.progress_story()?; + + while output.choices.is_empty() { + let mut new_output = self.progress_story()?; + output.blocks.append(&mut new_output.blocks); + output.choices = new_output.choices; + output.text = new_output.text; + } + + Ok(output) + } + pub fn get_block(&self, stack_data: &BlockStackData) -> Result { let id = stack_data.id; let cuentitos_block = self.get_cuentitos_block(id)?; @@ -342,7 +369,7 @@ impl Runtime { return Err(RuntimeError::InvalidBlockId(choices[choice])); } - let mut blocks = Self::push_stack_until_text(self, choices[choice])?; + let mut blocks = Self::push_stack_until_text_or_choice(self, choices[choice])?; let mut output = self.progress_story()?; blocks.append(&mut output.blocks); output.blocks = blocks; @@ -780,7 +807,7 @@ impl Runtime { Ok(()) } - fn push_stack_until_text(&mut self, id: BlockId) -> Result, RuntimeError> { + fn push_stack_until_text_or_choice(&mut self, id: BlockId) -> Result, RuntimeError> { if !self.meets_requirements_and_chance(id)? { return self.push_next(id); } @@ -806,7 +833,7 @@ impl Runtime { settings: _, } => { if let Some(next) = self.get_random_block_from_bucket(block.get_settings())? { - blocks.append(&mut self.push_stack_until_text(next)?); + blocks.append(&mut self.push_stack_until_text_or_choice(next)?); Ok(blocks) } else { blocks.append(&mut self.update_stack()?); @@ -817,7 +844,7 @@ impl Runtime { match next { NextBlock::BlockId(id) => { self.block_stack.clear(); - blocks.append(&mut self.push_stack_until_text(id)?) + blocks.append(&mut self.push_stack_until_text_or_choice(id)?) } NextBlock::EndOfFile => { return Err(RuntimeError::StoryFinished); @@ -831,7 +858,7 @@ impl Runtime { } cuentitos_common::Block::BoomerangDivert { next, settings: _ } => { match next { - NextBlock::BlockId(id) => blocks.append(&mut self.push_stack_until_text(id)?), + NextBlock::BlockId(id) => blocks.append(&mut self.push_stack_until_text_or_choice(id)?), NextBlock::EndOfFile => { return Err(RuntimeError::StoryFinished); } @@ -895,7 +922,7 @@ impl Runtime { } if self.block_stack.is_empty() { - return self.push_stack_until_text(0); + return self.push_stack_until_text_or_choice(0); } let last_block_id = match self.block_stack.last() { @@ -914,7 +941,7 @@ impl Runtime { if !settings.children.is_empty() { if let Some(child) = self.get_next_child_in_stack(&settings, 0)? { - return self.push_stack_until_text(child); + return self.push_stack_until_text_or_choice(child); } } @@ -947,7 +974,7 @@ impl Runtime { fn push_next(&mut self, previous_id: BlockId) -> Result, RuntimeError> { if self.block_stack.is_empty() { - return self.push_stack_until_text(previous_id + 1); + return self.push_stack_until_text_or_choice(previous_id + 1); } let new_block_id: usize = match self.block_stack.last() { @@ -976,7 +1003,7 @@ impl Runtime { { continue; } - return self.push_stack_until_text(*sibling); + return self.push_stack_until_text_or_choice(*sibling); } if *sibling == previous_id { previous_block_found = true; @@ -1084,17 +1111,153 @@ mod test { use std::{collections::HashMap, fmt::Display, str::FromStr, vec}; use crate::{ - runtime::{BlockStackData, Chance}, - GameState, Runtime, RuntimeError, + runtime::{self, BlockStackData, Chance}, + GameState, Output, Runtime, RuntimeError, }; use cuentitos_common::{ - condition::ComparisonOperator, modifier::ModifierOperator, Block, Condition, Config, Database, - FrequencyModifier, Function, I18n, LanguageDb, LanguageId, Modifier, NextBlock, Requirement, - Section, VariableKind, + condition::ComparisonOperator, modifier::ModifierOperator, Block, BlockSettings, Condition, + Config, Database, FrequencyModifier, Function, I18n, LanguageDb, LanguageId, Modifier, + NextBlock, Requirement, Section, VariableKind, }; use rand::SeedableRng; use rand_pcg::Pcg32; + #[test] + fn skip() { + let text_1 = Block::Text { + id: "a".to_string(), + settings: BlockSettings::default(), + }; + let text_2 = Block::Text { + id: "b".to_string(), + settings: BlockSettings { + children: vec![2], + ..Default::default() + }, + }; + let choice = Block::Choice { + id: "c".to_string(), + settings: BlockSettings::default(), + }; + + let mut en: LanguageDb = HashMap::default(); + en.insert("a".to_string(), "Text 1".to_string()); + en.insert("b".to_string(), "Text 2".to_string()); + en.insert("c".to_string(), "Choice".to_string()); + let mut strings: HashMap = HashMap::default(); + strings.insert("en".to_string(), en); + + let i18n = I18n { + locales: vec!["en".to_string()], + default_locale: "en".to_string(), + strings, + }; + + let database = Database { + blocks: vec![text_1, text_2, choice], + i18n, + ..Default::default() + }; + + let mut runtime = Runtime { + database, + current_locale: "en".to_string(), + ..Default::default() + }; + + let output_text_1 = runtime::Block::Text { + text: "Text 1".to_string(), + settings: runtime::BlockSettings { + id: 0, + ..Default::default() + }, + }; + let output_text_2 = runtime::Block::Text { + text: "Text 2".to_string(), + settings: runtime::BlockSettings { + id: 1, + ..Default::default() + }, + }; + + let output = runtime.skip().unwrap(); + let expected_output = Output { + text: "Text 1\nText 2".to_string(), + choices: vec!["Choice".to_string()], + blocks: vec![output_text_1, output_text_2], + }; + + assert_eq!(output, expected_output); + } + + #[test] + fn skip_all() { + let text_1 = Block::Text { + id: "a".to_string(), + settings: BlockSettings::default(), + }; + let text_2 = Block::Text { + id: "b".to_string(), + settings: BlockSettings { + children: vec![2], + ..Default::default() + }, + }; + let choice = Block::Choice { + id: "c".to_string(), + settings: BlockSettings::default(), + }; + + let mut en: LanguageDb = HashMap::default(); + en.insert("a".to_string(), "Text 1".to_string()); + en.insert("b".to_string(), "Text 2".to_string()); + en.insert("c".to_string(), "Choice".to_string()); + let mut strings: HashMap = HashMap::default(); + strings.insert("en".to_string(), en); + + let i18n = I18n { + locales: vec!["en".to_string()], + default_locale: "en".to_string(), + strings, + }; + + let database = Database { + blocks: vec![text_1, text_2, choice], + i18n, + ..Default::default() + }; + + let mut runtime = Runtime { + database, + current_locale: "en".to_string(), + ..Default::default() + }; + + let output_text_1 = runtime::Block::Text { + text: "Text 1".to_string(), + settings: runtime::BlockSettings { + id: 0, + ..Default::default() + }, + }; + let output_text_2 = runtime::Block::Text { + text: "Text 2".to_string(), + settings: runtime::BlockSettings { + id: 1, + ..Default::default() + }, + }; + + let output = runtime.skip_all().unwrap(); + let expected_output = Output { + text: "Text 2".to_string(), + choices: vec!["Choice".to_string()], + blocks: vec![output_text_1, output_text_2], + }; + + assert_eq!(output, expected_output); + } + #[test] fn new_runtime_works_correctly() { let database = Database::default(); @@ -1780,7 +1943,7 @@ mod test { .unwrap() .unwrap(); assert_eq!(id, 1); - Runtime::push_stack_until_text(&mut runtime, 1).unwrap(); + Runtime::push_stack_until_text_or_choice(&mut runtime, 1).unwrap(); let bucket_settings = runtime .get_cuentitos_block(0) .unwrap() From 715b40fa2be5c67c8770ed7507816d6cddb02c39 Mon Sep 17 00:00:00 2001 From: loomstyla Date: Thu, 5 Oct 2023 15:39:04 -0300 Subject: [PATCH 2/3] story_progress_style configuration --- cli/src/console.rs | 42 ++++++++- common/src/config.rs | 9 ++ compiler/en.csv | 93 ++++++++++-------- examples/cuentitos.toml | 1 + runtime/src/lib.rs | 1 + runtime/src/runtime.rs | 203 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 299 insertions(+), 50 deletions(-) diff --git a/cli/src/console.rs b/cli/src/console.rs index 56f4531..3d33b54 100644 --- a/cli/src/console.rs +++ b/cli/src/console.rs @@ -91,13 +91,14 @@ impl Console { fn run_command(command: &str, parameters: Vec<&str>, runtime: &mut Runtime) -> String { match command { "" => progress_story(runtime), + "next" | "n" => next_block(runtime), "sections" => sections_command(parameters, runtime), "?" => state_command(parameters, runtime), "variables" => variables_command(parameters, runtime), "set" => set_command(parameters, runtime), "->" => divert(parameters, runtime), "<->" => boomerang_divert(parameters, runtime), - "skip" => skip(runtime), + "skip" | "s" => skip(runtime), "skip-all" => skip_all(runtime), "reset" => reset_command(parameters, runtime), str => { @@ -152,10 +153,12 @@ fn get_output_string(output: Output, runtime: &Runtime) -> String { for block in output.blocks { let block_output = get_block_string(block, runtime); if !block_output.is_empty() { - output_string += &block_output; + output_string = output_string + &block_output + "\n"; } } + output_string = output_string.trim_end().to_string(); + let choices_string = get_choices_string(output.choices); if !choices_string.is_empty() { output_string += &format!("\n{}", choices_string); @@ -197,6 +200,8 @@ fn get_block_string(block: Block, runtime: &Runtime) -> String { } _ => block_string, } + .trim_end() + .to_string() } fn get_change_string(chance: &Chance) -> String { @@ -257,6 +262,13 @@ fn progress_story(runtime: &mut Runtime) -> String { } } +fn next_block(runtime: &mut Runtime) -> String { + match runtime.next_block() { + Ok(output) => get_output_string(output, runtime), + Err(error) => get_runtime_error_string(error, runtime), + } +} + fn grep(pattern: &str, source: &str) -> String { let mut final_string = String::default(); @@ -542,7 +554,11 @@ mod test { let str_found = Console::process_line(Ok("".to_string()), &mut rl, &mut runtime).unwrap(); assert_eq!(expected_str, &str_found); - let str_found = runtime.current().unwrap().text; + runtime.reset_all(); + runtime.database.config.story_progress_style = StoryProgressStyle::Skip; + + let expected_str = "You've just arrived in the bustling city, full of excitement and anticipation for your new job.\nThe skyline reaches for the clouds, and the sounds of traffic and people surround you.\nAs you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment.\n (1)I take a walk through a nearby park to relax and acclimate to the city.\n (2)I visit a popular street market to experience the city's unique flavors and energy.\n"; + let str_found = Console::process_line(Ok("".to_string()), &mut rl, &mut runtime).unwrap(); assert_eq!(expected_str, &str_found); } @@ -729,6 +745,11 @@ mod test { let expected_str = "You've just arrived in the bustling city, full of excitement and anticipation for your new job.\nThe skyline reaches for the clouds, and the sounds of traffic and people surround you.\nAs you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment.\n (1)I take a walk through a nearby park to relax and acclimate to the city.\n (2)I visit a popular street market to experience the city's unique flavors and energy.\n"; let str_found = Console::process_line(Ok("skip".to_string()), &mut rl, &mut runtime).unwrap(); assert_eq!(expected_str, &str_found); + + runtime.reset_all(); + + let str_found = Console::process_line(Ok("s".to_string()), &mut rl, &mut runtime).unwrap(); + assert_eq!(expected_str, &str_found); } #[test] @@ -741,4 +762,19 @@ mod test { Console::process_line(Ok("skip-all".to_string()), &mut rl, &mut runtime).unwrap(); assert_eq!(expected_str, &str_found); } + + #[test] + fn next_command() { + let mut runtime = Console::load_runtime("./fixtures/script"); + let mut rl = DefaultEditor::new().unwrap(); + + let expected_str = "You've just arrived in the bustling city, full of excitement and anticipation for your new job."; + let str_found = Console::process_line(Ok("n".to_string()), &mut rl, &mut runtime).unwrap(); + assert_eq!(expected_str, &str_found); + + runtime.reset_all(); + + let str_found = Console::process_line(Ok("next".to_string()), &mut rl, &mut runtime).unwrap(); + assert_eq!(expected_str, &str_found); + } } diff --git a/common/src/config.rs b/common/src/config.rs index d379224..ea210c4 100644 --- a/common/src/config.rs +++ b/common/src/config.rs @@ -14,6 +14,15 @@ pub struct Config { pub variables: HashMap, pub locales: Vec, pub default_locale: String, + #[serde(default)] + pub story_progress_style: StoryProgressStyle, +} +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Eq)] +#[serde(rename_all = "lowercase")] +pub enum StoryProgressStyle { + #[default] + Next, + Skip, } impl Config { diff --git a/compiler/en.csv b/compiler/en.csv index 196222a..6f27dbb 100644 --- a/compiler/en.csv +++ b/compiler/en.csv @@ -1,51 +1,66 @@ Id,Text -61,I call my parents -64,"The phone rings twice, and dad picks up. You have a good chat." -4,I take a walk through a nearby park to relax and acclimate to the city. -28,The musician smiles and nods thanking you. -67,"The phone rings twice, and mom picks up. You have a good chat." -27,I leave two dollars to the artist. -32,I grab my phone and take pictures of the murals. -2,"The skyline reaches for the clouds, and the sounds of traffic and people surround you." +30,"Wandering the market, you stumble upon a hidden alley adorned with vibrant street art." +115,"You buy an apple and take a bite. Hmm, delicious." +10,"At the bustling street market, you discover a food stand offering mouthwa tering delicacies." +40,The moonlight gives the room a peaceful tone. +74,You decide it's now time to go to sleep. +18,"You spot a visibly agitated vendor, their clenched fists and piercing glare making it clear that they're unhappy with the current situation unfolding before them." +83,Go to the Farmer's Market +116,Buy an orange +38,The sun shines bright through the window. +81,Explore a museum +5,"As you stroll through the nearby park, the soothing sounds of rustling leaves and chirping birds help calm your senses." 8,This serene oasis gives you the confidence to face the challenges ahead as you acclimate to your new life in the bustling city. -13,"You notice the stand owner, their eyes sparkling with joy as they animatedly describe their homemade offerings to an eager customer." +47,You decide to focus on the now... +117,"You buy an orange and take a bite. Hmm, refreshing." 22,"The vendor at a nearby food stand appears worn, their movements slow and deliberate, as they attempt to maintain a smile while attending to the seemingly endless stream of customers." +56,I go to bed +29,"I nod when the musician looks my way, to show I really enjoy the music." +113,You stop by a fruit stand that sells apples and oranges. +49,I make some tea +72,"The phone rings ten times, nobody is at home." +24,"As you try to navigate the crowded market, you're drawn to the entrancing melody of a street musician." +44,That makes you feel overwhelmed. +101,You learn something new today and return home with a smile on your face. +62,I call my parents 9,I visit a popular street market to experience the city's unique flavors and energy. +57,"Feeling depleted of spoons, you go right back to bed." +87,"You enter the museum, it is crowded but the exhibitions look amazing." +68,"The phone rings twice, and mom picks up. You have a good chat." +4,I take a walk through a nearby park to relax and acclimate to the city. 23,You feel they're too busy to bother them with questions. +91,Where should I go? 26,"You take a moment to appreciate the beauty of the music, feeling a connection to the artist and the vibrant energy they bring to the urban landscape." -14,"You see the owner beaming with joy, their infectious smile and animated gestures inviting customers to try their delectable creations." -17,"You come across a vendor with furrowed brows and a tense expression, their voice raised as they heatedly argue with a customer over a transaction at their stand." -7,"A solitary figure sits on the bench, engrossed in a book, seemingly unfazed by the surrounding city noise." -34,"This unexpected oasis of visual tranquility provides a respite from the chaos of the city, inspiring you to explore more of the urban canvas and the stories it holds." -29,"I nod when the musician looks my way, to show I really enjoy the music." -30,"Wandering the market, you stumble upon a hidden alley adorned with vibrant street art." +100,Go home. +105,You get to the farmer's market. It's very early and some stands are still being set up. +33,"I keep walking, even if the murals look good, the darkness of the alley is unsettling." +13,"You notice the stand owner, their eyes sparkling with joy as they animatedly describe their homemade offerings to an eager customer." 37,"As you enter the peaceful sanctuary of your room, you take a deep breath, relieved to have a quiet space where you can recharge and prepare for the challenges ahead." -5,"As you stroll through the nearby park, the soothing sounds of rustling leaves and chirping birds help calm your senses." +27,I leave two dollars to the artist. +2,"The skyline reaches for the clouds, and the sounds of traffic and people surround you." +7,"A solitary figure sits on the bench, engrossed in a book, seemingly unfazed by the surrounding city noise." +107,The fruit looks very appetizing and you feel like trying some. +1,"You've just arrived in the bustling city, full of excitement and anticipation for your new job." +92,Go to the dinosaur section. +6,"You find a quiet bench to sit on, taking a moment to breathe deeply and gather your thoughts." +28,The musician smiles and nods thanking you. 36,"Feeling mentally and physically exhausted from the day's adventures, you decide it's time to head back to your hotel." 42,You start to think about all the stuff you need to do tomorrow. -71,"The phone rings ten times, nobody is at home." -33,"I keep walking, even if the murals look good, the darkness of the alley is unsettling." -10,"At the bustling street market, you discover a food stand offering mouthwa tering delicacies." -80,Explore a museum -18,"You spot a visibly agitated vendor, their clenched fists and piercing glare making it clear that they're unhappy with the current situation unfolding before them." -6,"You find a quiet bench to sit on, taking a moment to breathe deeply and gather your thoughts." -1,"You've just arrived in the bustling city, full of excitement and anticipation for your new job." -40,The moonlight gives the room a peaceful tone. -49,I make some tea -44,That makes you feel overwhelmed. -57,"Feeling depleted of spoons, you go right back to bed." -73,You decide it's now time to go to sleep. -38,The sun shines bright through the window. -82,Go to the Farmer's Market -86,You get to the museum door. You watch through the window. It seems crowded. -89,You get to the farmer's market. It's very early and some stands are still being set up. -21,"You observe a vendor at a small food stand, their shoulders slumped and eyes slightly glazed as they quietly serve customers, mustering just enough energy to complete each transaction." -24,"As you try to navigate the crowded market, you're drawn to the entrancing melody of a street musician." -3,"As you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment." 31,"Each colorful mural tells a different story, capturing your imagination and sparking your creativity." +98,You admire the paintings. +32,I grab my phone and take pictures of the murals. +65,"The phone rings twice, and dad picks up. You have a good chat." +17,"You come across a vendor with furrowed brows and a tense expression, their voice raised as they heatedly argue with a customer over a transaction at their stand." +21,"You observe a vendor at a small food stand, their shoulders slumped and eyes slightly glazed as they quietly serve customers, mustering just enough energy to complete each transaction." +109,You feel satisfied with the fruit you bought and return home with a smile on your face. +25,"The captivating sound creates a soothing bubble, momentarily transporting you away from the city's noise." 51,A good cup of tea is always good to regulate after the sensory overload of the city. +96,Go to the art section. +34,"This unexpected oasis of visual tranquility provides a respite from the chaos of the city, inspiring you to explore more of the urban canvas and the stories it holds." +14,"You see the owner beaming with joy, their infectious smile and animated gestures inviting customers to try their delectable creations." +94,The Tyrannosaurus Rex is scary up close. +106,You take a stroll while patiently waiting for the market to finish setting up. +3,"As you take your first steps in this urban jungle, you feel a mix of emotions, hoping to find your place in this new environment." +80,You wake up feeling refreshed. Let's see what this day brings. +114,Buy an apple 52,You sit in the couch to enjoy your tea. Drink half of the cup and fall asleep. -47,You decide to focus on the now... -79,You wake up feeling refreshed. Let's see what this day brings. -25,"The captivating sound creates a soothing bubble, momentarily transporting you away from the city's noise." -56,I go to bed diff --git a/examples/cuentitos.toml b/examples/cuentitos.toml index 73274dd..7a54c11 100644 --- a/examples/cuentitos.toml +++ b/examples/cuentitos.toml @@ -1,5 +1,6 @@ locales = ['en'] default_locale = 'en' +story_progress_style = 'skip' [variables] energy = "integer" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 30a14e2..a4478cf 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2,6 +2,7 @@ mod runtime; pub use runtime::*; pub use cuentitos_common::Database; +pub use cuentitos_common::StoryProgressStyle; mod game_state; pub use cuentitos_common::Section; diff --git a/runtime/src/runtime.rs b/runtime/src/runtime.rs index c37dccf..a2566aa 100644 --- a/runtime/src/runtime.rs +++ b/runtime/src/runtime.rs @@ -254,7 +254,7 @@ impl Runtime { Output::from_blocks(blocks, self) } - pub fn progress_story(&mut self) -> Result { + pub fn next_block(&mut self) -> Result { if self.database.blocks.is_empty() { return Err(RuntimeError::EmptyDatabase); } @@ -263,11 +263,18 @@ impl Runtime { Output::from_blocks(blocks, self) } + pub fn progress_story(&mut self) -> Result { + match self.database.config.story_progress_style { + cuentitos_common::StoryProgressStyle::Next => self.next_block(), + cuentitos_common::StoryProgressStyle::Skip => self.skip(), + } + } + pub fn skip(&mut self) -> Result { - let mut output = self.progress_story()?; + let mut output = self.next_block()?; while output.choices.is_empty() { - let mut new_output = self.progress_story()?; + let mut new_output = self.next_block()?; output.blocks.append(&mut new_output.blocks); output.choices = new_output.choices; output.text += "\n"; @@ -278,10 +285,10 @@ impl Runtime { } pub fn skip_all(&mut self) -> Result { - let mut output = self.progress_story()?; + let mut output = self.next_block()?; while output.choices.is_empty() { - let mut new_output = self.progress_story()?; + let mut new_output = self.next_block()?; output.blocks.append(&mut new_output.blocks); output.choices = new_output.choices; output.text = new_output.text; @@ -1815,7 +1822,7 @@ mod test { } #[test] - fn next_block_works_correctly() { + fn next_works_correctly() { let settings = cuentitos_common::BlockSettings { children: vec![1, 2], ..Default::default() @@ -1861,7 +1868,7 @@ mod test { ..Default::default() }; - let output = runtime.progress_story().unwrap(); + let output = runtime.next_block().unwrap(); let block = runtime .get_block(&BlockStackData { id: 0, @@ -3412,7 +3419,7 @@ mod test { } #[test] - fn next_block_throws_error_if_theres_a_choice() { + fn next_throws_error_if_theres_a_choice() { let text = Block::Text { id: String::default(), settings: cuentitos_common::BlockSettings { @@ -3851,6 +3858,186 @@ mod test { assert!(runtime.section.is_none()); } + #[test] + fn progress_story_works_with_next() { + let text_1 = Block::Text { + id: "text_1".to_string(), + settings: BlockSettings::default(), + }; + + let settings = cuentitos_common::BlockSettings { + children: vec![2, 3], + ..Default::default() + }; + let text_2 = Block::Text { + id: "text_2".to_string(), + settings, + }; + + let choice_1 = Block::Choice { + id: "1".to_string(), + settings: cuentitos_common::BlockSettings::default(), + }; + + let choice_2 = Block::Choice { + id: "2".to_string(), + settings: cuentitos_common::BlockSettings::default(), + }; + + let mut en: LanguageDb = HashMap::default(); + en.insert("1".to_string(), "1".to_string()); + en.insert("2".to_string(), "2".to_string()); + en.insert("text_1".to_string(), "text_1".to_string()); + en.insert("text_2".to_string(), "text_2".to_string()); + + let mut strings: HashMap = HashMap::default(); + strings.insert("en".to_string(), en); + + let i18n = I18n { + locales: vec!["en".to_string()], + default_locale: "en".to_string(), + strings, + }; + + let database = Database { + blocks: vec![ + text_1.clone(), + text_2.clone(), + choice_1.clone(), + choice_2.clone(), + ], + i18n, + config: Config { + story_progress_style: cuentitos_common::StoryProgressStyle::Next, + ..Default::default() + }, + ..Default::default() + }; + + let mut runtime = Runtime { + database, + current_locale: "en".to_string(), + ..Default::default() + }; + + let output = runtime.progress_story().unwrap(); + let block = runtime + .get_block(&BlockStackData { + id: 0, + chance: Chance::None, + }) + .unwrap(); + + let expected_output = crate::Output { + text: "text_1".to_string(), + choices: Vec::default(), + blocks: vec![block], + ..Default::default() + }; + + assert_eq!(output, expected_output); + assert_eq!( + runtime.block_stack, + vec![BlockStackData { + id: 0, + chance: Chance::None + }] + ); + } + + #[test] + fn progress_story_works_with_skip() { + let text_1 = Block::Text { + id: "text_1".to_string(), + settings: BlockSettings::default(), + }; + + let settings = cuentitos_common::BlockSettings { + children: vec![2, 3], + ..Default::default() + }; + let text_2 = Block::Text { + id: "text_2".to_string(), + settings, + }; + + let choice_1 = Block::Choice { + id: "1".to_string(), + settings: cuentitos_common::BlockSettings::default(), + }; + + let choice_2 = Block::Choice { + id: "2".to_string(), + settings: cuentitos_common::BlockSettings::default(), + }; + + let mut en: LanguageDb = HashMap::default(); + en.insert("1".to_string(), "1".to_string()); + en.insert("2".to_string(), "2".to_string()); + en.insert("text_1".to_string(), "text_1".to_string()); + en.insert("text_2".to_string(), "text_2".to_string()); + + let mut strings: HashMap = HashMap::default(); + strings.insert("en".to_string(), en); + + let i18n = I18n { + locales: vec!["en".to_string()], + default_locale: "en".to_string(), + strings, + }; + + let database = Database { + blocks: vec![ + text_1.clone(), + text_2.clone(), + choice_1.clone(), + choice_2.clone(), + ], + i18n, + config: Config { + story_progress_style: cuentitos_common::StoryProgressStyle::Skip, + ..Default::default() + }, + ..Default::default() + }; + + let mut runtime = Runtime { + database, + current_locale: "en".to_string(), + ..Default::default() + }; + + let output = runtime.progress_story().unwrap(); + let block_1 = runtime + .get_block(&BlockStackData { + id: 0, + chance: Chance::None, + }) + .unwrap(); + + let block_2 = runtime + .get_block(&BlockStackData { + id: 1, + chance: Chance::None, + }) + .unwrap(); + + let expected_output = crate::Output { + text: "text_1\ntext_2".to_string(), + choices: vec!["1".to_string(), "2".to_string()], + blocks: vec![block_1, block_2], + ..Default::default() + }; + + assert_eq!(output, expected_output); + assert_eq!( + runtime.block_stack, + vec![BlockStackData { + id: 1, + chance: Chance::None + }] + ); + } #[derive(Debug, Default, PartialEq, Eq)] enum TimeOfDay { #[default] From 007399be8c15d7e7ce417c1e705e8f7eb6f459b8 Mon Sep 17 00:00:00 2001 From: loomstyla Date: Thu, 5 Oct 2023 15:45:40 -0300 Subject: [PATCH 3/3] Update cuentitos.toml --- examples/cuentitos.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cuentitos.toml b/examples/cuentitos.toml index 7a54c11..47ae375 100644 --- a/examples/cuentitos.toml +++ b/examples/cuentitos.toml @@ -1,6 +1,6 @@ locales = ['en'] default_locale = 'en' -story_progress_style = 'skip' +story_progress_style = 'next' [variables] energy = "integer"