diff --git a/src/campaign/campaign_tests.rs b/src/campaign/campaign_tests.rs index 03f4c9e..3951956 100644 --- a/src/campaign/campaign_tests.rs +++ b/src/campaign/campaign_tests.rs @@ -219,6 +219,25 @@ fn an_engine_directive_appears_in_the_transcript_under_its_own_prefix() { assert_eq!(sections[0].body, "storied> Recap the session."); } +#[test] +fn a_multi_paragraph_input_carries_the_prefix_on_every_line() { + let (campaign, _dir) = campaign(); + + campaign + .append_spoken( + time("#d1-0830"), + Speaker::Engine, + "Recap the session.\n\nKeep it short.", + ) + .unwrap(); + + let sections = campaign.transcript_entries().unwrap(); + assert_eq!( + sections[0].body, + "storied> Recap the session.\n\nstoried> Keep it short." + ); +} + #[test] fn narrations_at_the_same_time_share_a_section() { let (campaign, _dir) = campaign(); diff --git a/src/campaign/mod.rs b/src/campaign/mod.rs index eb0304b..a10d6da 100644 --- a/src/campaign/mod.rs +++ b/src/campaign/mod.rs @@ -110,8 +110,22 @@ impl Campaign { speaker: Speaker, input: &str, ) -> Result<(), String> { - self.transcript - .append(time, &format!("{}{input}", transcript::prefix(speaker))) + // Every non-blank line carries the prefix, not just the first. + // Replay reads the transcript line by line, and an unprefixed + // continuation line would come back as the DM's narration + // instead of the speaker's own words. + let prefix = transcript::prefix(speaker); + let spoken: Vec = input + .lines() + .map(|line| { + if line.trim().is_empty() { + String::new() + } else { + format!("{prefix}{line}") + } + }) + .collect(); + self.transcript.append(time, &spoken.join("\n")) } /// Records the DM's narration at the given game time.