Compare commits
6 commits
ca5ebf22d5
...
ae3e9c9b48
Author | SHA1 | Date | |
---|---|---|---|
yuni | ae3e9c9b48 | ||
yuni | b5e969f0f7 | ||
yuni | ebe028d567 | ||
yuni | c48e5cdb3a | ||
yuni | 93293092ce | ||
yuni | aaa5266478 |
|
@ -1,3 +1,9 @@
|
||||||
|
# v0.12.0-dev
|
||||||
|
|
||||||
|
- Add power-hungry optional thruster boost
|
||||||
|
- Add different flashlight power settings
|
||||||
|
- Add different light amplification settings
|
||||||
|
|
||||||
# v0.11.1
|
# v0.11.1
|
||||||
|
|
||||||
- Added space suit thruster particle effects
|
- Added space suit thruster particle effects
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
- achieve.ogg: [UI Completed Status Alert Notification by Headphaze, CC BY 4.0](https://freesound.org/s/277033/)
|
- achieve.ogg: [UI Completed Status Alert Notification by Headphaze, CC BY 4.0](https://freesound.org/s/277033/)
|
||||||
- drink.ogg: [Pouring Beer into Short Glass by megashroom, CC0](https://freesound.org/s/390336/)
|
- drink.ogg: [Pouring Beer into Short Glass by megashroom, CC0](https://freesound.org/s/390336/)
|
||||||
- enter.ogg, exit.ogg: [Getting Out of Car.wav by kingsrow, CC0](https://freesound.org/s/181568/)
|
- enter.ogg, exit.ogg: [Getting Out of Car.wav by kingsrow, CC0](https://freesound.org/s/181568/)
|
||||||
|
- powerdown.ogg: [Energy Drain by qubodup, CC0](https://freesound.org/people/qubodup/sounds/742835/)
|
||||||
|
- spark.ogg: [Socket Connect Disconnect by JustHallowed, CC BY 4.0](https://freesound.org/people/JustHallowed/sounds/691007/), Tempo -40, Amplify 4
|
||||||
- Takeoff.ogg: [By Serat, CC BY 4.0](https://freemusicarchive.org/music/serat/route-remastered/takeoff-remastered/)
|
- Takeoff.ogg: [By Serat, CC BY 4.0](https://freemusicarchive.org/music/serat/route-remastered/takeoff-remastered/)
|
||||||
- JupiterRecording.ogg: An [actual Jupiter recording by NASA](https://archive.org/download/voyager-1-and-2-1990-jupiter-nasa-voyager-space-sounds-electronic), public domain.
|
- JupiterRecording.ogg: An [actual Jupiter recording by NASA](https://archive.org/download/voyager-1-and-2-1990-jupiter-nasa-voyager-space-sounds-electronic), public domain.
|
||||||
- Processed by cutting out min 1:47-3:47 and applying a 10s linear crossfade at the end. Exported as ogg with quality=3, see [.kdenlive file](src/audio/JupiterRecording.kdenlive).
|
- Processed by cutting out min 1:47-3:47 and applying a 10s linear crossfade at the end. Exported as ogg with quality=3, see [.kdenlive file](src/audio/JupiterRecording.kdenlive).
|
||||||
|
|
|
@ -35,7 +35,7 @@ The `SPACE` key helps you move more intuitively by slowing you down. Hold it fo
|
||||||
|
|
||||||
When you're ready, take a look around, explore the starting area. There is a friendly person floating nearby in a red space suit that would love to talk to you.
|
When you're ready, take a look around, explore the starting area. There is a friendly person floating nearby in a red space suit that would love to talk to you.
|
||||||
|
|
||||||
The game is dark. After all, space is dark. The planets and moons orbit in real time, the map changes depending on when you play, and if you're unlucky, you start in the shadow of Jupiter and everything's even darker! Try the flashlight (`f` key), turning off shadows in the menu, and make sure that Augmented Reality is on (`TAB` key) which gives you a little extra light amplification.
|
The game is dark. After all, space is dark. The planets and moons orbit in real time, the map changes depending on when you play, and if you're unlucky, you start in the shadow of Jupiter and everything's even darker! Try the flashlight (`f` key), or stronger light amplification (menu), which requires Augmented Reality to be active (`TAB` key).
|
||||||
|
|
||||||
Press `Esc` for the menu to restart the game if you get lost, explore more key bindings, game features, and the **achievements** to get some guidance on what you can do in the game.
|
Press `Esc` for the menu to restart the game if you get lost, explore more key bindings, game features, and the **achievements** to get some guidance on what you can do in the game.
|
||||||
|
|
||||||
|
|
BIN
assets/sounds/powerdown.ogg
Normal file
BIN
assets/sounds/powerdown.ogg
Normal file
Binary file not shown.
BIN
assets/sounds/spark.ogg
Normal file
BIN
assets/sounds/spark.ogg
Normal file
Binary file not shown.
BIN
assets/sprites/dashboard_battery.png
Normal file
BIN
assets/sprites/dashboard_battery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -110,6 +110,16 @@ A variety of relatively simple game systems should interact with each other to c
|
||||||
- can we make it non-modal? Interweave it into regular gameplay?
|
- can we make it non-modal? Interweave it into regular gameplay?
|
||||||
- G-forces and equipment/organ damage
|
- G-forces and equipment/organ damage
|
||||||
- Death, and survival
|
- Death, and survival
|
||||||
|
- Spacesuit energy distribution into:
|
||||||
|
- [X] Residual Light Amplification
|
||||||
|
- [X] Augmented Reality
|
||||||
|
- [X] Flashlight intensity
|
||||||
|
- [ ] AI assistance systems
|
||||||
|
- [ ] Thruster boost
|
||||||
|
- [ ] G-force dampeners
|
||||||
|
- [ ] Life support, material recyclers (air, water, etc)
|
||||||
|
- [ ] High energy particle shield?
|
||||||
|
- [ ] Micrometeorite shield?
|
||||||
|
|
||||||
# Quest Ideas
|
# Quest Ideas
|
||||||
|
|
||||||
|
@ -150,6 +160,7 @@ A variety of relatively simple game systems should interact with each other to c
|
||||||
- Nethack
|
- Nethack
|
||||||
- Planescape: Torment
|
- Planescape: Torment
|
||||||
- Prey (2017 game)
|
- Prey (2017 game)
|
||||||
|
- Primer (2004 film)
|
||||||
- Project Hail Mary
|
- Project Hail Mary
|
||||||
- RimWorld
|
- RimWorld
|
||||||
- Risk of Rain
|
- Risk of Rain
|
||||||
|
@ -157,6 +168,7 @@ A variety of relatively simple game systems should interact with each other to c
|
||||||
- Shadowrun Returns: Dragonfall, Hong Kong
|
- Shadowrun Returns: Dragonfall, Hong Kong
|
||||||
- Stardew Valley
|
- Stardew Valley
|
||||||
- Stray (2022 game)
|
- Stray (2022 game)
|
||||||
|
- Synthwave (music genre)
|
||||||
- System Shock 2
|
- System Shock 2
|
||||||
- The Expanse
|
- The Expanse
|
||||||
- The Forgotten City
|
- The Forgotten City
|
||||||
|
|
62
src/actor.rs
62
src/actor.rs
|
@ -21,6 +21,10 @@ use bevy_xpbd_3d::prelude::*;
|
||||||
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
||||||
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
|
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
|
||||||
const MAX_INTERACT_DISTANCE: f32 = 50.0;
|
const MAX_INTERACT_DISTANCE: f32 = 50.0;
|
||||||
|
const POWER_DRAIN_THRUSTER: [f32; 3] = [3e6, 3e6, 0.0];
|
||||||
|
const THRUSTER_BOOST_FACTOR: [f64; 3] = [3.0, 3.0, 0.0];
|
||||||
|
const POWER_DRAIN_FLASHLIGHT: [f32; 3] = [200e3, 1500e3, 2500e3];
|
||||||
|
pub const FLASHLIGHT_INTENSITY: [f32; 3] = [10e6, 400e6, 2e9]; // in lumens
|
||||||
|
|
||||||
pub struct ActorPlugin;
|
pub struct ActorPlugin;
|
||||||
impl Plugin for ActorPlugin {
|
impl Plugin for ActorPlugin {
|
||||||
|
@ -210,6 +214,9 @@ pub struct Engine {
|
||||||
pub engine_type: EngineType,
|
pub engine_type: EngineType,
|
||||||
pub warmup_seconds: f32,
|
pub warmup_seconds: f32,
|
||||||
pub current_warmup: f32, // between 0.0 and 1.0
|
pub current_warmup: f32, // between 0.0 and 1.0
|
||||||
|
pub current_boost_factor: f64,
|
||||||
|
pub currently_firing: bool,
|
||||||
|
pub currently_matching_velocity: bool,
|
||||||
}
|
}
|
||||||
impl Default for Engine {
|
impl Default for Engine {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -221,6 +228,9 @@ impl Default for Engine {
|
||||||
engine_type: EngineType::Monopropellant,
|
engine_type: EngineType::Monopropellant,
|
||||||
warmup_seconds: 1.5,
|
warmup_seconds: 1.5,
|
||||||
current_warmup: 0.0,
|
current_warmup: 0.0,
|
||||||
|
current_boost_factor: 1.0,
|
||||||
|
currently_firing: false,
|
||||||
|
currently_matching_velocity: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +258,7 @@ pub struct Battery {
|
||||||
pub power: f32, // Watt-seconds
|
pub power: f32, // Watt-seconds
|
||||||
pub capacity: f32, // Watt-seconds
|
pub capacity: f32, // Watt-seconds
|
||||||
pub reactor: f32, // Watt (production)
|
pub reactor: f32, // Watt (production)
|
||||||
|
pub overloaded_recovering: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Battery {
|
impl Default for Battery {
|
||||||
|
@ -256,6 +267,7 @@ impl Default for Battery {
|
||||||
power: 10e3 * 3600.0,
|
power: 10e3 * 3600.0,
|
||||||
capacity: 10e3 * 3600.0, // 10kWh
|
capacity: 10e3 * 3600.0, // 10kWh
|
||||||
reactor: 2000e3, // 2MW
|
reactor: 2000e3, // 2MW
|
||||||
|
overloaded_recovering: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,23 +275,63 @@ impl Default for Battery {
|
||||||
pub fn update_power(
|
pub fn update_power(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut settings: ResMut<Settings>,
|
mut settings: ResMut<Settings>,
|
||||||
mut q_battery: Query<(&mut Battery, Option<&Player>)>,
|
prefs: Res<Preferences>,
|
||||||
|
mut q_battery: Query<(&mut Battery, &mut Engine), With<Player>>,
|
||||||
mut q_flashlight: Query<&mut Visibility, With<PlayersFlashLight>>,
|
mut q_flashlight: Query<&mut Visibility, With<PlayersFlashLight>>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
|
mut ew_game: EventWriter<game::GameEvent>,
|
||||||
) {
|
) {
|
||||||
|
let mut power_down = false;
|
||||||
let d = time.delta_seconds();
|
let d = time.delta_seconds();
|
||||||
for (mut battery, player) in &mut q_battery {
|
for (mut battery, mut engine) in &mut q_battery {
|
||||||
if player.is_some() && settings.flashlight_active {
|
if settings.flashlight_active {
|
||||||
battery.power -= 2400000.0 * d;
|
battery.power -= POWER_DRAIN_FLASHLIGHT[prefs.flashlight_power] * d; // 2.4MW
|
||||||
if battery.power <= 0.0 {
|
if battery.power <= 0.0 {
|
||||||
|
power_down = true;
|
||||||
settings.flashlight_active = false;
|
settings.flashlight_active = false;
|
||||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
|
||||||
for mut flashlight_vis in &mut q_flashlight {
|
for mut flashlight_vis in &mut q_flashlight {
|
||||||
*flashlight_vis = Visibility::Hidden;
|
*flashlight_vis = Visibility::Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if settings.hud_active {
|
||||||
|
let mut hud_drain = 300e3; // 300kW
|
||||||
|
hud_drain += prefs.light_amp as f32 * 200e3; // 200kW per level
|
||||||
|
battery.power -= hud_drain * d;
|
||||||
|
if battery.power <= 0.0 {
|
||||||
|
power_down = true;
|
||||||
|
ew_game.send(GameEvent::SetAR(Turn::Off));
|
||||||
|
for mut flashlight_vis in &mut q_flashlight {
|
||||||
|
*flashlight_vis = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let drain = POWER_DRAIN_THRUSTER[prefs.thruster_boost];
|
||||||
|
let boosting = !battery.overloaded_recovering
|
||||||
|
&& prefs.thruster_boost != 2
|
||||||
|
&& (prefs.thruster_boost == 1 || engine.currently_matching_velocity);
|
||||||
|
if boosting {
|
||||||
|
if battery.power > drain * d * 100.0 {
|
||||||
|
engine.current_boost_factor = THRUSTER_BOOST_FACTOR[prefs.thruster_boost];
|
||||||
|
if engine.currently_firing {
|
||||||
|
battery.power -= drain * d;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
power_down = true;
|
||||||
|
battery.overloaded_recovering = true;
|
||||||
|
engine.current_boost_factor = 1.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
engine.current_boost_factor = 1.0;
|
||||||
|
}
|
||||||
|
if power_down {
|
||||||
|
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::PowerDown));
|
||||||
|
}
|
||||||
battery.power = (battery.power + battery.reactor * d).clamp(0.0, battery.capacity);
|
battery.power = (battery.power + battery.reactor * d).clamp(0.0, battery.capacity);
|
||||||
|
if battery.overloaded_recovering && battery.power > battery.capacity * 0.5 {
|
||||||
|
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::PowerUp));
|
||||||
|
battery.overloaded_recovering = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,8 @@ const PATHS: &[(SfxType, Sfx, &str)] = &[
|
||||||
"sounds/connect.ogg",
|
"sounds/connect.ogg",
|
||||||
),
|
),
|
||||||
(SfxType::OneOff, Sfx::Ping, "sounds/connect.ogg"),
|
(SfxType::OneOff, Sfx::Ping, "sounds/connect.ogg"),
|
||||||
|
(SfxType::OneOff, Sfx::PowerDown, "sounds/powerdown.ogg"),
|
||||||
|
(SfxType::OneOff, Sfx::PowerUp, "sounds/spark.ogg"),
|
||||||
(SfxType::OneOff, Sfx::Switch, "sounds/click2.ogg"),
|
(SfxType::OneOff, Sfx::Switch, "sounds/click2.ogg"),
|
||||||
(SfxType::OneOff, Sfx::Refill, "sounds/refill.ogg"),
|
(SfxType::OneOff, Sfx::Refill, "sounds/refill.ogg"),
|
||||||
(SfxType::OneOff, Sfx::WakeUp, "sounds/wakeup.ogg"),
|
(SfxType::OneOff, Sfx::WakeUp, "sounds/wakeup.ogg"),
|
||||||
|
@ -103,6 +105,8 @@ pub enum Sfx {
|
||||||
IncomingChatMessage,
|
IncomingChatMessage,
|
||||||
Ion,
|
Ion,
|
||||||
Ping,
|
Ping,
|
||||||
|
PowerDown,
|
||||||
|
PowerUp,
|
||||||
Refill,
|
Refill,
|
||||||
Switch,
|
Switch,
|
||||||
Thruster,
|
Thruster,
|
||||||
|
@ -125,6 +129,8 @@ pub fn str2sfx(sfx_label: &str) -> Sfx {
|
||||||
"zoom" => Sfx::Zoom,
|
"zoom" => Sfx::Zoom,
|
||||||
"chat" => Sfx::IncomingChatMessage,
|
"chat" => Sfx::IncomingChatMessage,
|
||||||
"ping" => Sfx::Ping,
|
"ping" => Sfx::Ping,
|
||||||
|
"powerdown" => Sfx::PowerDown,
|
||||||
|
"powerup" => Sfx::PowerUp,
|
||||||
"connect" => Sfx::Connect,
|
"connect" => Sfx::Connect,
|
||||||
"refill" => Sfx::Refill,
|
"refill" => Sfx::Refill,
|
||||||
"entervehicle" => Sfx::EnterVehicle,
|
"entervehicle" => Sfx::EnterVehicle,
|
||||||
|
|
|
@ -541,15 +541,22 @@ pub fn apply_input_to_player(
|
||||||
let right_factor = engine.thrust_sideways * engine.current_warmup;
|
let right_factor = engine.thrust_sideways * engine.current_warmup;
|
||||||
let up_factor = engine.thrust_sideways * engine.current_warmup;
|
let up_factor = engine.thrust_sideways * engine.current_warmup;
|
||||||
let factor = DVec3::new(right_factor as f64, up_factor as f64, forward_factor as f64);
|
let factor = DVec3::new(right_factor as f64, up_factor as f64, forward_factor as f64);
|
||||||
|
let boost = if bike.is_none() {
|
||||||
|
engine.current_boost_factor
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
if axis_input.length_squared() > 0.003 {
|
if axis_input.length_squared() > 0.003 {
|
||||||
|
engine.currently_firing = true;
|
||||||
let acceleration_global: DVec3 =
|
let acceleration_global: DVec3 =
|
||||||
DVec3::from(player_transform.rotation * (axis_input * factor).as_vec3());
|
DVec3::from(player_transform.rotation * (axis_input * factor).as_vec3());
|
||||||
let mut acceleration_total: DVec3 =
|
let mut acceleration_total: DVec3 =
|
||||||
(actor::ENGINE_SPEED_FACTOR * dt) as f64 * acceleration_global;
|
(actor::ENGINE_SPEED_FACTOR * dt) as f64 * boost * acceleration_global;
|
||||||
let threshold = 1e-5;
|
let threshold = 1e-5;
|
||||||
if key_input.pressed(settings.key_stop) {
|
if key_input.pressed(settings.key_stop) {
|
||||||
// Decelerate (or match velocity to target_v)
|
// Decelerate (or match velocity to target_v)
|
||||||
|
engine.currently_matching_velocity = true;
|
||||||
let dv = v.0 - target_v;
|
let dv = v.0 - target_v;
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
if dv[i].abs() < threshold {
|
if dv[i].abs() < threshold {
|
||||||
|
@ -560,6 +567,8 @@ pub fn apply_input_to_player(
|
||||||
acceleration_total[i] = 0.0;
|
acceleration_total[i] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
engine.currently_matching_velocity = false;
|
||||||
}
|
}
|
||||||
// TODO: handle mass
|
// TODO: handle mass
|
||||||
v.0 += acceleration_total;
|
v.0 += acceleration_total;
|
||||||
|
@ -571,7 +580,7 @@ pub fn apply_input_to_player(
|
||||||
if bike.is_none() && acceleration_total.length_squared() > 1e-4 {
|
if bike.is_none() && acceleration_total.length_squared() > 1e-4 {
|
||||||
let thruster_direction = acceleration_total.normalize();
|
let thruster_direction = acceleration_total.normalize();
|
||||||
let thruster_pos = pos.0 - 0.3 * thruster_direction;
|
let thruster_pos = pos.0 - 0.3 * thruster_direction;
|
||||||
let thruster_v = v.0 - 5.0 * thruster_direction;
|
let thruster_v = v.0 - boost * 5.0 * thruster_direction;
|
||||||
ew_effect.send(visual::SpawnEffectEvent {
|
ew_effect.send(visual::SpawnEffectEvent {
|
||||||
duration: 2.0,
|
duration: 2.0,
|
||||||
class: visual::Effects::ThrusterParticle(
|
class: visual::Effects::ThrusterParticle(
|
||||||
|
@ -581,6 +590,8 @@ pub fn apply_input_to_player(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
engine.currently_firing = false;
|
||||||
|
engine.currently_matching_velocity = false;
|
||||||
engine.current_warmup =
|
engine.current_warmup =
|
||||||
(engine.current_warmup - dt / engine.warmup_seconds).clamp(0.0, 1.0);
|
(engine.current_warmup - dt / engine.warmup_seconds).clamp(0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -676,21 +687,23 @@ pub fn apply_input_to_player(
|
||||||
let sinks = vec![
|
let sinks = vec![
|
||||||
(
|
(
|
||||||
1.0,
|
1.0,
|
||||||
|
boost as f32,
|
||||||
actor::EngineType::Monopropellant,
|
actor::EngineType::Monopropellant,
|
||||||
sinks.get(&audio::Sfx::Thruster),
|
sinks.get(&audio::Sfx::Thruster),
|
||||||
),
|
),
|
||||||
(1.0, actor::EngineType::Ion, sinks.get(&audio::Sfx::Ion)),
|
(1.0, 1.0, actor::EngineType::Ion, sinks.get(&audio::Sfx::Ion)),
|
||||||
];
|
];
|
||||||
let seconds_to_max_vol = 0.05;
|
let seconds_to_max_vol = 0.05;
|
||||||
let seconds_to_min_vol = 0.05;
|
let seconds_to_min_vol = 0.05;
|
||||||
for sink_data in sinks {
|
for sink_data in sinks {
|
||||||
if let (vol_boost, engine_type, Some(sink)) = sink_data {
|
if let (vol_boost, speed, engine_type, Some(sink)) = sink_data {
|
||||||
if settings.mute_sfx {
|
if settings.mute_sfx {
|
||||||
sink.pause();
|
sink.pause();
|
||||||
} else {
|
} else {
|
||||||
let volume = sink.volume();
|
let volume = sink.volume();
|
||||||
if engine.engine_type == engine_type {
|
if engine.engine_type == engine_type {
|
||||||
if play_thruster_sound {
|
if play_thruster_sound {
|
||||||
|
sink.set_speed(speed);
|
||||||
sink.play();
|
sink.play();
|
||||||
if volume < 1.0 {
|
if volume < 1.0 {
|
||||||
let maxvol = vol_boost;
|
let maxvol = vol_boost;
|
||||||
|
|
|
@ -816,6 +816,7 @@ fn spawn_entities(
|
||||||
mut achievement_tracker: ResMut<var::AchievementTracker>,
|
mut achievement_tracker: ResMut<var::AchievementTracker>,
|
||||||
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
|
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
|
||||||
settings: Res<var::Settings>,
|
settings: Res<var::Settings>,
|
||||||
|
prefs: Res<var::Preferences>,
|
||||||
) {
|
) {
|
||||||
for state_wrapper in er_spawn.read() {
|
for state_wrapper in er_spawn.read() {
|
||||||
let state = &state_wrapper.0;
|
let state = &state_wrapper.0;
|
||||||
|
@ -1073,7 +1074,7 @@ fn spawn_entities(
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
spot_light: SpotLight {
|
spot_light: SpotLight {
|
||||||
intensity: 400_000_000.0, // lumens
|
intensity: actor::FLASHLIGHT_INTENSITY[prefs.flashlight_power],
|
||||||
color: Color::WHITE,
|
color: Color::WHITE,
|
||||||
shadows_enabled: true,
|
shadows_enabled: true,
|
||||||
inner_angle: PI32 / 8.0 * 0.85,
|
inner_angle: PI32 / 8.0 * 0.85,
|
||||||
|
|
|
@ -88,6 +88,7 @@ pub enum GameEvent {
|
||||||
SetThirdPerson(Turn),
|
SetThirdPerson(Turn),
|
||||||
SetRotationStabilizer(Turn),
|
SetRotationStabilizer(Turn),
|
||||||
SetShadows(Turn),
|
SetShadows(Turn),
|
||||||
|
UpdateFlashlight,
|
||||||
Achievement(String),
|
Achievement(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +142,7 @@ impl Cycle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(mut settings: ResMut<Settings>, prefs: Res<var::Preferences>) {
|
pub fn setup(mut settings: ResMut<Settings>, prefs: ResMut<var::Preferences>) {
|
||||||
settings.hud_active = prefs.augmented_reality;
|
settings.hud_active = prefs.augmented_reality;
|
||||||
settings.radio_mode = prefs.radio_station;
|
settings.radio_mode = prefs.radio_station;
|
||||||
settings.set_noise_cancellation_mode(prefs.noise_cancellation_mode);
|
settings.set_noise_cancellation_mode(prefs.noise_cancellation_mode);
|
||||||
|
@ -159,6 +160,7 @@ pub fn handle_game_event(
|
||||||
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
||||||
mut q_window: Query<&mut Window, With<PrimaryWindow>>,
|
mut q_window: Query<&mut Window, With<PrimaryWindow>>,
|
||||||
mut q_light: Query<&mut DirectionalLight>,
|
mut q_light: Query<&mut DirectionalLight>,
|
||||||
|
mut q_flashlight: Query<&mut SpotLight, With<actor::PlayersFlashLight>>,
|
||||||
mut mapcam: ResMut<camera::MapCam>,
|
mut mapcam: ResMut<camera::MapCam>,
|
||||||
mut log: ResMut<hud::Log>,
|
mut log: ResMut<hud::Log>,
|
||||||
opt: Res<var::CommandLineOptions>,
|
opt: Res<var::CommandLineOptions>,
|
||||||
|
@ -255,6 +257,11 @@ pub fn handle_game_event(
|
||||||
hud::LogLevel::Achievement,
|
hud::LogLevel::Achievement,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
GameEvent::UpdateFlashlight => {
|
||||||
|
for mut spotlight in &mut q_flashlight {
|
||||||
|
spotlight.intensity = actor::FLASHLIGHT_INTENSITY[prefs.flashlight_power];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/hud.rs
15
src/hud.rs
|
@ -28,8 +28,7 @@ pub const LOG_MAX: usize = LOG_MAX_ROWS;
|
||||||
pub const MAX_CHOICES: usize = 10;
|
pub const MAX_CHOICES: usize = 10;
|
||||||
pub const SPEEDOMETER_WIDTH: f32 = 20.0;
|
pub const SPEEDOMETER_WIDTH: f32 = 20.0;
|
||||||
pub const SPEEDOMETER_HEIGHT: f32 = 10.0;
|
pub const SPEEDOMETER_HEIGHT: f32 = 10.0;
|
||||||
pub const AMBIENT_LIGHT: f32 = 0.0; // Space is DARK
|
pub const AMBIENT_LIGHT: [f32; 4] = [0.0, 20.0, 60.0, 150.0];
|
||||||
pub const AMBIENT_LIGHT_AR: f32 = 20.0;
|
|
||||||
//pub const REPLY_NUMBERS: [char; 10] = ['❶', '❷', '❸', '❹', '❺', '❻', '❼', '❽', '❾', '⓿'];
|
//pub const REPLY_NUMBERS: [char; 10] = ['❶', '❷', '❸', '❹', '❺', '❻', '❼', '❽', '❾', '⓿'];
|
||||||
//pub const REPLY_NUMBERS: [char; 10] = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];
|
//pub const REPLY_NUMBERS: [char; 10] = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];
|
||||||
pub const REPLY_NUMBERS: [char; 10] = ['➀', '➁', '➂', '➃', '➄', '➅', '➆', '➇', '➈', '➉'];
|
pub const REPLY_NUMBERS: [char; 10] = ['➀', '➁', '➂', '➃', '➄', '➅', '➆', '➇', '➈', '➉'];
|
||||||
|
@ -39,6 +38,7 @@ pub const DASHBOARD_DEF: &[(Dashboard, &str)] = &[
|
||||||
(Dashboard::Leak, "leak"),
|
(Dashboard::Leak, "leak"),
|
||||||
(Dashboard::RotationStabiliser, "rotation_stabiliser"),
|
(Dashboard::RotationStabiliser, "rotation_stabiliser"),
|
||||||
(Dashboard::CruiseControl, "cruise_control"),
|
(Dashboard::CruiseControl, "cruise_control"),
|
||||||
|
(Dashboard::Battery, "battery"),
|
||||||
(Dashboard::Radioactivity, "radioactivity"),
|
(Dashboard::Radioactivity, "radioactivity"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ pub enum Dashboard {
|
||||||
RotationStabiliser,
|
RotationStabiliser,
|
||||||
CruiseControl,
|
CruiseControl,
|
||||||
Radioactivity,
|
Radioactivity,
|
||||||
|
Battery,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Debug, Copy, Clone)]
|
#[derive(Component, Debug, Copy, Clone)]
|
||||||
|
@ -682,7 +683,7 @@ fn update_dashboard(
|
||||||
timer: ResMut<FPSUpdateTimer>,
|
timer: ResMut<FPSUpdateTimer>,
|
||||||
mut q_dashboard: Query<(&mut Visibility, &Dashboard)>,
|
mut q_dashboard: Query<(&mut Visibility, &Dashboard)>,
|
||||||
id2pos: Res<game::Id2Pos>,
|
id2pos: Res<game::Id2Pos>,
|
||||||
q_player: Query<(&actor::Suit, &Position), With<actor::Player>>,
|
q_player: Query<(&actor::Suit, &actor::Battery, &Position), With<actor::Player>>,
|
||||||
settings: Res<Settings>,
|
settings: Res<Settings>,
|
||||||
) {
|
) {
|
||||||
if !settings.hud_active || !timer.0.just_finished() {
|
if !settings.hud_active || !timer.0.just_finished() {
|
||||||
|
@ -692,12 +693,13 @@ fn update_dashboard(
|
||||||
if player.is_err() {
|
if player.is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let (suit, pos) = player.unwrap();
|
let (suit, battery, pos) = player.unwrap();
|
||||||
|
|
||||||
for (mut vis, icon) in &mut q_dashboard {
|
for (mut vis, icon) in &mut q_dashboard {
|
||||||
*vis = bool2vis(match icon {
|
*vis = bool2vis(match icon {
|
||||||
Dashboard::Flashlight => settings.flashlight_active,
|
Dashboard::Flashlight => settings.flashlight_active,
|
||||||
Dashboard::Leak => suit.integrity < 0.5,
|
Dashboard::Leak => suit.integrity < 0.5,
|
||||||
|
Dashboard::Battery => battery.overloaded_recovering,
|
||||||
Dashboard::RotationStabiliser => !settings.rotation_stabilizer_active,
|
Dashboard::RotationStabiliser => !settings.rotation_stabilizer_active,
|
||||||
Dashboard::CruiseControl => settings.cruise_control_active,
|
Dashboard::CruiseControl => settings.cruise_control_active,
|
||||||
Dashboard::Radioactivity => {
|
Dashboard::Radioactivity => {
|
||||||
|
@ -1253,6 +1255,7 @@ fn update_overlay_visibility(
|
||||||
mut ambient_light: ResMut<AmbientLight>,
|
mut ambient_light: ResMut<AmbientLight>,
|
||||||
er_target: EventReader<UpdateOverlayVisibility>,
|
er_target: EventReader<UpdateOverlayVisibility>,
|
||||||
settings: Res<Settings>,
|
settings: Res<Settings>,
|
||||||
|
prefs: Res<Preferences>,
|
||||||
) {
|
) {
|
||||||
if er_target.is_empty() {
|
if er_target.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -1280,9 +1283,9 @@ fn update_overlay_visibility(
|
||||||
}
|
}
|
||||||
|
|
||||||
ambient_light.brightness = if settings.hud_active {
|
ambient_light.brightness = if settings.hud_active {
|
||||||
AMBIENT_LIGHT_AR
|
AMBIENT_LIGHT[prefs.light_amp]
|
||||||
} else {
|
} else {
|
||||||
AMBIENT_LIGHT
|
AMBIENT_LIGHT[0]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub mod world;
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::common::*;
|
pub use crate::common::*;
|
||||||
pub use crate::load::load_asset;
|
pub use crate::load::load_asset;
|
||||||
pub use crate::var::Settings;
|
pub use crate::var::{Preferences, Settings};
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
actor, audio, camera, chat, cmd, common, game, hud, load, menu, nature, var, visual, world,
|
actor, audio, camera, chat, cmd, common, game, hud, load, menu, nature, var, visual, world,
|
||||||
};
|
};
|
||||||
|
|
49
src/menu.rs
49
src/menu.rs
|
@ -66,6 +66,9 @@ pub const MENUDEF: &[(&str, MenuAction)] = &[
|
||||||
("", MenuAction::ToggleMap),
|
("", MenuAction::ToggleMap),
|
||||||
("", MenuAction::ToggleAR),
|
("", MenuAction::ToggleAR),
|
||||||
("", MenuAction::ChangeARAvatar),
|
("", MenuAction::ChangeARAvatar),
|
||||||
|
("", MenuAction::ModLightAmp),
|
||||||
|
("", MenuAction::ModFlashlightPower),
|
||||||
|
("", MenuAction::ModThrusterBoost),
|
||||||
("", MenuAction::ToggleSound),
|
("", MenuAction::ToggleSound),
|
||||||
("", MenuAction::ToggleMusic),
|
("", MenuAction::ToggleMusic),
|
||||||
("", MenuAction::ToggleCamera),
|
("", MenuAction::ToggleCamera),
|
||||||
|
@ -80,6 +83,9 @@ pub enum MenuAction {
|
||||||
ToggleMap,
|
ToggleMap,
|
||||||
ToggleAR,
|
ToggleAR,
|
||||||
ChangeARAvatar,
|
ChangeARAvatar,
|
||||||
|
ModLightAmp,
|
||||||
|
ModFlashlightPower,
|
||||||
|
ModThrusterBoost,
|
||||||
ToggleSound,
|
ToggleSound,
|
||||||
ToggleMusic,
|
ToggleMusic,
|
||||||
ToggleCamera,
|
ToggleCamera,
|
||||||
|
@ -428,6 +434,7 @@ pub fn update_menu(
|
||||||
achievement_tracker: Res<var::AchievementTracker>,
|
achievement_tracker: Res<var::AchievementTracker>,
|
||||||
menustate: Res<MenuState>,
|
menustate: Res<MenuState>,
|
||||||
settings: Res<Settings>,
|
settings: Res<Settings>,
|
||||||
|
prefs: Res<Preferences>,
|
||||||
) {
|
) {
|
||||||
for mut vis in &mut q_vis {
|
for mut vis in &mut q_vis {
|
||||||
*vis = bool2vis(settings.menu_active);
|
*vis = bool2vis(settings.menu_active);
|
||||||
|
@ -481,6 +488,23 @@ pub fn update_menu(
|
||||||
let onoff = bool2string(settings.hud_active);
|
let onoff = bool2string(settings.hud_active);
|
||||||
text.sections[i].value = format!("Augmented Reality: {onoff} [TAB]\n");
|
text.sections[i].value = format!("Augmented Reality: {onoff} [TAB]\n");
|
||||||
}
|
}
|
||||||
|
MenuAction::ModLightAmp => {
|
||||||
|
let n = prefs.light_amp;
|
||||||
|
text.sections[i].value = format!("Light Amplification: {n}/3\n");
|
||||||
|
}
|
||||||
|
MenuAction::ModFlashlightPower => {
|
||||||
|
let n = prefs.flashlight_power + 1;
|
||||||
|
text.sections[i].value = format!("Flashlight Power: {n}/3\n");
|
||||||
|
}
|
||||||
|
MenuAction::ModThrusterBoost => {
|
||||||
|
let state = match prefs.thruster_boost {
|
||||||
|
0 => "Only when slowing down",
|
||||||
|
1 => "MAX POWER",
|
||||||
|
2 => "Off",
|
||||||
|
_ => "ERROR",
|
||||||
|
};
|
||||||
|
text.sections[i].value = format!("Thruster Boost: {state}\n");
|
||||||
|
}
|
||||||
MenuAction::ChangeARAvatar => {
|
MenuAction::ChangeARAvatar => {
|
||||||
if let Some(ava) = hud::PLAYER_AR_AVATARS.get(settings.ar_avatar) {
|
if let Some(ava) = hud::PLAYER_AR_AVATARS.get(settings.ar_avatar) {
|
||||||
let avatar_title = ava.3;
|
let avatar_title = ava.3;
|
||||||
|
@ -516,6 +540,7 @@ pub fn update_menu(
|
||||||
pub fn handle_input(
|
pub fn handle_input(
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut settings: ResMut<Settings>,
|
mut settings: ResMut<Settings>,
|
||||||
|
mut prefs: ResMut<Preferences>,
|
||||||
mut menustate: ResMut<MenuState>,
|
mut menustate: ResMut<MenuState>,
|
||||||
mut app_exit_events: ResMut<Events<AppExit>>,
|
mut app_exit_events: ResMut<Events<AppExit>>,
|
||||||
mut ew_game: EventWriter<game::GameEvent>,
|
mut ew_game: EventWriter<game::GameEvent>,
|
||||||
|
@ -523,6 +548,7 @@ pub fn handle_input(
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
mut ew_updatemenu: EventWriter<UpdateMenuEvent>,
|
mut ew_updatemenu: EventWriter<UpdateMenuEvent>,
|
||||||
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
|
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
|
||||||
|
mut ew_updateoverlays: EventWriter<hud::UpdateOverlayVisibility>,
|
||||||
) {
|
) {
|
||||||
let last_menu_entry = MENUDEF.len() - 1;
|
let last_menu_entry = MENUDEF.len() - 1;
|
||||||
|
|
||||||
|
@ -577,6 +603,29 @@ pub fn handle_input(
|
||||||
ew_updateavatar.send(hud::UpdateAvatarEvent);
|
ew_updateavatar.send(hud::UpdateAvatarEvent);
|
||||||
ew_updatemenu.send(UpdateMenuEvent);
|
ew_updatemenu.send(UpdateMenuEvent);
|
||||||
}
|
}
|
||||||
|
MenuAction::ModLightAmp => {
|
||||||
|
prefs.light_amp += 1;
|
||||||
|
if prefs.light_amp > 3 {
|
||||||
|
prefs.light_amp = 0;
|
||||||
|
}
|
||||||
|
ew_updateoverlays.send(hud::UpdateOverlayVisibility);
|
||||||
|
ew_updatemenu.send(UpdateMenuEvent);
|
||||||
|
}
|
||||||
|
MenuAction::ModFlashlightPower => {
|
||||||
|
prefs.flashlight_power += 1;
|
||||||
|
if prefs.flashlight_power > 2 {
|
||||||
|
prefs.flashlight_power = 0;
|
||||||
|
}
|
||||||
|
ew_game.send(GameEvent::UpdateFlashlight);
|
||||||
|
ew_updatemenu.send(UpdateMenuEvent);
|
||||||
|
}
|
||||||
|
MenuAction::ModThrusterBoost => {
|
||||||
|
prefs.thruster_boost += 1;
|
||||||
|
if prefs.thruster_boost > 2 {
|
||||||
|
prefs.thruster_boost = 0;
|
||||||
|
}
|
||||||
|
ew_updatemenu.send(UpdateMenuEvent);
|
||||||
|
}
|
||||||
MenuAction::ToggleMusic => {
|
MenuAction::ToggleMusic => {
|
||||||
ew_game.send(GameEvent::SetMusic(Next));
|
ew_game.send(GameEvent::SetMusic(Next));
|
||||||
ew_updatemenu.send(UpdateMenuEvent);
|
ew_updatemenu.send(UpdateMenuEvent);
|
||||||
|
|
105
src/svg/dashboard_battery.svg
Normal file
105
src/svg/dashboard_battery.svg
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="256"
|
||||||
|
height="256"
|
||||||
|
viewBox="0 0 67.733334 67.733334"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||||
|
sodipodi:docname="dashboard_battery.svg"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:export-filename="../../assets/sprites/dashboard_battery.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#252525"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#000000"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:zoom="1.6542969"
|
||||||
|
inkscape:cx="107.59858"
|
||||||
|
inkscape:cy="110.92326"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="820"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="60"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="g227"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:export-bgcolor="#00000000"><inkscape:grid
|
||||||
|
id="grid1"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="0.26458334"
|
||||||
|
spacingy="0.26458334"
|
||||||
|
empcolor="#0099e5"
|
||||||
|
empopacity="0.30196078"
|
||||||
|
color="#0099e5"
|
||||||
|
opacity="0.14901961"
|
||||||
|
empspacing="8"
|
||||||
|
dotted="false"
|
||||||
|
gridanglex="30"
|
||||||
|
gridanglez="30"
|
||||||
|
visible="true" /></sodipodi:namedview><defs
|
||||||
|
id="defs1"><filter
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter1"
|
||||||
|
inkscape:label="bloom"
|
||||||
|
x="-0.13048332"
|
||||||
|
y="-0.15460972"
|
||||||
|
width="1.2609666"
|
||||||
|
height="1.3092194"><feConvolveMatrix
|
||||||
|
order="1 1"
|
||||||
|
kernelMatrix="1.0000000 "
|
||||||
|
id="feConvolveMatrix1"
|
||||||
|
result="result1"
|
||||||
|
bias="0"
|
||||||
|
preserveAlpha="true"
|
||||||
|
edgeMode="none"
|
||||||
|
divisor="0" /><feGaussianBlur
|
||||||
|
stdDeviation="2"
|
||||||
|
id="feGaussianBlur1"
|
||||||
|
in="SourceGraphic" /><feComposite
|
||||||
|
id="feComposite1"
|
||||||
|
operator="arithmetic"
|
||||||
|
k1="1"
|
||||||
|
k2="0.99999999999999922"
|
||||||
|
k3="1"
|
||||||
|
k4="0"
|
||||||
|
in2="result1" /></filter></defs><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"><g
|
||||||
|
id="g227"
|
||||||
|
style="filter:url(#filter1)"><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1-5"
|
||||||
|
transform="matrix(0.86486189,0,0,0.86486189,5.6836111,4.3940895)"><path
|
||||||
|
style="font-variation-settings:'wght' 400;fill:none;fill-opacity:1;stroke:#be1251;stroke-width:3.05926;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 6.7381087,16.059295 4.5e-6,40.702599 54.2571138,-2.5e-5 -3e-6,-40.702598 h -7.398697 l -14.797395,2.4e-5 14.797397,8.8e-5 -2e-6,-5.087942 H 41.265364 v 5.08783 l -14.797395,2.4e-5 -14.180835,2.4e-5 14.180837,6.4e-5 -2e-6,-5.087918 H 14.136807 v 5.08783 z"
|
||||||
|
id="path9"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccccc" /><path
|
||||||
|
style="font-variation-settings:'wght' 400;fill:none;fill-opacity:1;stroke:#be1251;stroke-width:5.29167;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 13.758334,30.691669 H 27.516668"
|
||||||
|
id="path10"
|
||||||
|
sodipodi:nodetypes="cc" /><path
|
||||||
|
style="font-variation-settings:'wght' 400;fill:none;fill-opacity:1;stroke:#be1251;stroke-width:5.29167;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 20.637501,23.283335 V 38.100002"
|
||||||
|
id="path11"
|
||||||
|
sodipodi:nodetypes="cc" /><path
|
||||||
|
style="font-variation-settings:'wght' 400;fill:none;fill-opacity:1;stroke:#be1251;stroke-width:5.29167;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 40.216669,30.691669 H 53.975003"
|
||||||
|
id="path12"
|
||||||
|
sodipodi:nodetypes="cc" /></g></g></g></svg>
|
After Width: | Height: | Size: 4.1 KiB |
17
src/var.rs
17
src/var.rs
|
@ -439,6 +439,7 @@ impl AchievementTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for settings that are preserved across restarts
|
||||||
#[derive(Resource, Serialize, Deserialize, Debug, Default)]
|
#[derive(Resource, Serialize, Deserialize, Debug, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Preferences {
|
pub struct Preferences {
|
||||||
|
@ -451,6 +452,9 @@ pub struct Preferences {
|
||||||
pub third_person: bool,
|
pub third_person: bool,
|
||||||
pub shadows_sun: bool,
|
pub shadows_sun: bool,
|
||||||
pub avatar: usize,
|
pub avatar: usize,
|
||||||
|
pub light_amp: usize, // 0-3
|
||||||
|
pub flashlight_power: usize, // 0-2
|
||||||
|
pub thruster_boost: usize, // 0-2
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub source_file: Option<String>,
|
pub source_file: Option<String>,
|
||||||
|
@ -564,23 +568,26 @@ pub fn load_prefs() -> Preferences {
|
||||||
};
|
};
|
||||||
match toml.parse::<DocumentMut>() {
|
match toml.parse::<DocumentMut>() {
|
||||||
Ok(doc) => match toml_edit::de::from_document::<Preferences>(doc) {
|
Ok(doc) => match toml_edit::de::from_document::<Preferences>(doc) {
|
||||||
Ok(mut pref) => {
|
Ok(mut prefs) => {
|
||||||
if let Some(path) = &path {
|
if let Some(path) = &path {
|
||||||
println!("Loaded preference file from {path}");
|
println!("Loaded preference file from {path}");
|
||||||
} else {
|
} else {
|
||||||
println!("Loaded preferences from internal defaults");
|
println!("Loaded preferences from internal defaults");
|
||||||
}
|
}
|
||||||
pref.source_file = path;
|
prefs.source_file = path;
|
||||||
return pref;
|
prefs.flashlight_power = prefs.flashlight_power.clamp(0, 2);
|
||||||
|
prefs.light_amp = prefs.light_amp.clamp(0, 3);
|
||||||
|
prefs.thruster_boost = prefs.thruster_boost.clamp(0, 2);
|
||||||
|
prefs
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("Error: Failed to read preference line: {error}");
|
eprintln!("Error: Failed to read preference line: {error}");
|
||||||
return Preferences::default();
|
Preferences::default()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("Error: Failed to open preferences: {error}");
|
eprintln!("Error: Failed to open preferences: {error}");
|
||||||
return Preferences::default();
|
Preferences::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue