outfly/src/var.rs

690 lines
24 KiB
Rust
Raw Normal View History

2024-04-21 16:23:40 +00:00
// ▄████████▄ + ███ + ▄█████████ ███ +
// ███▀ ▀███ + + ███ ███▀ + ███ + +
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
2024-04-21 17:34:00 +00:00
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
2024-04-21 16:23:40 +00:00
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
// + + + ███
// + ▀████████████████████████████████████████████████████▀
2024-04-23 15:33:36 +00:00
//
// This module manages variables, settings, as well as evaluating
// "if"-conditions in chats.
2024-04-21 16:23:40 +00:00
2024-05-12 23:42:14 +00:00
use crate::prelude::*;
use bevy::window::WindowMode;
2024-03-16 21:20:23 +00:00
use bevy::prelude::*;
2024-05-13 23:24:57 +00:00
use std::collections::{HashMap, HashSet};
2024-04-30 20:26:54 +00:00
use serde::Deserialize;
use toml_edit::DocumentMut;
2024-04-30 20:26:54 +00:00
use std::env;
use std::fs;
2024-03-16 21:20:23 +00:00
2024-04-14 14:20:51 +00:00
pub const SCOPE_SEPARATOR: &str = "$";
pub const TOKEN_EQUALS: &str = "==";
pub const TOKEN_EQUALS_NOT: &str = "!=";
pub const TOKEN_GREATER_THAN: &str = ">";
pub const TOKEN_LESS_THAN: &str = "<";
pub const TOKEN_GREATER_EQUALS: &str = ">=";
pub const TOKEN_LESS_EQUALS: &str = "<=";
pub const TOKEN_NEGATE: &str = "~";
2024-04-12 23:34:18 +00:00
pub const DEFAULT_CHAT_SPEED: f32 = 10.0;
2024-03-17 17:26:44 +00:00
#[derive(Resource)]
2024-03-16 21:20:23 +00:00
pub struct Settings {
2024-03-30 20:14:04 +00:00
pub dev_mode: bool,
2024-04-07 23:44:36 +00:00
pub god_mode: bool,
2024-04-18 01:56:32 +00:00
pub version: String,
2024-05-13 02:47:47 +00:00
pub alive: bool,
2024-03-16 21:20:23 +00:00
pub mute_sfx: bool,
pub mute_music: bool,
pub volume_sfx: u8,
pub volume_music: u8,
2024-03-30 15:27:56 +00:00
pub mouse_sensitivity: f32,
2024-04-08 01:15:45 +00:00
pub fov: f32,
pub fov_highspeed: f32,
pub zoom_fov: f32,
2024-04-05 21:38:20 +00:00
pub zoom_sensitivity_factor: f32,
2024-03-17 19:31:16 +00:00
pub font_size_hud: f32,
pub font_size_fps: f32,
2024-03-17 19:31:16 +00:00
pub font_size_conversations: f32,
2024-04-15 18:58:19 +00:00
pub font_size_choices: f32,
pub font_size_console: f32,
2024-04-28 04:29:01 +00:00
pub font_size_speedometer: f32,
2024-05-12 20:17:17 +00:00
pub font_size_deathtext: f32,
pub font_size_deathsubtext: f32,
2024-05-12 23:42:22 +00:00
pub font_size_deathpoem: f32,
2024-05-14 04:28:14 +00:00
pub font_size_death_achievements: f32,
2024-05-14 03:17:32 +00:00
pub font_size_achievement: f32,
pub font_size_achievement_header: f32,
2024-04-15 18:58:19 +00:00
pub hud_color: Color,
pub hud_color_fps: Color,
2024-04-15 18:58:19 +00:00
pub hud_color_console: Color,
pub hud_color_console_warn: Color,
pub hud_color_console_system: Color,
pub hud_color_console_achievement: Color,
2024-04-15 18:58:19 +00:00
pub hud_color_alert: Color,
pub hud_color_subtitles: Color,
pub hud_color_choices: Color,
2024-04-28 04:29:01 +00:00
pub hud_color_speedometer: Color,
2024-05-12 23:42:22 +00:00
pub hud_color_deathpoem: Color,
2024-05-14 03:17:32 +00:00
pub hud_color_achievement: Color,
pub hud_color_achievement_header: Color,
pub hud_color_achievement_accomplished: Color,
2024-05-14 04:28:14 +00:00
pub hud_color_death: Color,
pub hud_color_death_achievements: Color,
2024-04-12 23:34:18 +00:00
pub chat_speed: f32,
pub flashlight_active: bool,
pub hud_active: bool,
2024-04-18 19:01:03 +00:00
pub map_active: bool,
2024-05-12 20:17:17 +00:00
pub deathscreen_active: bool,
2024-05-13 18:21:56 +00:00
pub menu_active: bool,
2024-05-12 20:17:17 +00:00
pub death_cause: String,
2024-04-05 21:38:20 +00:00
pub is_zooming: bool,
pub third_person: bool,
2024-04-11 19:06:21 +00:00
pub rotation_stabilizer_active: bool,
pub shadows_sun: bool,
pub shadows_pointlights: bool,
2024-04-24 17:59:14 +00:00
pub shadowmap_resolution: usize,
pub large_moons: bool,
pub key_selectobject: MouseButton,
2024-04-05 21:38:20 +00:00
pub key_zoom: MouseButton,
2024-04-18 19:01:03 +00:00
pub key_map: KeyCode,
pub key_map_zoom_out: KeyCode,
pub key_map_zoom_in: KeyCode,
//pub key_map_zoom_out_wheel: MouseButton,
//pub key_map_zoom_in_wheel: MouseButton,
2024-03-18 03:39:26 +00:00
pub key_togglehud: KeyCode,
2024-05-13 18:21:56 +00:00
pub key_menu: KeyCode,
2024-03-18 03:39:26 +00:00
pub key_fullscreen: KeyCode,
2024-04-15 21:17:44 +00:00
pub key_help: KeyCode,
2024-03-18 03:39:26 +00:00
pub key_forward: KeyCode,
pub key_back: KeyCode,
pub key_left: KeyCode,
pub key_right: KeyCode,
pub key_up: KeyCode,
pub key_down: KeyCode,
pub key_run: KeyCode,
pub key_stop: KeyCode,
pub key_interact: KeyCode,
pub key_vehicle: KeyCode,
pub key_camera: KeyCode,
pub key_flashlight: KeyCode,
2024-03-30 18:14:59 +00:00
pub key_rotate: KeyCode,
2024-04-11 19:06:21 +00:00
pub key_rotation_stabilizer: KeyCode,
pub key_mouseup: KeyCode,
pub key_mousedown: KeyCode,
pub key_mouseleft: KeyCode,
pub key_mouseright: KeyCode,
pub key_rotateleft: KeyCode,
pub key_rotateright: KeyCode,
2024-03-20 01:03:42 +00:00
pub key_reply1: KeyCode,
pub key_reply2: KeyCode,
pub key_reply3: KeyCode,
pub key_reply4: KeyCode,
pub key_reply5: KeyCode,
pub key_reply6: KeyCode,
pub key_reply7: KeyCode,
pub key_reply8: KeyCode,
pub key_reply9: KeyCode,
pub key_reply10: KeyCode,
2024-04-07 23:44:36 +00:00
pub key_cheat_god_mode: KeyCode,
2024-04-01 03:25:35 +00:00
pub key_cheat_stop: KeyCode,
pub key_cheat_speed: KeyCode,
pub key_cheat_speed_backward: KeyCode,
2024-04-14 21:38:55 +00:00
pub key_cheat_teleport: KeyCode,
2024-04-01 03:25:35 +00:00
pub key_cheat_pizza: KeyCode,
pub key_cheat_farview1: KeyCode,
pub key_cheat_farview2: KeyCode,
pub key_cheat_adrenaline_zero: KeyCode,
pub key_cheat_adrenaline_mid: KeyCode,
pub key_cheat_adrenaline_max: KeyCode,
2024-04-05 00:58:02 +00:00
pub key_cheat_die: KeyCode,
2024-03-16 21:20:23 +00:00
}
impl Default for Settings {
fn default() -> Self {
let dev_mode = cfg!(feature = "dev_mode") && env::var("CARGO").is_ok();
2024-03-28 19:54:34 +00:00
let default_mute_sfx = false;
let default_mute_music = dev_mode;
2024-04-18 01:56:32 +00:00
let version = if let Some(version) = option_env!("CARGO_PKG_VERSION") {
version.to_string()
} else {
"13.37".to_string()
};
2024-03-22 11:08:00 +00:00
2024-03-16 21:20:23 +00:00
Settings {
2024-04-14 02:56:34 +00:00
dev_mode,
2024-04-07 23:44:36 +00:00
god_mode: false,
2024-04-18 01:56:32 +00:00
version,
2024-05-13 02:47:47 +00:00
alive: true,
2024-03-22 11:08:00 +00:00
mute_sfx: default_mute_sfx,
mute_music: default_mute_music,
2024-03-16 21:20:23 +00:00
volume_sfx: 100,
volume_music: 100,
mouse_sensitivity: 0.4,
2024-04-08 01:15:45 +00:00
fov: 50.0,
fov_highspeed: 25.0,
2024-04-08 02:16:01 +00:00
zoom_fov: 15.0,
2024-04-08 00:17:36 +00:00
zoom_sensitivity_factor: 0.25,
2024-04-15 19:29:06 +00:00
font_size_hud: 24.0,
font_size_fps: 14.0,
2024-03-17 19:31:16 +00:00
font_size_conversations: 32.0,
2024-04-15 18:58:19 +00:00
font_size_choices: 28.0,
font_size_console: 20.0,
2024-04-28 04:29:01 +00:00
font_size_speedometer: 34.0,
2024-05-12 20:17:17 +00:00
font_size_deathtext: 64.0,
font_size_deathsubtext: 32.0,
2024-05-12 23:42:22 +00:00
font_size_deathpoem: 18.0,
2024-05-14 04:28:14 +00:00
font_size_death_achievements: 24.0,
2024-05-14 03:17:32 +00:00
font_size_achievement: 24.0,
font_size_achievement_header: 32.0,
2024-04-30 22:51:50 +00:00
hud_color: Color::hex("#BE1251").unwrap(),
hud_color_fps: Color::hex("#181818").unwrap(),
2024-04-30 22:51:50 +00:00
hud_color_console: Color::hex("#BE1251").unwrap(),
hud_color_console_achievement: Color::hex("#F0D50C").unwrap(),
2024-04-30 22:51:50 +00:00
hud_color_console_warn: Color::hex("#CCCCCC").unwrap(),
hud_color_console_system: Color::hex("#7F7F7F").unwrap(),
2024-04-30 22:51:50 +00:00
hud_color_alert: Color::hex("#CCCCCC").unwrap(),
hud_color_subtitles: Color::hex("#CCCCCC").unwrap(),
hud_color_choices: Color::hex("#727272").unwrap(),
hud_color_speedometer: Color::hex("#BE1251").unwrap(),
2024-05-12 23:42:22 +00:00
hud_color_deathpoem: Color::hex("#CC2200").unwrap(),
2024-05-14 03:17:32 +00:00
hud_color_achievement: Color::hex("#666666").unwrap(),
hud_color_achievement_accomplished: Color::hex("#F0D50C").unwrap(),
hud_color_achievement_header: Color::hex("#BE1251").unwrap(),
2024-05-14 04:28:14 +00:00
hud_color_death: Color::hex("#CCCCCC").unwrap(),
hud_color_death_achievements: Color::hex("#CCCCCC").unwrap(),
2024-04-14 19:07:59 +00:00
chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 },
flashlight_active: false,
hud_active: true,
2024-04-18 19:01:03 +00:00
map_active: false,
2024-05-12 20:17:17 +00:00
deathscreen_active: false,
2024-05-13 18:21:56 +00:00
menu_active: false,
2024-05-12 20:17:17 +00:00
death_cause: "Unknown".to_string(),
2024-04-05 21:38:20 +00:00
is_zooming: false,
third_person: true,
2024-04-11 19:06:21 +00:00
rotation_stabilizer_active: true,
shadows_sun: true,
shadows_pointlights: false,
2024-04-24 17:59:14 +00:00
shadowmap_resolution: 2048,
large_moons: false,
key_selectobject: MouseButton::Left,
2024-04-05 21:38:20 +00:00
key_zoom: MouseButton::Right,
2024-04-20 02:48:17 +00:00
key_map: KeyCode::KeyM,
2024-04-18 19:01:03 +00:00
key_map_zoom_out: KeyCode::ShiftLeft,
key_map_zoom_in: KeyCode::ControlLeft,
//key_map_zoom_out_wheel: KeyCode::Shift,
//key_map_zoom_in_wheel: KeyCode::Shift,
2024-03-18 03:39:26 +00:00
key_togglehud: KeyCode::Tab,
2024-05-13 18:21:56 +00:00
key_menu: KeyCode::Escape,
2024-03-18 03:39:26 +00:00
key_fullscreen: KeyCode::F11,
2024-04-15 21:17:44 +00:00
key_help: KeyCode::F1,
2024-03-18 03:39:26 +00:00
key_forward: KeyCode::KeyW,
key_back: KeyCode::KeyS,
key_left: KeyCode::KeyA,
key_right: KeyCode::KeyD,
key_up: KeyCode::ShiftLeft,
key_down: KeyCode::ControlLeft,
key_run: KeyCode::KeyR,
key_stop: KeyCode::Space,
key_interact: KeyCode::KeyE,
key_vehicle: KeyCode::KeyQ,
2024-05-13 21:01:00 +00:00
key_camera: KeyCode::KeyC,
key_flashlight: KeyCode::KeyF,
2024-03-30 18:14:59 +00:00
key_rotate: KeyCode::KeyR,
2024-04-11 19:06:21 +00:00
key_rotation_stabilizer: KeyCode::KeyY,
key_mouseup: KeyCode::KeyI,
key_mousedown: KeyCode::KeyK,
key_mouseleft: KeyCode::KeyJ,
key_mouseright: KeyCode::KeyL,
key_rotateleft: KeyCode::KeyU,
key_rotateright: KeyCode::KeyO,
2024-03-20 01:03:42 +00:00
key_reply1: KeyCode::Digit1,
key_reply2: KeyCode::Digit2,
key_reply3: KeyCode::Digit3,
key_reply4: KeyCode::Digit4,
key_reply5: KeyCode::Digit5,
key_reply6: KeyCode::Digit6,
key_reply7: KeyCode::Digit7,
key_reply8: KeyCode::Digit8,
key_reply9: KeyCode::Digit9,
key_reply10: KeyCode::Digit0,
2024-04-07 23:44:36 +00:00
key_cheat_god_mode: KeyCode::KeyG,
2024-05-13 21:01:00 +00:00
key_cheat_stop: KeyCode::KeyZ,
2024-04-01 03:25:35 +00:00
key_cheat_speed: KeyCode::KeyV,
key_cheat_speed_backward: KeyCode::KeyB,
2024-04-14 21:38:55 +00:00
key_cheat_teleport: KeyCode::KeyX,
2024-04-11 18:47:11 +00:00
key_cheat_pizza: KeyCode::F9,
key_cheat_farview1: KeyCode::F10,
key_cheat_farview2: KeyCode::F12,
2024-04-01 03:25:35 +00:00
key_cheat_adrenaline_zero: KeyCode::F5,
key_cheat_adrenaline_mid: KeyCode::F6,
2024-04-11 18:47:11 +00:00
key_cheat_adrenaline_max: KeyCode::F8,
2024-05-13 21:01:00 +00:00
key_cheat_die: KeyCode::F4,
2024-03-16 21:20:23 +00:00
}
}
}
impl Settings {
2024-04-11 19:20:54 +00:00
#[allow(dead_code)]
2024-03-16 21:20:23 +00:00
pub fn reset(&mut self) {
println!("Resetting settings!");
*self = Self::default();
}
2024-03-20 01:03:42 +00:00
2024-04-11 19:20:54 +00:00
pub fn reset_player_settings(&mut self) {
println!("Resetting player settings!");
let default = Self::default();
self.rotation_stabilizer_active = default.rotation_stabilizer_active;
self.third_person = default.third_person;
self.is_zooming = default.is_zooming;
2024-05-08 03:47:37 +00:00
self.flashlight_active = default.flashlight_active;
2024-05-12 21:30:55 +00:00
self.map_active = default.map_active;
2024-04-11 19:20:54 +00:00
}
2024-03-20 01:03:42 +00:00
pub fn get_reply_keys(&self) -> [KeyCode; 10] {
return [
self.key_reply1,
self.key_reply2,
self.key_reply3,
self.key_reply4,
self.key_reply5,
self.key_reply6,
self.key_reply7,
self.key_reply8,
self.key_reply9,
self.key_reply10,
];
}
2024-05-13 18:21:56 +00:00
pub fn in_control(&self) -> bool {
return self.alive && !self.menu_active;
}
2024-03-16 21:20:23 +00:00
}
2024-04-14 13:37:36 +00:00
2024-05-13 23:24:57 +00:00
#[derive(Resource, Default, Debug)]
pub struct AchievementTracker {
pub repair_suit: bool,
pub drink_a_pizza: bool,
pub in_jupiters_shadow: bool,
2024-05-14 03:33:35 +00:00
pub find_earth: bool,
2024-05-13 23:24:57 +00:00
pub ride_every_vehicle: bool,
pub vehicles_ridden: HashSet<String>,
pub all_vehicles: HashSet<String>,
pub talk_to_everyone: bool,
pub people_talked_to: HashSet<String>,
pub all_people: HashSet<String>,
}
2024-05-14 03:17:32 +00:00
impl AchievementTracker {
pub fn to_bool_vec(&self) -> Vec<bool> {
vec![
self.repair_suit,
self.drink_a_pizza,
self.ride_every_vehicle,
self.talk_to_everyone,
2024-05-14 03:33:35 +00:00
self.find_earth,
2024-05-14 03:17:32 +00:00
self.in_jupiters_shadow,
]
}
2024-05-14 04:28:14 +00:00
pub fn achieve_all(&mut self) {
self.repair_suit = true;
self.drink_a_pizza = true;
self.ride_every_vehicle = true;
self.talk_to_everyone = true;
self.find_earth = true;
self.in_jupiters_shadow = true;
}
2024-05-14 03:17:32 +00:00
pub fn to_textsections(&self) -> Vec<String> {
2024-05-14 03:41:26 +00:00
fn collectible(current: usize, total: usize) -> String {
if current < total {
format!(" ({}/{})", current, total)
} else {
"".to_string()
}
2024-05-14 03:17:32 +00:00
}
2024-05-14 03:41:26 +00:00
let ride = collectible(self.vehicles_ridden.len(), self.all_vehicles.len());
let talk = collectible(self.people_talked_to.len(), self.all_people.len());
2024-05-14 03:17:32 +00:00
vec![
2024-05-14 03:41:26 +00:00
"Repair Your Suit\n".to_string(),
"Consume A Pizza\n".to_string(),
format!("Ride Every Vehicle{ride}\n"),
format!("Talk To Everyone{talk}\n"),
"Find Earth\n".to_string(),
"Let Jupiter Eclipse The Sun\n".to_string(),
2024-05-14 03:17:32 +00:00
]
}
2024-05-14 04:28:14 +00:00
pub fn to_overview(&self) -> Vec<(bool, String)> {
vec![
(self.repair_suit, "repair your suit".into()),
(self.drink_a_pizza, "consume a pizza".into()),
(self.ride_every_vehicle, "ride every vehicle".into()),
(self.talk_to_everyone, "talk to everyone".into()),
(self.find_earth, "find Earth".into()),
(self.in_jupiters_shadow, "let Jupiter eclipse the Sun".into()),
]
}
pub fn to_summary(&self) -> String {
let list = self.to_overview();
let count = list.iter().filter(|(achieved, _)| *achieved).count();
if count == 0 {
return "".to_string()
}
let mut summary = "\n\n\nYou managed to ".to_string();
for (i, (_, text)) in list.iter().filter(|(achieved, _)| *achieved).enumerate() {
summary += text.as_str();
if i + 2 == count {
summary += ", and ";
}
else if i + 1 == count {
summary += " before you perished.";
if count == list.len() {
summary += "\nA truly astounding achievement, a glimmer in the void, before it all fades, into nothingness.";
}
}
else {
summary += ", ";
}
}
summary
}
2024-05-14 03:17:32 +00:00
}
#[derive(Resource, Deserialize, Debug, Default)]
#[serde(default)]
pub struct Preferences {
pub fullscreen_mode: String,
pub window_mode: String,
pub render_mode: String,
#[serde(skip)]
pub source_file: Option<String>,
}
impl Preferences {
pub fn get_fullscreen_mode(&self) -> WindowMode {
match self.fullscreen_mode.as_str() {
"legacy" => WindowMode::Fullscreen,
"sized" => WindowMode::SizedFullscreen,
_ => WindowMode::BorderlessFullscreen,
}
}
pub fn get_window_mode(&self) -> WindowMode {
match self.window_mode.as_str() {
"fullscreen" => self.get_fullscreen_mode(),
_ => WindowMode::Windowed,
}
}
pub fn render_mode_is_gl(&self) -> bool {
return self.render_mode == "gl";
}
}
fn file_is_readable(file_path: &str) -> bool {
fs::metadata(file_path).map(|metadata| metadata.is_file()).unwrap_or(false)
}
fn get_prefs_path() -> Option<String> {
2024-05-12 23:42:14 +00:00
let test = CONF_FILE;
if file_is_readable(test) {
return Some(test.to_string());
}
if let Ok(basedir) = env::var("XDG_CONFIG_HOME") {
2024-05-12 23:42:14 +00:00
let test = basedir.to_string() + "/outfly/" + CONF_FILE;
if file_is_readable(test.as_str()) {
return Some(test);
}
} else if let Ok(basedir) = env::var("HOME") {
2024-05-12 23:42:14 +00:00
let test = basedir.to_string() + ".config/outfly/" + CONF_FILE;
if file_is_readable(test.as_str()) {
return Some(test);
}
}
return None;
}
pub fn load_prefs() -> Preferences {
let (toml, path) = match get_prefs_path() {
Some(path) => {
let toml = fs::read_to_string(&path);
match toml {
Ok(toml) => (toml, Some(path)),
Err(error) => {
error!("Failed to open preferences file '{path}': {error}");
return Preferences::default();
}
}
}
None => {
warn!("Found no preference file, using default preferences.");
(include_str!("data/outfly.toml").to_string(), None)
}
};
match toml.parse::<DocumentMut>() {
Ok(doc) => {
match toml_edit::de::from_document::<Preferences>(doc) {
Ok(mut pref) => {
if let Some(path) = &path {
info!("Loaded preference file from {path}");
} else {
info!("Loaded preferences from internal defaults");
}
pref.source_file = path;
dbg!(&pref);
return pref;
}
Err(error) => {
error!("Failed to read preference line: {error}");
return Preferences::default();
}
}
}
Err(error) => {
error!("Failed to open preferences: {error}");
return Preferences::default();
}
}
}
2024-04-14 13:37:36 +00:00
#[derive(Resource)]
2024-04-14 14:20:51 +00:00
pub struct GameVars {
2024-04-14 13:37:36 +00:00
pub db: HashMap<String, String>,
}
2024-04-14 14:20:51 +00:00
impl Default for GameVars {
fn default() -> Self {
Self {
db: HashMap::new(),
}
}
}
2024-04-14 13:37:36 +00:00
impl GameVars {
#[allow(dead_code)]
2024-04-14 14:20:51 +00:00
pub fn get(&self, key: &str) -> Option<String> {
2024-04-14 13:37:36 +00:00
if let Some(value) = self.db.get(key) {
return Some(value.clone());
}
return None;
}
#[allow(dead_code)]
2024-04-14 14:20:51 +00:00
pub fn getf(&self, key: &str) -> Option<f64> {
2024-04-14 13:37:36 +00:00
if let Some(value) = self.db.get(key) {
if let Ok(float) = value.parse::<f64>() {
return Some(float);
}
}
return None;
}
2024-04-14 14:20:51 +00:00
pub fn getb(&self, key: &str) -> bool {
2024-04-14 13:37:36 +00:00
if let Some(value) = self.db.get(key) {
return Self::evaluate_str_as_bool(value);
2024-04-14 13:37:36 +00:00
}
return false;
}
pub fn evaluate_str_as_bool(string: &str) -> bool {
return string != "0";
2024-04-14 14:20:51 +00:00
}
// This method ensures that the variable name contains a scope separator,
// and if a scope is missing, it prefixes the fallback scope.
// Should NOT be used on non-variable values, like plain strings.
//
// Some examples, assuming fallback_scope="Clippy", SCOPE_SEPARATOR="$":
//
// "" -> "clippy$"
// "foo" -> "clippy$foo"
// "FOO" -> "clippy$foo"
// "$foo" -> "clippy$foo"
// "$$foo" -> "$$foo"
// "PizzaClippy$foo" -> "pizzaclippy$foo" (unchanged)
// "$foo$foo$foo$foo" -> "$foo$foo$foo$foo" (unchanged)
pub fn normalize_varname(fallback_scope: &str, key: &str) -> String {
let parts: Vec<&str> = key.split(SCOPE_SEPARATOR).collect();
let key: String = if parts.len() == 1 {
// we got a key like "foo", turn it into "<scope>$foo"
fallback_scope.to_string() + SCOPE_SEPARATOR + key
} else if parts.len() > 1 {
// we got a key with at least one "$"
// extract anything before the last "$":
let scope_part: String = parts[0..parts.len() - 2].join(SCOPE_SEPARATOR);
if scope_part.is_empty() {
// we got a key like "$foo", just prefix the fallback scope
fallback_scope.to_string() + key
}
else {
// we got a key like "Ke$ha$foo" or "$$foo" (which is the convention for
// global variables), leave the scope intact
key.to_string()
}
2024-04-14 14:20:51 +00:00
} else {
// we got an empty string. this is bad, but handle gracefully
fallback_scope.to_string() + SCOPE_SEPARATOR
2024-04-14 14:20:51 +00:00
};
return key.to_lowercase();
}
pub fn set_in_scope(&mut self, fallback_scope: &str, key: &str, value: String) {
let key = Self::normalize_varname(fallback_scope, key);
2024-04-14 14:20:51 +00:00
self.db.insert(key, value);
2024-04-14 13:37:36 +00:00
}
pub fn evaluate_condition(&self, condition: &str, scope: &str) -> bool {
let parts: Vec<&str> = condition.split(" ").collect();
if parts.len() == 0 {
// Got an empty string, this is always false.
return false;
} else if parts.len() == 1 {
// Got something like "if $somevar:".
// Check whether the variable evaluates to true.
let part = parts[0];
let (part, negate) = if part.starts_with(TOKEN_NEGATE) {
(&part[1..], true)
} else {
(part, false)
};
if part.contains(SCOPE_SEPARATOR) {
let part = Self::normalize_varname(scope, part);
let value_bool = self.getb(part.as_str());
return value_bool ^ negate;
}
else {
return Self::evaluate_str_as_bool(part) ^ negate;
}
} else if parts.len() == 2 {
// Got something like "if $something somethingelse"
// Check whether the two are identical.
let mut left: String = parts[0].to_string();
if left.contains(SCOPE_SEPARATOR) {
left = self
.get(Self::normalize_varname(scope, left.as_str()).as_str())
.unwrap_or("".to_string());
}
let mut right: String = parts[1].to_string();
if right.contains(SCOPE_SEPARATOR) {
right = self
.get(Self::normalize_varname(scope, right.as_str()).as_str())
.unwrap_or("".to_string());
}
return left == right;
} else {
// Got something like "if $something != somethingelse bla bla"
let mut left: String = parts[0].to_string();
if left.contains(SCOPE_SEPARATOR) {
left = self
.get(Self::normalize_varname(scope, left.as_str()).as_str())
.unwrap_or("".to_string());
}
let mut right: String = parts[2..parts.len()].join(" ").to_string();
if right.contains(SCOPE_SEPARATOR) {
right = self
.get(Self::normalize_varname(scope, right.as_str()).as_str())
.unwrap_or("".to_string());
}
let floats = (left.parse::<f64>(), right.parse::<f64>());
let operator: &str = parts[1];
match operator {
TOKEN_EQUALS => {
if let (Ok(left), Ok(right)) = floats {
return left == right;
}
return left == right;
}
TOKEN_EQUALS_NOT => {
if let (Ok(left), Ok(right)) = floats {
return left != right;
}
return left != right;
}
TOKEN_GREATER_THAN => {
if let (Ok(left), Ok(right)) = floats {
return left > right;
}
return false;
}
TOKEN_GREATER_EQUALS => {
if let (Ok(left), Ok(right)) = floats {
return left >= right;
}
return false;
}
TOKEN_LESS_THAN => {
if let (Ok(left), Ok(right)) = floats {
return left < right;
}
return false;
}
TOKEN_LESS_EQUALS => {
if let (Ok(left), Ok(right)) = floats {
return left <= right;
}
return false;
}
_ => {
error!("Unknown operator '{operator}' in if-condition!");
return false;
}
}
}
}
2024-04-14 13:37:36 +00:00
}
2024-05-13 18:21:56 +00:00
#[derive(Resource, Default)]
pub struct CommandLineOptions {
pub window_mode_fullscreen: WindowMode,
pub window_mode_initial: WindowMode,
pub use_gl: bool,
}