Compare commits
7 commits
242e06ebf1
...
678979db7e
Author | SHA1 | Date | |
---|---|---|---|
yuni | 678979db7e | ||
yuni | 9ea706c48e | ||
yuni | 52d962a6bb | ||
yuni | c787e7caf4 | ||
yuni | b9708f7839 | ||
yuni | 758114e3a2 | ||
yuni | 55426ba0dd |
|
@ -1,5 +1,7 @@
|
||||||
# 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
|
||||||
|
|
62
src/chat.rs
62
src/chat.rs
|
@ -21,10 +21,13 @@ 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";
|
||||||
|
@ -890,11 +893,13 @@ 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
|
||||||
|
@ -1002,6 +1007,33 @@ 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(¶m1) {
|
||||||
|
let param1_string = param1.to_string();
|
||||||
|
if !prefs.contacts.contains(¶m1_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}");
|
||||||
}
|
}
|
||||||
|
@ -1012,6 +1044,7 @@ 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() {
|
||||||
|
@ -1025,15 +1058,7 @@ 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(
|
vars.set_in_scope("$", "ar", bool2chatvar(settings.hud_active));
|
||||||
"$",
|
|
||||||
"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,
|
||||||
|
@ -1043,5 +1068,24 @@ 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,10 @@
|
||||||
- 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.:
|
||||||
|
|
55
src/chats/phone.yaml
Normal file
55
src/chats/phone.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
- 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
|
|
@ -18,6 +18,7 @@ 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";
|
||||||
|
@ -901,9 +902,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() {
|
||||||
"jupiter" => Some(nature::JUPITER_MASS),
|
ID_JUPITER => Some(nature::JUPITER_MASS),
|
||||||
"earth" => Some(nature::EARTH_MASS),
|
ID_EARTH => Some(nature::EARTH_MASS),
|
||||||
"sol" => Some(nature::SOL_MASS),
|
ID_SOL => Some(nature::SOL_MASS),
|
||||||
_ => {
|
_ => {
|
||||||
error!("Found no mass for object `{id}`");
|
error!("Found no mass for object `{id}`");
|
||||||
continue;
|
continue;
|
||||||
|
|
21
src/game.rs
21
src/game.rs
|
@ -98,6 +98,7 @@ pub enum GameEvent {
|
||||||
SetShadows(Turn),
|
SetShadows(Turn),
|
||||||
UpdateFlashlight,
|
UpdateFlashlight,
|
||||||
Achievement(String),
|
Achievement(String),
|
||||||
|
PhoneCall,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Turn {
|
pub enum Turn {
|
||||||
|
@ -162,6 +163,7 @@ 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>,
|
||||||
|
@ -270,6 +272,19 @@ 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,7 +501,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 == "jupiter" {
|
if id.0 == cmd::ID_JUPITER {
|
||||||
jupiterpos.0 = pos.0;
|
jupiterpos.0 = pos.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -594,12 +609,12 @@ fn check_achievements(
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let pos_sun = if let Some(pos) = id2pos.0.get("sol") {
|
let pos_sun = if let Some(pos) = id2pos.0.get(cmd::ID_SOL) {
|
||||||
pos
|
pos
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let pos_jupiter = if let Some(pos) = id2pos.0.get("jupiter") {
|
let pos_jupiter = if let Some(pos) = id2pos.0.get(cmd::ID_JUPITER) {
|
||||||
pos
|
pos
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
|
42
src/menu.rs
42
src/menu.rs
|
@ -49,6 +49,8 @@ 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;
|
||||||
|
@ -63,6 +65,7 @@ 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),
|
||||||
|
@ -92,6 +95,7 @@ pub enum MenuAction {
|
||||||
ModReactor,
|
ModReactor,
|
||||||
ToggleSound,
|
ToggleSound,
|
||||||
ToggleMusic,
|
ToggleMusic,
|
||||||
|
PhoneCall,
|
||||||
ToggleCamera,
|
ToggleCamera,
|
||||||
ToggleFullscreen,
|
ToggleFullscreen,
|
||||||
ToggleShadows,
|
ToggleShadows,
|
||||||
|
@ -347,7 +351,9 @@ pub fn setup(
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.with_children(|builder| {
|
.with_children(|builder| {
|
||||||
builder.spawn((TextBundle {
|
builder.spawn((
|
||||||
|
FooterElement,
|
||||||
|
TextBundle {
|
||||||
text: Text {
|
text: Text {
|
||||||
sections: vec![TextSection::new(
|
sections: vec![TextSection::new(
|
||||||
format!("{} {}", GAME_NAME, settings.version.as_str()),
|
format!("{} {}", GAME_NAME, settings.version.as_str()),
|
||||||
|
@ -357,7 +363,8 @@ pub fn setup(
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
},));
|
},
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,8 +440,17 @@ 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_achievement_text: Query<&mut Text, (With<MenuAchievements>, Without<MenuTopLevel>)>,
|
mut q_footer: Query<&mut Text, (With<FooterElement>, 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>,
|
||||||
|
@ -449,6 +465,21 @@ 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] {
|
||||||
|
@ -713,6 +744,11 @@ 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));
|
||||||
|
|
|
@ -242,3 +242,26 @@ 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);
|
||||||
|
}
|
||||||
|
|
|
@ -477,6 +477,7 @@ 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>,
|
||||||
|
|
Loading…
Reference in a new issue