Compare commits

..

5 commits

Author SHA1 Message Date
yuni b2f28c36f1 fix ending of chats 2024-10-26 02:19:27 +02:00
yuni 092feccc84 disable chat timer 2024-10-26 00:59:44 +02:00
yuni b01d53833b add implicit "Continue" option to all conversations 2024-10-26 00:41:46 +02:00
yuni 3234b1f4bb remove "`" (backquote) keybinding 2024-10-26 00:40:24 +02:00
yuni 5723fd909b cargo fmt 2024-10-26 00:37:58 +02:00
6 changed files with 99 additions and 43 deletions

View file

@ -54,7 +54,6 @@ Press **ESC** to view these any time from the in-game menu.
- **T**: Cruise control - **T**: Cruise control
- **R**: Rotate (hold + move mouse) - **R**: Rotate (hold + move mouse)
- **Y**: Rotation stabilizer - **Y**: Rotation stabilizer
- **`**: Fast forward conversation
- **AWSD/Shift/Ctrl**: Move - **AWSD/Shift/Ctrl**: Move
- **J/K/U/L/I/O**: Rotate - **J/K/U/L/I/O**: Rotate
- **F11**: Fullscreen - **F11**: Fullscreen

View file

@ -25,6 +25,8 @@ pub const CHATS: &[&str] = &[
include_str!("chats/thebe.yaml"), include_str!("chats/thebe.yaml"),
]; ];
pub const TEXT_CONTINUE: &str = "Continue...";
pub const TOKEN_CHAT: &str = "chat"; pub const TOKEN_CHAT: &str = "chat";
pub const TOKEN_MSG: &str = "msg"; pub const TOKEN_MSG: &str = "msg";
pub const TOKEN_SYSTEM: &str = "system"; pub const TOKEN_SYSTEM: &str = "system";
@ -46,6 +48,7 @@ pub const TOKEN_IF_INLINE: &str = "if "; // for lines like `- if foo:`
pub const DEFAULT_SOUND: &str = "chat"; pub const DEFAULT_SOUND: &str = "chat";
pub const MAX_BRANCH_DEPTH: usize = 64; pub const MAX_BRANCH_DEPTH: usize = 64;
pub const ENABLE_CHOICE_TIMER: bool = false;
pub const CHOICE_TIMER: f64 = 40.0 * var::DEFAULT_CHAT_SPEED as f64; pub const CHOICE_TIMER: f64 = 40.0 * var::DEFAULT_CHAT_SPEED as f64;
pub const LETTERS_PER_SECOND: f32 = 17.0; pub const LETTERS_PER_SECOND: f32 = 17.0;
pub const TALKER_SPEED_FACTOR: f32 = var::DEFAULT_CHAT_SPEED / LETTERS_PER_SECOND; pub const TALKER_SPEED_FACTOR: f32 = var::DEFAULT_CHAT_SPEED / LETTERS_PER_SECOND;
@ -105,6 +108,7 @@ pub struct Chat {
pub internal_id: usize, pub internal_id: usize,
pub position: ChatPos, pub position: ChatPos,
pub timer: f64, pub timer: f64,
pub message_open: bool,
pub talker: Talker, pub talker: Talker,
} }
@ -473,6 +477,7 @@ impl ChatDB {
let mut processed_a_choice = false; let mut processed_a_choice = false;
match current_item { match current_item {
Some(Value::String(message)) => { Some(Value::String(message)) => {
chat.message_open = true;
event.send(ChatEvent::SpawnMessage( event.send(ChatEvent::SpawnMessage(
message.to_string(), message.to_string(),
hud::LogLevel::Chat, hud::LogLevel::Chat,
@ -520,23 +525,35 @@ impl ChatDB {
let key = key.as_str(); let key = key.as_str();
match (key, value) { match (key, value) {
(Some(TOKEN_MSG), Value::String(message)) => { (Some(TOKEN_MSG), Value::String(message)) => {
let loglevel = hud::LogLevel::Chat;
if loglevel.is_subtitle() {
chat.message_open = true;
}
event.send(ChatEvent::SpawnMessage( event.send(ChatEvent::SpawnMessage(
message.to_string(), message.to_string(),
hud::LogLevel::Chat, loglevel,
sound.clone(), sound.clone(),
)); ));
} }
(Some(TOKEN_SYSTEM), Value::String(message)) => { (Some(TOKEN_SYSTEM), Value::String(message)) => {
let loglevel = hud::LogLevel::Info;
if loglevel.is_subtitle() {
chat.message_open = true;
}
event.send(ChatEvent::SpawnMessage( event.send(ChatEvent::SpawnMessage(
message.to_string(), message.to_string(),
hud::LogLevel::Info, loglevel,
sound.clone(), sound.clone(),
)); ));
} }
(Some(TOKEN_WARN), Value::String(message)) => { (Some(TOKEN_WARN), Value::String(message)) => {
let loglevel = hud::LogLevel::Warning;
if loglevel.is_subtitle() {
chat.message_open = true;
}
event.send(ChatEvent::SpawnMessage( event.send(ChatEvent::SpawnMessage(
message.to_string(), message.to_string(),
hud::LogLevel::Warning, loglevel,
sound.clone(), sound.clone(),
)); ));
} }
@ -575,11 +592,7 @@ impl ChatDB {
} }
None => { None => {
if chat.position.len() == 0 { if chat.position.len() == 0 {
event.send(ChatEvent::SpawnMessage( // Here it used to spawn the "Disconnected" message.
"Disconnected.".to_string(),
hud::LogLevel::Info,
DEFAULT_SOUND.to_string(),
));
event.send(ChatEvent::DespawnAllChats); event.send(ChatEvent::DespawnAllChats);
} }
} }
@ -633,6 +646,19 @@ impl ChatDB {
break; break;
} }
} }
// Add a "Continue" choice to any conversation line that doesn't define any choices
let choices_available = key > 0;
if chat.message_open && !choices_available {
let goto: Vec<usize> = chat.position.clone();
event.send(ChatEvent::SpawnChoice(
String::from(TEXT_CONTINUE),
0,
goto,
true,
None,
));
}
} }
} }
} }
@ -671,6 +697,7 @@ pub fn handle_new_conversations(
let mut chat = Chat { let mut chat = Chat {
internal_id: chat_id, internal_id: chat_id,
position: vec![0], position: vec![0],
message_open: false,
timer: time.elapsed_seconds_f64(), timer: time.elapsed_seconds_f64(),
talker: event.talker.clone(), talker: event.talker.clone(),
}; };
@ -728,6 +755,12 @@ pub fn handle_chat_events(
} }
ChatEvent::DespawnAllChats => { ChatEvent::DespawnAllChats => {
commands.entity(chat_entity).despawn(); commands.entity(chat_entity).despawn();
// also despawn all choices (keep in sync with DespawnAllChoices handler)
for entity in &q_choices {
commands.entity(entity).despawn();
}
choice_key = 0;
} }
ChatEvent::SpawnMessage(message, level, sound) => { ChatEvent::SpawnMessage(message, level, sound) => {
match level { match level {
@ -754,11 +787,15 @@ pub fn handle_chat_events(
); );
} }
} }
if ENABLE_CHOICE_TIMER {
chat.timer = now chat.timer = now
+ ((message.len() as f32).max(CHAT_SPEED_MIN_LEN) + ((message.len() as f32).max(CHAT_SPEED_MIN_LEN)
* TALKER_SPEED_FACTOR * TALKER_SPEED_FACTOR
* chat.talker.talking_speed * chat.talker.talking_speed
/ settings.chat_speed) as f64; / settings.chat_speed) as f64;
} else {
chat.timer = f64::INFINITY;
}
let sfx = audio::str2sfx(sound); let sfx = audio::str2sfx(sound);
ew_sfx.send(audio::PlaySfxEvent(sfx)); ew_sfx.send(audio::PlaySfxEvent(sfx));
@ -778,8 +815,10 @@ pub fn handle_chat_events(
}, },
)); ));
choice_key += 1; choice_key += 1;
if !nowait { if ENABLE_CHOICE_TIMER && !nowait {
chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64; chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64;
} else {
chat.timer = f64::INFINITY;
} }
} }
ChatEvent::RunScript(script) => { ChatEvent::RunScript(script) => {
@ -809,7 +848,8 @@ fn handle_reply_keys(
settings: Res<var::Settings>, settings: Res<var::Settings>,
q_choices: Query<&Choice>, q_choices: Query<&Choice>,
mut q_chats: Query<&mut Chat>, mut q_chats: Query<&mut Chat>,
mut evwriter_sfx: EventWriter<audio::PlaySfxEvent>, mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
mut ew_chat: EventWriter<ChatEvent>,
time: Res<Time>, time: Res<Time>,
) { ) {
let mut selected_choice: usize = 0; let mut selected_choice: usize = 0;
@ -817,10 +857,18 @@ fn handle_reply_keys(
if keyboard_input.just_pressed(key) { if keyboard_input.just_pressed(key) {
for choice in &q_choices { for choice in &q_choices {
if choice.key == selected_choice { if choice.key == selected_choice {
if choice.goto.is_empty() {
// Conversation ended. No need to advance the chat.
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
ew_chat.send(ChatEvent::DespawnAllChats);
break 'outer;
}
if let Ok(mut chat) = q_chats.get_single_mut() { if let Ok(mut chat) = q_chats.get_single_mut() {
evwriter_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click)); // Advance the chat.
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
chat.timer = time.elapsed_seconds_f64(); chat.timer = time.elapsed_seconds_f64();
chat.position = choice.goto.clone(); chat.position = choice.goto.clone();
chat.message_open = false;
} }
break 'outer; break 'outer;
} }
@ -828,13 +876,6 @@ fn handle_reply_keys(
} }
selected_choice += 1; selected_choice += 1;
} }
if keyboard_input.just_pressed(settings.key_next_chat_line) {
if let Ok(mut chat) = q_chats.get_single_mut() {
evwriter_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
chat.timer = 0.0;
}
}
} }
pub fn handle_chat_scripts( pub fn handle_chat_scripts(
@ -987,7 +1028,11 @@ pub fn update_chat_variables(
vars.set_in_scope( vars.set_in_scope(
"$", "$",
"ar", "ar",
if settings.hud_active { String::from("1") } else { String::from("0") } if settings.hud_active {
String::from("1")
} else {
String::from("0")
},
); );
let wears_chefhat = if let Some(ava) = hud::PLAYER_AR_AVATARS.get(settings.ar_avatar) { let wears_chefhat = if let Some(ava) = hud::PLAYER_AR_AVATARS.get(settings.ar_avatar) {
match ava.0 { match ava.0 {

View file

@ -470,8 +470,8 @@
- You age slower, can fly further, time dilation from special relativity. - You age slower, can fly further, time dilation from special relativity.
- label: skiprelativityintro - label: skiprelativityintro
- Given the right speed, you age so slowly that you can literally go anywhere you want. - Given the right speed, you age so slowly that you can literally go anywhere you want.
- Any *time* you want.
- set: timetravel - set: timetravel
- Any *time* you want.
- Time travel! Only into the future though, of course.: - Time travel! Only into the future though, of course.:
- Exactly. - Exactly.
- goto: continuemonologue - goto: continuemonologue

View file

@ -7,7 +7,6 @@ C: Camera
T: Cruise control T: Cruise control
R: Rotate (hold + move mouse) R: Rotate (hold + move mouse)
Y: Rotation stabilizer Y: Rotation stabilizer
`: Fast forward conversation
AWSD/Shift/Ctrl: Move AWSD/Shift/Ctrl: Move
J/K/U/L/I/O: Rotate J/K/U/L/I/O: Rotate
F11: Fullscreen F11: Fullscreen

View file

@ -213,6 +213,7 @@ pub enum Avatar {
Armor, Armor,
} }
#[derive(Clone)]
pub enum LogLevel { pub enum LogLevel {
Achievement, Achievement,
Always, Always,
@ -224,7 +225,18 @@ pub enum LogLevel {
//Ping, //Ping,
} }
struct Message { impl LogLevel {
pub fn is_subtitle(&self) -> bool {
match self {
LogLevel::Chat => true,
LogLevel::Info => true,
_ => false,
}
}
}
#[derive(Clone)]
pub struct Message {
text: String, text: String,
sender: String, sender: String,
level: LogLevel, level: LogLevel,
@ -310,6 +322,20 @@ impl Log {
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.logs.clear(); self.logs.clear();
} }
pub fn get_subtitle_line(&self) -> Option<Message> {
let messages: Vec<&Message> = self
.logs
.iter()
.filter(|msg: &&Message| msg.level.is_subtitle())
.rev()
.take(1)
.collect();
if messages.len() > 0 {
return Some(messages[0].clone());
}
return None;
}
} }
pub fn setup( pub fn setup(
@ -1016,19 +1042,8 @@ fn update_hud(
// Display the last chat line as "subtitles" // Display the last chat line as "subtitles"
if !q_chat.is_empty() { if !q_chat.is_empty() {
let messages: Vec<&Message> = log if let Some(message) = log.get_subtitle_line() {
.logs node_currentline.sections[0].value = message.format();
.iter()
.filter(|msg: &&Message| match msg.level {
LogLevel::Chat => true,
LogLevel::Info => true,
_ => false,
})
.rev()
.take(1)
.collect();
if messages.len() > 0 {
node_currentline.sections[0].value = messages[0].format();
} else { } else {
node_currentline.sections[0].value = "".to_string(); node_currentline.sections[0].value = "".to_string();
} }

View file

@ -143,7 +143,6 @@ pub struct Settings {
pub key_reply8: KeyCode, pub key_reply8: KeyCode,
pub key_reply9: KeyCode, pub key_reply9: KeyCode,
pub key_reply10: KeyCode, pub key_reply10: KeyCode,
pub key_next_chat_line: KeyCode,
pub key_cheat_god_mode: KeyCode, pub key_cheat_god_mode: KeyCode,
pub key_cheat_stop: KeyCode, pub key_cheat_stop: KeyCode,
pub key_cheat_speed: KeyCode, pub key_cheat_speed: KeyCode,
@ -286,7 +285,6 @@ impl Default for Settings {
key_reply8: KeyCode::Digit8, key_reply8: KeyCode::Digit8,
key_reply9: KeyCode::Digit9, key_reply9: KeyCode::Digit9,
key_reply10: KeyCode::Digit0, key_reply10: KeyCode::Digit0,
key_next_chat_line: KeyCode::Backquote,
key_cheat_god_mode: KeyCode::KeyG, key_cheat_god_mode: KeyCode::KeyG,
key_cheat_stop: KeyCode::KeyZ, key_cheat_stop: KeyCode::KeyZ,
key_cheat_speed: KeyCode::KeyV, key_cheat_speed: KeyCode::KeyV,