Compare commits

..

No commits in common. "678979db7e0ae2eebadf0165c4e3657f21b17a83" and "242e06ebf1dba274d11d36f47678818d45da124f" have entirely different histories.

9 changed files with 25 additions and 206 deletions

View file

@ -1,7 +1,5 @@
# v0.14.0-dev # v0.14.0-dev
- Implement fast travel (must be unlocked by getting phone number of FASTravel)
- Implement phone calls
- Chats don't automatically advance now, the player has to press "Continue" - Chats don't automatically advance now, the player has to press "Continue"
- Add sparkles to Jupiter's ring ✨😍✨ best visible from Farview Station - Add sparkles to Jupiter's ring ✨😍✨ best visible from Farview Station
- Add setting to change pointer - Add setting to change pointer

View file

@ -21,13 +21,10 @@ use std::collections::HashMap;
pub const CHATS: &[&str] = &[ pub const CHATS: &[&str] = &[
include_str!("chats/fastravel.yaml"), include_str!("chats/fastravel.yaml"),
include_str!("chats/phone.yaml"),
include_str!("chats/serenity.yaml"), include_str!("chats/serenity.yaml"),
include_str!("chats/thebe.yaml"), include_str!("chats/thebe.yaml"),
]; ];
pub const CONTACTS: &[&str] = &["icarus", "travel", "luna", "nox"];
pub const TEXT_CONTINUE: &str = "Continue..."; pub const TEXT_CONTINUE: &str = "Continue...";
pub const TOKEN_CHAT: &str = "chat"; pub const TOKEN_CHAT: &str = "chat";
@ -893,13 +890,11 @@ pub fn handle_chat_scripts(
With<actor::Player>, With<actor::Player>,
>, >,
mut q_playercam: Query<(&mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>, mut q_playercam: Query<(&mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
mut q_chats: Query<&mut Chat>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>, mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
mut ew_effect: EventWriter<visual::SpawnEffectEvent>, mut ew_effect: EventWriter<visual::SpawnEffectEvent>,
mut ew_achievement: EventWriter<game::AchievementEvent>, mut ew_achievement: EventWriter<game::AchievementEvent>,
id2pos: Res<game::Id2Pos>, id2pos: Res<game::Id2Pos>,
id2v: Res<game::Id2V>, id2v: Res<game::Id2V>,
mut prefs: ResMut<Preferences>,
) { ) {
for script in er_chatscript.read() { for script in er_chatscript.read() {
// Parse the script string // Parse the script string
@ -1007,33 +1002,6 @@ pub fn handle_chat_scripts(
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Drink)); ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Drink));
ew_achievement.send(game::AchievementEvent::DrinkPizza); ew_achievement.send(game::AchievementEvent::DrinkPizza);
} }
"changename" => {
let mut new_name = param1.to_string();
if !param2.is_empty() {
if !new_name.is_empty() {
new_name += " ";
}
new_name += param2;
}
for mut chat in &mut q_chats {
if new_name.is_empty() {
chat.talker.name = None;
} else {
chat.talker.name = Some(new_name.clone());
}
}
}
"registercontact" => {
if CONTACTS.contains(&param1) {
let param1_string = param1.to_string();
if !prefs.contacts.contains(&param1_string) {
prefs.contacts.push(param1_string);
prefs.save();
}
} else {
error!("Can't register contact `{param1}', it doesn't exist in the chat::CONTACTS constant.");
}
}
_ => { _ => {
error!("Error, undefined chat script {name}"); error!("Error, undefined chat script {name}");
} }
@ -1044,7 +1012,6 @@ pub fn handle_chat_scripts(
pub fn update_chat_variables( pub fn update_chat_variables(
mut vars: ResMut<var::GameVars>, mut vars: ResMut<var::GameVars>,
settings: Res<var::Settings>, settings: Res<var::Settings>,
prefs: Res<var::Preferences>,
q_player: Query<&actor::Suit, With<actor::Player>>, q_player: Query<&actor::Suit, With<actor::Player>>,
) { ) {
if let Ok(suit) = q_player.get_single() { if let Ok(suit) = q_player.get_single() {
@ -1058,7 +1025,15 @@ pub fn update_chat_variables(
"player_suit_health_percent", "player_suit_health_percent",
((suit.integrity * 100.0).round() as u8).to_string(), ((suit.integrity * 100.0).round() as u8).to_string(),
); );
vars.set_in_scope("$", "ar", bool2chatvar(settings.hud_active)); vars.set_in_scope(
"$",
"ar",
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 {
hud::Avatar::ChefHat => 1, hud::Avatar::ChefHat => 1,
@ -1068,24 +1043,5 @@ pub fn update_chat_variables(
0 0
}; };
vars.set_in_scope("$", "chefhat", wears_chefhat.to_string()); vars.set_in_scope("$", "chefhat", wears_chefhat.to_string());
// Set phone variables
let mut any = false;
for contact in CONTACTS {
let value = prefs.contacts.contains(&contact.to_string());
if value {
any = true;
}
vars.set_in_scope("phone", contact, bool2chatvar(value));
}
vars.set_in_scope("phone", "any", bool2chatvar(any));
}
}
fn bool2chatvar(var: bool) -> String {
if var {
String::from("1")
} else {
String::from("0")
} }
} }

View file

@ -96,10 +96,6 @@
- Can you please fill up my oxygen tank without taking me anywhere?: - Can you please fill up my oxygen tank without taking me anywhere?:
- script: refilloxygen 1000 - script: refilloxygen 1000
- Of course, you can count on FASTravel! - Of course, you can count on FASTravel!
- I wish I could use your services from anywhere!:
- Actually, you can!
- script: registercontact travel
- Here's our phone number, call us any time!
- Is there anything interesting to do around here?: - Is there anything interesting to do around here?:
- goto: interesting - goto: interesting
- No, thank you.: - No, thank you.:

View file

@ -1,55 +0,0 @@
- chat: phone
- if ~phone$any:
- "Error: Phonebook empty."
- goto: EXIT
- Select contact to call.
- if: phone$travel
FASTravel:
- goto: travel
- "[Cancel]":
- goto: EXIT
- label: travel
- script: changename FASTravel
- Welcome to FASTravel™, how can I help you today?
- label: travel_mainnode
- Can you pick me up please?:
- Yes! Where should we drop you off?
- Serenity Station:
- Ok! Activate cryofreeze and we'll be right there.
- "[Activate Cryofreeze]":
- script: cryofadeout
- sleep: 5
- script: cryotrip serenity
- goto: EXIT
- I changed my mind.:
- Alright. Anything else I can help you with?
- goto: travel_mainnode
- Metis Prime Station:
- Ok! Activate cryofreeze and we'll be right there.
- "[Activate Cryofreeze]":
- script: cryofadeout
- sleep: 5
- script: cryotrip metisprime
- goto: EXIT
- I changed my mind.:
- Alright. Anything else I can help you with?
- goto: travel_mainnode
- Farview Station:
- Ok! Activate cryofreeze and we'll be right there.
- "[Activate Cryofreeze]":
- script: cryofadeout
- sleep: 5
- script: cryotrip farview
- goto: EXIT
- I changed my mind.:
- Alright. Anything else I can help you with?
- goto: travel_mainnode
- I just wanted to say that you're awesome!:
- Thank you so much!
- Hearing this makes my day!
- Satisfying our customers is what I'm programmed to live for.
- Good bye!:
- goto: EXIT
- "[Hang up]":
- goto: EXIT

View file

@ -18,7 +18,6 @@ use bevy_xpbd_3d::prelude::*;
use regex::Regex; use regex::Regex;
pub const ID_SPECIAL_PLAYERCAM: &str = "PLAYERCAMERA"; pub const ID_SPECIAL_PLAYERCAM: &str = "PLAYERCAMERA";
pub const ID_PLAYER: &str = "player";
pub const ID_EARTH: &str = "earth"; pub const ID_EARTH: &str = "earth";
pub const ID_SOL: &str = "sol"; pub const ID_SOL: &str = "sol";
pub const ID_JUPITER: &str = "jupiter"; pub const ID_JUPITER: &str = "jupiter";
@ -902,9 +901,9 @@ fn spawn_entities(
let orbited_mass: Option<f64> = if let Some(id) = &state.orbit_object_id { let orbited_mass: Option<f64> = if let Some(id) = &state.orbit_object_id {
match id.as_str() { match id.as_str() {
ID_JUPITER => Some(nature::JUPITER_MASS), "jupiter" => Some(nature::JUPITER_MASS),
ID_EARTH => Some(nature::EARTH_MASS), "earth" => Some(nature::EARTH_MASS),
ID_SOL => Some(nature::SOL_MASS), "sol" => Some(nature::SOL_MASS),
_ => { _ => {
error!("Found no mass for object `{id}`"); error!("Found no mass for object `{id}`");
continue; continue;

View file

@ -98,7 +98,6 @@ pub enum GameEvent {
SetShadows(Turn), SetShadows(Turn),
UpdateFlashlight, UpdateFlashlight,
Achievement(String), Achievement(String),
PhoneCall,
} }
pub enum Turn { pub enum Turn {
@ -163,7 +162,6 @@ pub fn setup(mut settings: ResMut<Settings>, prefs: ResMut<var::Preferences>) {
pub fn handle_game_event( pub fn handle_game_event(
mut settings: ResMut<Settings>, mut settings: ResMut<Settings>,
mut er_game: EventReader<GameEvent>, mut er_game: EventReader<GameEvent>,
mut ew_conv: EventWriter<chat::StartConversationEvent>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>, mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
mut ew_updateoverlays: EventWriter<hud::UpdateOverlayVisibility>, mut ew_updateoverlays: EventWriter<hud::UpdateOverlayVisibility>,
mut ew_updatemenu: EventWriter<menu::UpdateMenuEvent>, mut ew_updatemenu: EventWriter<menu::UpdateMenuEvent>,
@ -272,19 +270,6 @@ pub fn handle_game_event(
spotlight.intensity = actor::FLASHLIGHT_INTENSITY[prefs.flashlight_power]; spotlight.intensity = actor::FLASHLIGHT_INTENSITY[prefs.flashlight_power];
} }
} }
GameEvent::PhoneCall => {
let talker = chat::Talker {
chat_name: "phone".to_string(),
actor_id: "".to_string(),
name: Some("Phone".to_string()),
counts_towards_achievement: false,
pronoun: None,
talking_speed: 0.0,
};
ew_conv.send(chat::StartConversationEvent {
talker: talker,
});
}
} }
} }
} }
@ -501,7 +486,7 @@ fn update_id2pos(
id2pos.0.clear(); id2pos.0.clear();
for (pos, id) in &q_id { for (pos, id) in &q_id {
id2pos.0.insert(id.0.clone(), pos.0); id2pos.0.insert(id.0.clone(), pos.0);
if id.0 == cmd::ID_JUPITER { if id.0 == "jupiter" {
jupiterpos.0 = pos.0; jupiterpos.0 = pos.0;
} }
} }
@ -609,12 +594,12 @@ fn check_achievements(
} else { } else {
return; return;
}; };
let pos_sun = if let Some(pos) = id2pos.0.get(cmd::ID_SOL) { let pos_sun = if let Some(pos) = id2pos.0.get("sol") {
pos pos
} else { } else {
return; return;
}; };
let pos_jupiter = if let Some(pos) = id2pos.0.get(cmd::ID_JUPITER) { let pos_jupiter = if let Some(pos) = id2pos.0.get("jupiter") {
pos pos
} else { } else {
return; return;

View file

@ -49,8 +49,6 @@ pub struct MenuElement;
#[derive(Component)] #[derive(Component)]
pub struct MenuTopLevel; pub struct MenuTopLevel;
#[derive(Component)] #[derive(Component)]
pub struct FooterElement;
#[derive(Component)]
pub struct MenuAchievements; pub struct MenuAchievements;
#[derive(Component)] #[derive(Component)]
pub struct DeathScreenElement; pub struct DeathScreenElement;
@ -65,7 +63,6 @@ pub enum DeathScreenEvent {
} }
pub const MENUDEF: &[(&str, MenuAction)] = &[ pub const MENUDEF: &[(&str, MenuAction)] = &[
("Phone Call", MenuAction::PhoneCall),
("", MenuAction::ToggleAR), ("", MenuAction::ToggleAR),
("", MenuAction::ChangeARAvatar), ("", MenuAction::ChangeARAvatar),
("", MenuAction::ChangePointer), ("", MenuAction::ChangePointer),
@ -95,7 +92,6 @@ pub enum MenuAction {
ModReactor, ModReactor,
ToggleSound, ToggleSound,
ToggleMusic, ToggleMusic,
PhoneCall,
ToggleCamera, ToggleCamera,
ToggleFullscreen, ToggleFullscreen,
ToggleShadows, ToggleShadows,
@ -351,20 +347,17 @@ pub fn setup(
}, },
)) ))
.with_children(|builder| { .with_children(|builder| {
builder.spawn(( builder.spawn((TextBundle {
FooterElement, text: Text {
TextBundle { sections: vec![TextSection::new(
text: Text { format!("{} {}", GAME_NAME, settings.version.as_str()),
sections: vec![TextSection::new( style_version,
format!("{} {}", GAME_NAME, settings.version.as_str()), )],
style_version, justify: JustifyText::Right,
)],
justify: JustifyText::Right,
..default()
},
..default() ..default()
}, },
)); ..default()
},));
}); });
} }
@ -440,17 +433,8 @@ pub struct MenuState {
pub fn update_menu( pub fn update_menu(
mut q_text: Query<&mut Text, With<MenuTopLevel>>, mut q_text: Query<&mut Text, With<MenuTopLevel>>,
mut q_footer: Query<&mut Text, (With<FooterElement>, Without<MenuTopLevel>)>, mut q_achievement_text: Query<&mut Text, (With<MenuAchievements>, Without<MenuTopLevel>)>,
mut q_achievement_text: Query<
&mut Text,
(
With<MenuAchievements>,
Without<MenuTopLevel>,
Without<FooterElement>,
),
>,
mut q_vis: Query<&mut Visibility, With<menu::MenuElement>>, mut q_vis: Query<&mut Visibility, With<menu::MenuElement>>,
id2pos: Res<game::Id2Pos>,
achievement_tracker: Res<var::AchievementTracker>, achievement_tracker: Res<var::AchievementTracker>,
menustate: Res<MenuState>, menustate: Res<MenuState>,
settings: Res<Settings>, settings: Res<Settings>,
@ -465,21 +449,6 @@ pub fn update_menu(
let bools = achievement_tracker.to_bool_vec(); let bools = achievement_tracker.to_bool_vec();
let rendered = achievement_tracker.to_textsections(); let rendered = achievement_tracker.to_textsections();
if let (Ok(mut text), Some(player_pos), Some(jupiter_pos)) = (
q_footer.get_single_mut(),
id2pos.0.get(cmd::ID_PLAYER),
id2pos.0.get(cmd::ID_JUPITER),
) {
let (clock_max, clock_current) =
nature::pos_to_orbit_time(*player_pos, *jupiter_pos, nature::JUPITER_MASS);
text.sections[0].value = format!(
"Orbital Clock:\n{} of {}\n{} {}",
nature::format_seconds_to_hour_min(clock_current),
nature::format_seconds_to_hour_min(clock_max),
GAME_NAME,
settings.version.as_str()
);
}
if let Ok(mut text) = q_achievement_text.get_single_mut() { if let Ok(mut text) = q_achievement_text.get_single_mut() {
for i in 0..text.sections.len() - 1 { for i in 0..text.sections.len() - 1 {
text.sections[i + 1].style.color = if bools[i] { text.sections[i + 1].style.color = if bools[i] {
@ -744,11 +713,6 @@ pub fn handle_input(
ew_game.send(GameEvent::SetShadows(Toggle)); ew_game.send(GameEvent::SetShadows(Toggle));
ew_updatemenu.send(UpdateMenuEvent); ew_updatemenu.send(UpdateMenuEvent);
} }
MenuAction::PhoneCall => {
ew_game.send(GameEvent::PhoneCall);
ew_game.send(GameEvent::SetMenu(Turn::Off));
ew_updatemenu.send(UpdateMenuEvent);
}
MenuAction::Restart => { MenuAction::Restart => {
settings.god_mode = false; settings.god_mode = false;
ew_playerdies.send(game::PlayerDiesEvent(actor::DamageType::Depressurization)); ew_playerdies.send(game::PlayerDiesEvent(actor::DamageType::Depressurization));

View file

@ -242,26 +242,3 @@ pub fn rotation_for_orbiting_body(orbit_distance: f64, mass: f64) -> f64 {
0.0 0.0
} }
} }
/// Assumes a circular 2D orbit in the invariable plane of the solar system
/// Returns (seconds for a single orbit, current seconds of orbit)
pub fn pos_to_orbit_time(pos: DVec3, orbited_pos: DVec3, orbited_mass: f64) -> (f64, f64) {
let rel_x = pos.x - orbited_pos.x;
let rel_z = pos.z - orbited_pos.z;
let orbit_distance = (rel_x * rel_x + rel_z * rel_z).sqrt();
// get total orbit seconds
let period = simple_orbital_period(orbited_mass, orbit_distance);
// get current orbital phase
let angle_radians = (rel_z).atan2(-rel_x);
let mut fraction = angle_radians / (PI * 2.0);
if fraction < 0.0 {
fraction += 1.0;
}
return (period, period * fraction);
}
pub fn format_seconds_to_hour_min(seconds: f64) -> String {
return format!("{:02.0}:{:02.0}", seconds / 3600.0, (seconds % 3600.0) / 60.0);
}

View file

@ -477,7 +477,6 @@ pub struct Preferences {
#[serde(default = "Preferences::default_flashlight_power")] #[serde(default = "Preferences::default_flashlight_power")]
pub flashlight_power: usize, // 0-2 pub flashlight_power: usize, // 0-2
pub thruster_boost: usize, // 0-2 pub thruster_boost: usize, // 0-2
pub contacts: Vec<String>,
#[serde(skip)] #[serde(skip)]
pub source_file: Option<String>, pub source_file: Option<String>,