Compare commits
13 commits
a670778fb0
...
2e57f911ed
Author | SHA1 | Date | |
---|---|---|---|
yuni | 2e57f911ed | ||
yuni | d21f8b4b09 | ||
yuni | 011938cadf | ||
yuni | 00df7bc711 | ||
yuni | d51333274b | ||
yuni | d6901bef00 | ||
yuni | a13264a404 | ||
yuni | b4ff95c3be | ||
yuni | 5df3f66ea6 | ||
yuni | 07be89162c | ||
yuni | 7b6b14a992 | ||
yuni | 600f9d5e3e | ||
yuni | 86cd3b049e |
|
@ -2,7 +2,7 @@ use bevy::prelude::*;
|
|||
use bevy_xpbd_3d::prelude::*;
|
||||
use bevy::scene::SceneInstance;
|
||||
use bevy::math::DVec3;
|
||||
use crate::{actor, audio, camera, chat, commands, effects, hud, nature, settings, world};
|
||||
use crate::{actor, audio, camera, chat, commands, effects, hud, nature, var, world};
|
||||
|
||||
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
||||
const MAX_TRANSMISSION_DISTANCE: f32 = 60.0;
|
||||
|
@ -234,7 +234,7 @@ pub fn update_physics_lifeforms(
|
|||
pub fn handle_input(
|
||||
mut commands: Commands,
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
q_talker: Query<(&chat::Talker, &Transform), (Without<actor::Player>, Without<Camera>)>,
|
||||
player: Query<Entity, With<actor::Player>>,
|
||||
q_camera: Query<&Transform, With<Camera>>,
|
||||
|
@ -424,7 +424,7 @@ fn handle_player_death(
|
|||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
mut ew_effect: EventWriter<effects::SpawnEffectEvent>,
|
||||
mut log: ResMut<hud::Log>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
) {
|
||||
for death in er_playerdies.read() {
|
||||
if settings.god_mode {
|
||||
|
@ -472,7 +472,7 @@ fn handle_player_death(
|
|||
fn handle_damage(
|
||||
mut ew_playerdies: EventWriter<PlayerDiesEvent>,
|
||||
mut q_hp: Query<(&mut HitPoints, Option<&Player>), Changed<HitPoints>>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
) {
|
||||
for (mut hp, player_maybe) in &mut q_hp {
|
||||
if player_maybe.is_some() {
|
||||
|
|
10
src/audio.rs
10
src/audio.rs
|
@ -1,6 +1,6 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy::audio::{PlaybackMode, Volume};
|
||||
use crate::settings;
|
||||
use crate::var;
|
||||
|
||||
const ASSET_CLICK: &str = "sounds/click-button-140881-crop.ogg";
|
||||
const ASSET_SWITCH: &str = "sounds/typosonic-typing-192811-crop.ogg";
|
||||
|
@ -59,7 +59,7 @@ pub enum Sfx {
|
|||
|
||||
pub fn setup(
|
||||
mut commands: Commands,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
commands.spawn((
|
||||
|
@ -132,7 +132,7 @@ pub fn toggle_bgm(
|
|||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut evwriter_toggle: EventWriter<ToggleMusicEvent>,
|
||||
mut evwriter_sfx: EventWriter<PlaySfxEvent>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
) {
|
||||
if keyboard_input.just_pressed(KeyCode::KeyT) {
|
||||
settings.mute_music ^= true;
|
||||
|
@ -148,7 +148,7 @@ pub fn toggle_bgm(
|
|||
|
||||
pub fn play_sfx(
|
||||
mut commands: Commands,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut events_sfx: EventReader<PlaySfxEvent>,
|
||||
sound_click: Res<SoundClick>,
|
||||
sound_switch: Res<SoundSwitch>,
|
||||
|
@ -200,7 +200,7 @@ pub fn str2sfx(sfx_label: &str) -> Sfx {
|
|||
pub fn update_music(
|
||||
mut events: EventReader<ToggleMusicEvent>,
|
||||
bgm_controller: Query<&AudioSink, With<ComponentBGM>>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
) {
|
||||
if !events.is_empty() {
|
||||
events.clear();
|
||||
|
|
|
@ -8,7 +8,7 @@ use bevy::transform::TransformSystem;
|
|||
use bevy::math::{DVec3, DQuat};
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use std::f32::consts::PI;
|
||||
use crate::{actor, audio, hud, settings};
|
||||
use crate::{actor, audio, hud, var};
|
||||
|
||||
pub struct CameraPlugin;
|
||||
|
||||
|
@ -68,7 +68,7 @@ pub fn setup_camera(
|
|||
}
|
||||
|
||||
pub fn sync_camera_to_player(
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut q_camera: Query<&mut Transform, (With<Camera>, Without<actor::PlayerCamera>)>,
|
||||
q_playercam: Query<(&actor::Actor, &Transform), (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||
) {
|
||||
|
@ -93,7 +93,7 @@ pub fn sync_camera_to_player(
|
|||
pub fn update_fov(
|
||||
q_player: Query<&actor::ExperiencesGForce, With<actor::Player>>,
|
||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
mut q_camera: Query<&mut Projection, With<Camera>>,
|
||||
) {
|
||||
if let (Ok(gforce), Ok(mut projection)) = (q_player.get_single(), q_camera.get_single_mut())
|
||||
|
@ -116,7 +116,7 @@ pub fn update_fov(
|
|||
|
||||
pub fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
) {
|
||||
if keyboard_input.just_pressed(settings.key_camera) {
|
||||
|
@ -129,7 +129,7 @@ pub fn handle_input(
|
|||
}
|
||||
|
||||
fn manage_player_actor(
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut q_playercam: Query<&mut Visibility, With<actor::PlayerCamera>>,
|
||||
mut q_hiddenplayer: Query<(&mut Visibility, &mut Position, &mut Rotation, &mut LinearVelocity, &mut AngularVelocity), (With<actor::Player>, Without<actor::PlayerCamera>)>,
|
||||
q_ride: Query<(&Transform, &Position, &Rotation, &LinearVelocity, &AngularVelocity), (With<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
||||
|
@ -161,7 +161,7 @@ fn manage_player_actor(
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn apply_input_to_player(
|
||||
time: Res<Time>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
windows: Query<&Window, With<PrimaryWindow>>,
|
||||
mut mouse_events: EventReader<MouseMotion>,
|
||||
key_input: Res<ButtonInput<KeyCode>>,
|
||||
|
|
190
src/chat.rs
190
src/chat.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::{actor, audio, hud, settings, world, effects};
|
||||
use crate::{actor, audio, effects, hud, var, world};
|
||||
use bevy::prelude::*;
|
||||
use bevy::math::DVec3;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
|
@ -18,6 +18,7 @@ pub const TOKEN_WARN: &str = "warn";
|
|||
pub const TOKEN_SLEEP: &str = "sleep";
|
||||
pub const TOKEN_SET: &str = "set";
|
||||
pub const TOKEN_IF: &str = "if";
|
||||
pub const TOKEN_THEN: &str = "then";
|
||||
pub const TOKEN_GOTO: &str = "goto";
|
||||
pub const TOKEN_LABEL: &str = "label";
|
||||
pub const TOKEN_SCRIPT: &str = "script";
|
||||
|
@ -26,13 +27,14 @@ pub const TOKEN_NOWAIT: &str = "nowait";
|
|||
|
||||
pub const TOKEN_INCLUDE: &str = "include";
|
||||
pub const TOKEN_GOTO_EXIT: &str = "EXIT";
|
||||
pub const TOKEN_IF_INLINE: &str = "if "; // for lines like `- if foo:`
|
||||
|
||||
pub const DEFAULT_SOUND: &str = "chat";
|
||||
pub const MAX_BRANCH_DEPTH: usize = 64;
|
||||
|
||||
pub const CHOICE_TIMER: f64 = 40.0 * settings::DEFAULT_CHAT_SPEED as f64;
|
||||
pub const CHOICE_TIMER: f64 = 40.0 * var::DEFAULT_CHAT_SPEED as f64;
|
||||
pub const LETTERS_PER_SECOND: f32 = 17.0;
|
||||
pub const TALKER_SPEED_FACTOR: f32 = settings::DEFAULT_CHAT_SPEED / LETTERS_PER_SECOND;
|
||||
pub const TALKER_SPEED_FACTOR: f32 = var::DEFAULT_CHAT_SPEED / LETTERS_PER_SECOND;
|
||||
pub const CHAT_SPEED_MIN_LEN: f32 = 40.0;
|
||||
|
||||
pub const NON_CHOICE_TOKENS: &[&str] = &[
|
||||
|
@ -43,6 +45,7 @@ pub const NON_CHOICE_TOKENS: &[&str] = &[
|
|||
TOKEN_SLEEP,
|
||||
TOKEN_SET,
|
||||
TOKEN_IF,
|
||||
TOKEN_THEN,
|
||||
TOKEN_GOTO,
|
||||
TOKEN_LABEL,
|
||||
TOKEN_SCRIPT,
|
||||
|
@ -78,7 +81,7 @@ type ChatPos = Vec<usize>;
|
|||
|
||||
#[derive(Component)]
|
||||
pub struct Chat {
|
||||
pub id: usize,
|
||||
pub internal_id: usize,
|
||||
pub position: ChatPos,
|
||||
pub timer: f64,
|
||||
pub talker: Talker,
|
||||
|
@ -94,7 +97,8 @@ pub struct Choice {
|
|||
#[derive(Component)]
|
||||
#[derive(Clone)]
|
||||
pub struct Talker {
|
||||
pub conv_id: String,
|
||||
pub chat_name: String,
|
||||
pub actor_id: String,
|
||||
pub name: Option<String>,
|
||||
pub pronoun: Option<String>,
|
||||
pub talking_speed: f32,
|
||||
|
@ -113,12 +117,29 @@ pub enum ChatEvent {
|
|||
DespawnAllChoices,
|
||||
DespawnAllChats,
|
||||
SpawnMessage(String, hud::LogLevel, String),
|
||||
SpawnChoice(String, usize, ChatPos, bool),
|
||||
SpawnChoice(String, usize, ChatPos, bool, Option<String>),
|
||||
RunScript(String),
|
||||
Sleep(f64),
|
||||
//Script(String, String, String),
|
||||
SleepSeconds(f64),
|
||||
SetVariable(String),
|
||||
GotoIf(String, ChatPos),
|
||||
}
|
||||
|
||||
pub struct Extracted {
|
||||
choice_text: Option<String>,
|
||||
nowait: bool,
|
||||
condition: Option<String>,
|
||||
}
|
||||
impl Default for Extracted {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
choice_text: None,
|
||||
nowait: false,
|
||||
condition: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is the only place where any YAML interaction should be happening.
|
||||
#[derive(Resource)]
|
||||
pub struct ChatDB(Vec<Value>);
|
||||
|
@ -191,7 +212,9 @@ impl ChatDB {
|
|||
for (index, label) in changes {
|
||||
if index < vector.len() {
|
||||
vector.remove(index);
|
||||
vector.splice(index..index, include_db[&label].iter().cloned());
|
||||
if let Some(chat) = include_db.get(&label) {
|
||||
vector.splice(index..index, chat.iter().cloned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,25 +245,38 @@ impl ChatDB {
|
|||
// Not acceptable:
|
||||
// - `"What's up?"`
|
||||
// - `{"goto": "foo"}`
|
||||
// Returns (choice text, sub-conversation branch, nowait flag)
|
||||
fn search_choice(&self, yaml: Option<&Value>) -> Option<(String, Value, bool)> {
|
||||
fn is_choice(&self, yaml: Option<&Value>) -> bool {
|
||||
if let Some(data) = self.extract(yaml) {
|
||||
return data.choice_text.is_some();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn extract(&self, yaml: Option<&Value>) -> Option<Extracted> {
|
||||
let non_choice_tokens = NON_CHOICE_TOKENS.to_vec();
|
||||
let mut result: Option<(String, Value, bool)> = None;
|
||||
let mut nowait = false;
|
||||
if let Some(Value::Mapping(map)) = yaml {
|
||||
let mut result: Extracted = Extracted::default();
|
||||
for (key, value) in map {
|
||||
if let Value::String(key) = key {
|
||||
if key == TOKEN_NOWAIT && value.as_bool() == Some(true) {
|
||||
nowait = true;
|
||||
result.nowait = true;
|
||||
}
|
||||
if non_choice_tokens.contains(&key.as_str()) {
|
||||
continue;
|
||||
else if key == TOKEN_IF {
|
||||
if let Some(condition) = value.as_str() {
|
||||
result.condition = Some(condition.to_string());
|
||||
}
|
||||
}
|
||||
else if non_choice_tokens.contains(&key.as_str()) {
|
||||
// skip over the other non-choice tokens
|
||||
}
|
||||
else {
|
||||
result.choice_text = Some(key.to_string());
|
||||
}
|
||||
result = Some((key.into(), map[key].clone(), nowait));
|
||||
}
|
||||
}
|
||||
return Some(result);
|
||||
}
|
||||
return result;
|
||||
return None;
|
||||
}
|
||||
|
||||
fn search_label_recursively(&self, sequence: &Value, label: &String, mut pos: ChatPos) -> Option<ChatPos> {
|
||||
|
@ -296,7 +332,7 @@ impl ChatDB {
|
|||
let mut popped = false;
|
||||
let mut seek_past_dialog_choices = false;
|
||||
while chat.position.len() > 0 {
|
||||
match self.at(chat.id, &chat.position) {
|
||||
match self.at(chat.internal_id, &chat.position) {
|
||||
None => {
|
||||
chat.position.pop();
|
||||
popped = true;
|
||||
|
@ -307,7 +343,7 @@ impl ChatDB {
|
|||
}
|
||||
},
|
||||
Some(Value::Mapping(map)) => {
|
||||
if seek_past_dialog_choices && self.search_choice(Some(&Value::Mapping(map))).is_some() {
|
||||
if seek_past_dialog_choices && self.is_choice(Some(&Value::Mapping(map))) {
|
||||
// we just dropped out of a branch and ended up in a dialog
|
||||
// choice. let's seek past all the choices until we find
|
||||
// the next non-dialog-choice item.
|
||||
|
@ -348,12 +384,12 @@ impl ChatDB {
|
|||
result = Some(Value::String(value_string.into()));
|
||||
}
|
||||
Some(Value::Mapping(mapping)) => {
|
||||
if let Some((_choicetext, subconversation, _)) = self.search_choice(value) {
|
||||
result = Some(Value::Mapping(mapping.clone()));
|
||||
next_pointer = Some(subconversation);
|
||||
}
|
||||
else {
|
||||
result = Some(Value::Mapping(mapping.clone()));
|
||||
result = Some(Value::Mapping(mapping.clone()));
|
||||
for value in mapping.values() {
|
||||
if let Some(list) = value.as_sequence() {
|
||||
next_pointer = Some(Value::Sequence(list.clone()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
@ -379,7 +415,7 @@ impl ChatDB {
|
|||
// This includes flow control tokens like "goto", no-op tokens like "label",
|
||||
// but not something with a side effect like "script", and especially not "if".
|
||||
fn is_skippable(&self, chat: &mut Chat) -> bool {
|
||||
let current_item = self.at(chat.id, &chat.position);
|
||||
let current_item = self.at(chat.internal_id, &chat.position);
|
||||
if current_item.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
@ -405,7 +441,7 @@ impl ChatDB {
|
|||
chat: &mut Chat,
|
||||
event: &mut EventWriter<ChatEvent>,
|
||||
) -> bool {
|
||||
let current_item = self.at(chat.id, &chat.position);
|
||||
let current_item = self.at(chat.internal_id, &chat.position);
|
||||
let mut processed_a_choice = false;
|
||||
match current_item {
|
||||
Some(Value::String(message)) => {
|
||||
|
@ -416,7 +452,7 @@ impl ChatDB {
|
|||
let mut sound = DEFAULT_SOUND.to_string();
|
||||
|
||||
// Is this a dialog choice?
|
||||
if let Some(_) = self.search_choice(Some(&Value::Mapping(map.clone()))) {
|
||||
if self.is_choice(Some(&Value::Mapping(map.clone()))) {
|
||||
processed_a_choice = true;
|
||||
}
|
||||
|
||||
|
@ -427,12 +463,25 @@ impl ChatDB {
|
|||
for (key, value) in &map {
|
||||
let key = key.as_str();
|
||||
match (key, value) {
|
||||
(Some(TOKEN_IF), _) => {} // TODO
|
||||
(Some(TOKEN_IF), Value::String(condition)) => {
|
||||
let mut pos = chat.position.clone();
|
||||
pos.push(0);
|
||||
event.send(ChatEvent::GotoIf(condition.into(), pos));
|
||||
}
|
||||
(Some(TOKEN_SOUND), Value::String(sound_name)) => {
|
||||
sound = sound_name.clone();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(key) = key {
|
||||
if key.starts_with(TOKEN_IF_INLINE) {
|
||||
let condition: &str = &key[TOKEN_IF_INLINE.len()..];
|
||||
let mut pos = chat.position.clone();
|
||||
pos.push(0);
|
||||
event.send(ChatEvent::GotoIf(condition.into(), pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass
|
||||
|
@ -451,7 +500,9 @@ impl ChatDB {
|
|||
event.send(ChatEvent::SpawnMessage(
|
||||
message.to_string(), hud::LogLevel::Warning, sound.clone()));
|
||||
}
|
||||
(Some(TOKEN_SET), _) => {} // TODO
|
||||
(Some(TOKEN_SET), Value::String(instructions)) => {
|
||||
event.send(ChatEvent::SetVariable(instructions.to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -462,11 +513,11 @@ impl ChatDB {
|
|||
match (key, value) {
|
||||
(Some(TOKEN_SLEEP), Value::Number(time)) => {
|
||||
if let Some(time_f64) = time.as_f64() {
|
||||
event.send(ChatEvent::Sleep(time_f64));
|
||||
event.send(ChatEvent::SleepSeconds(time_f64));
|
||||
}
|
||||
}
|
||||
(Some(TOKEN_GOTO), Value::String(label)) => {
|
||||
match self.search_label(chat.id, &label) {
|
||||
match self.search_label(chat.internal_id, &label) {
|
||||
Some(pos) => {
|
||||
chat.position = pos;
|
||||
}
|
||||
|
@ -517,16 +568,21 @@ impl ChatDB {
|
|||
// Spawn choices until we reach a non-choice item or the end of the branch
|
||||
let mut key: usize = 0;
|
||||
let mut reached_end_of_branch = false;
|
||||
while let Some((choice, _, nowait)) =
|
||||
self.search_choice(self.at(chat.id, &chat.position).as_ref()) {
|
||||
if reached_end_of_branch {
|
||||
while let Some(data) = self.extract(self.at(chat.internal_id, &chat.position).as_ref()) {
|
||||
if let Some(choice_text) = data.choice_text {
|
||||
if reached_end_of_branch {
|
||||
break;
|
||||
}
|
||||
let mut goto: Vec<usize> = chat.position.clone();
|
||||
goto.push(0);
|
||||
event.send(ChatEvent::SpawnChoice(choice_text,
|
||||
key, goto, data.nowait, data.condition));
|
||||
key += 1;
|
||||
reached_end_of_branch = self.advance_pointer(chat);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
let mut goto: Vec<usize> = chat.position.clone();
|
||||
goto.push(0);
|
||||
event.send(ChatEvent::SpawnChoice(choice, key, goto, nowait));
|
||||
key += 1;
|
||||
reached_end_of_branch = self.advance_pointer(chat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -555,10 +611,10 @@ pub fn handle_new_conversations(
|
|||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Ping));
|
||||
return;
|
||||
}
|
||||
match (*chatdb).get_chat_by_id(&event.talker.conv_id) {
|
||||
match (*chatdb).get_chat_by_id(&event.talker.chat_name) {
|
||||
Ok(chat_id) => {
|
||||
let mut chat = Chat {
|
||||
id: chat_id,
|
||||
internal_id: chat_id,
|
||||
position: vec![0],
|
||||
timer: time.elapsed_seconds_f64(),
|
||||
talker: event.talker.clone(),
|
||||
|
@ -596,10 +652,11 @@ pub fn handle_chat_events(
|
|||
mut ew_chatscript: EventWriter<ChatScriptEvent>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
mut log: ResMut<hud::Log>,
|
||||
mut vars: ResMut<var::GameVars>,
|
||||
q_choices: Query<Entity, With<Choice>>,
|
||||
mut q_chats: Query<(Entity, &mut Chat)>,
|
||||
time: Res<Time>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
) {
|
||||
for event in er_chatevent.read() {
|
||||
let now = time.elapsed_seconds_f64();
|
||||
|
@ -635,35 +692,54 @@ pub fn handle_chat_events(
|
|||
let sfx = audio::str2sfx(sound);
|
||||
ew_sfx.send(audio::PlaySfxEvent(sfx));
|
||||
}
|
||||
ChatEvent::SpawnChoice(replytext, key, goto, nowait) => {
|
||||
commands.spawn((
|
||||
world::DespawnOnPlayerDeath,
|
||||
Choice {
|
||||
text: replytext.into(),
|
||||
key: *key,
|
||||
goto: goto.clone(),
|
||||
ChatEvent::SpawnChoice(replytext, key, goto, nowait, condition) => {
|
||||
'out: {
|
||||
dbg!(condition);
|
||||
if let Some(condition) = condition {
|
||||
if !vars.evaluate_condition(condition, &chat.talker.actor_id) {
|
||||
break 'out;
|
||||
}
|
||||
}
|
||||
commands.spawn((
|
||||
world::DespawnOnPlayerDeath,
|
||||
Choice {
|
||||
text: replytext.into(),
|
||||
key: *key,
|
||||
goto: goto.clone(),
|
||||
}
|
||||
));
|
||||
if !nowait {
|
||||
chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64;
|
||||
}
|
||||
));
|
||||
if !nowait {
|
||||
chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64;
|
||||
}
|
||||
}
|
||||
ChatEvent::RunScript(script) => {
|
||||
ew_chatscript.send(ChatScriptEvent(script.clone()));
|
||||
}
|
||||
ChatEvent::Sleep(sleep_duration) => {
|
||||
ChatEvent::SleepSeconds(sleep_duration) => {
|
||||
chat.timer = now + sleep_duration;
|
||||
}
|
||||
ChatEvent::SetVariable(string) => {
|
||||
if let Some((key, value)) = string.split_once(" ") {
|
||||
vars.set_in_scope(&chat.talker.actor_id, key, value.into());
|
||||
} else {
|
||||
vars.set_in_scope(&chat.talker.actor_id, string, "".into());
|
||||
}
|
||||
}
|
||||
ChatEvent::GotoIf(condition, goto) => {
|
||||
if vars.evaluate_condition(condition, &chat.talker.actor_id) {
|
||||
chat.position = goto.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_reply_keys(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
settings: ResMut<settings::Settings>,
|
||||
settings: ResMut<var::Settings>,
|
||||
q_choices: Query<&Choice>,
|
||||
mut q_chats: Query<&mut Chat>,
|
||||
//mut evwriter_sendmsg: EventWriter<SendMessageEvent>,
|
||||
mut evwriter_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
|
|
|
@ -17,7 +17,12 @@
|
|||
|
||||
|
||||
- chat: Icarus
|
||||
- if $met:
|
||||
- Oh hey, you're back!
|
||||
- How are you doing?
|
||||
- goto: howru
|
||||
- Oh hey, you're awake!
|
||||
- set: $met
|
||||
- I found you drifting out cold, and thought, I better watch over you.
|
||||
- Took us here behind that moonlet, to shield you from the micros.
|
||||
- Thank you!:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
|
||||
- chat: ClippyTransSerenity
|
||||
- set: busstop serenity
|
||||
- set: $busstop serenity
|
||||
- Welcome at StarTrans Cargo Services! You have reached Serenity Station.
|
||||
- "Ready for a trip? Available bus stops: Oscillation Station, Metis Prime Station"
|
||||
- label: startransbusstop
|
||||
|
@ -21,7 +21,7 @@
|
|||
|
||||
|
||||
- chat: ClippyTransMetis
|
||||
- set: busstop metis
|
||||
- set: $busstop metis
|
||||
- Welcome at StarTrans Cargo Services! You have reached Metis Prime Station.
|
||||
- "Ready for a trip? Available bus stops: Oscillation Station, Serenity Station"
|
||||
- label: startransbusstop
|
||||
|
@ -36,7 +36,7 @@
|
|||
|
||||
|
||||
- chat: ClippyTransOscillation
|
||||
- set: busstop oscillation
|
||||
- set: $busstop oscillation
|
||||
- Welcome at StarTrans Cargo Services! You have reached Oscillation Station.
|
||||
- "Ready for a trip? Available bus stops: Serenity Station, Metis Prime Station"
|
||||
- label: startransbusstop
|
||||
|
@ -57,21 +57,21 @@
|
|||
- Can I take a spacecraft with me?:
|
||||
- Absolutely.
|
||||
- goto: startransbusstop
|
||||
- if: busstop != "oscillation"
|
||||
- if: $busstop != oscillation
|
||||
Take me to Oscillation Station, please.:
|
||||
- StarTrans wishes you a pleasant journey.
|
||||
- script: cryofadeout
|
||||
- sleep: 5
|
||||
- script: cryotrip oscillation
|
||||
- goto: EXIT
|
||||
- if: busstop != "metis"
|
||||
- if: $busstop != metis
|
||||
Take me to Metis Prime Station, please.:
|
||||
- StarTrans wishes you a pleasant journey.
|
||||
- script: cryofadeout
|
||||
- sleep: 5
|
||||
- script: cryotrip metisprime
|
||||
- goto: EXIT
|
||||
- if: busstop != "serenity"
|
||||
- if: $busstop != serenity
|
||||
Take me to Serenity Station, please.:
|
||||
- StarTrans wishes you a pleasant journey.
|
||||
- script: cryofadeout
|
||||
|
|
|
@ -692,7 +692,8 @@ fn spawn_entities(
|
|||
}
|
||||
if !state.chat.is_empty() {
|
||||
actor.insert(chat::Talker {
|
||||
conv_id: state.chat.clone(),
|
||||
actor_id: state.id.clone(),
|
||||
chat_name: state.chat.clone(),
|
||||
name: state.name.clone(),
|
||||
pronoun: Some(state.pronoun.clone()),
|
||||
talking_speed: 1.0,
|
||||
|
|
|
@ -199,6 +199,7 @@ actor -3300 10 0 pizzeria
|
|||
actor 60 -15 -40 suit
|
||||
relativeto player
|
||||
name Icarus
|
||||
id Icarus
|
||||
chatid Icarus
|
||||
alive yes
|
||||
scale 2
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::prelude::*;
|
||||
use crate::{camera, settings};
|
||||
use crate::{camera, var};
|
||||
|
||||
pub struct EffectsPlugin;
|
||||
|
||||
|
@ -40,7 +40,7 @@ pub struct SpawnEffectEvent {
|
|||
}
|
||||
|
||||
pub fn setup(
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut ew_effect: EventWriter<SpawnEffectEvent>,
|
||||
) {
|
||||
if !settings.dev_mode {
|
||||
|
|
14
src/hud.rs
14
src/hud.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::{actor, audio, camera, chat, nature, settings, world};
|
||||
use crate::{actor, audio, camera, chat, nature, var, world};
|
||||
use bevy::prelude::*;
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
use bevy::transform::TransformSystem;
|
||||
|
@ -151,7 +151,7 @@ impl Log {
|
|||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut log: ResMut<Log>,
|
||||
mut ambient_light: ResMut<AmbientLight>,
|
||||
|
@ -414,7 +414,7 @@ fn update_hud(
|
|||
q_choices: Query<&chat::Choice>,
|
||||
mut query_chat: Query<&mut Text, (With<ChatText>, Without<GaugesText>)>,
|
||||
query_all_actors: Query<&actor::Actor>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
q_target: Query<(&IsClickable, Option<&Position>, Option<&LinearVelocity>), With<IsTargeted>>,
|
||||
) {
|
||||
// TODO only when hud is actually on
|
||||
|
@ -563,7 +563,7 @@ fn update_hud(
|
|||
fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
mut q_hud: Query<(&mut Visibility, Option<&OnlyHideWhenTogglingHud>), With<ToggleableHudElement>>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
||||
|
@ -607,7 +607,7 @@ fn handle_input(
|
|||
|
||||
fn handle_target_event(
|
||||
mut commands: Commands,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut er_target: EventReader<TargetEvent>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
q_target: Query<Entity, With<IsTargeted>>,
|
||||
|
@ -631,7 +631,7 @@ fn handle_target_event(
|
|||
}
|
||||
|
||||
fn update_target_selectagon(
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut q_selectagon: Query<(&mut Transform, &mut Visibility), (With<Selectagon>, Without<IsTargeted>, Without<Camera>)>,
|
||||
q_target: Query<&Transform, (With<IsTargeted>, Without<Camera>, Without<Selectagon>)>,
|
||||
q_camera: Query<&Transform, (With<Camera>, Without<IsTargeted>, Without<Selectagon>)>,
|
||||
|
@ -671,7 +671,7 @@ fn update_target_selectagon(
|
|||
fn update_ar_overlays (
|
||||
q_owners: Query<(Entity, &Transform, &Visibility), (With<AugmentedRealityOverlayBroadcaster>, Without<AugmentedRealityOverlay>)>,
|
||||
mut q_overlays: Query<(&mut Transform, &mut Visibility, &mut AugmentedRealityOverlay)>,
|
||||
settings: ResMut<settings::Settings>,
|
||||
settings: ResMut<var::Settings>,
|
||||
mut state: ResMut<AugmentedRealityState>,
|
||||
) {
|
||||
let (need_activate, need_clean, need_update);
|
||||
|
|
|
@ -5,8 +5,8 @@ mod chat;
|
|||
mod commands;
|
||||
mod effects;
|
||||
mod hud;
|
||||
mod settings;
|
||||
mod stars;
|
||||
mod var;
|
||||
mod world;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -47,7 +47,8 @@ impl Plugin for OutFlyPlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, handle_input);
|
||||
app.insert_resource(settings::Settings::default());
|
||||
app.insert_resource(var::Settings::default());
|
||||
app.insert_resource(var::GameVars::default());
|
||||
app.add_plugins((
|
||||
DefaultPlugins,//.set(ImagePlugin::default_nearest()),
|
||||
FrameTimeDiagnosticsPlugin,
|
||||
|
@ -77,7 +78,7 @@ fn setup(
|
|||
|
||||
fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
settings: Res<settings::Settings>,
|
||||
settings: Res<var::Settings>,
|
||||
mut app_exit_events: ResMut<Events<bevy::app::AppExit>>,
|
||||
mut windows: Query<&mut Window, With<PrimaryWindow>>,
|
||||
) {
|
||||
|
|
190
src/settings.rs
190
src/settings.rs
|
@ -1,190 +0,0 @@
|
|||
use bevy::prelude::*;
|
||||
use std::env;
|
||||
|
||||
pub const DEFAULT_CHAT_SPEED: f32 = 10.0;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct Settings {
|
||||
pub dev_mode: bool,
|
||||
pub god_mode: bool,
|
||||
pub mute_sfx: bool,
|
||||
pub mute_music: bool,
|
||||
pub volume_sfx: u8,
|
||||
pub volume_music: u8,
|
||||
pub mouse_sensitivity: f32,
|
||||
pub fov: f32,
|
||||
pub fov_highspeed: f32,
|
||||
pub zoom_fov: f32,
|
||||
pub zoom_sensitivity_factor: f32,
|
||||
pub font_size_hud: f32,
|
||||
pub font_size_conversations: f32,
|
||||
pub chat_speed: f32,
|
||||
pub hud_active: bool,
|
||||
pub is_zooming: bool,
|
||||
pub third_person: bool,
|
||||
pub rotation_stabilizer_active: bool,
|
||||
pub key_selectobject: MouseButton,
|
||||
pub key_zoom: MouseButton,
|
||||
pub key_togglehud: KeyCode,
|
||||
pub key_exit: KeyCode,
|
||||
pub key_restart: KeyCode,
|
||||
pub key_fullscreen: KeyCode,
|
||||
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_rotate: KeyCode,
|
||||
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,
|
||||
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,
|
||||
pub key_cheat_god_mode: KeyCode,
|
||||
pub key_cheat_stop: KeyCode,
|
||||
pub key_cheat_speed: KeyCode,
|
||||
pub key_cheat_speed_backward: KeyCode,
|
||||
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,
|
||||
pub key_cheat_die: KeyCode,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
let dev_mode;
|
||||
|
||||
let default_mute_sfx = false;
|
||||
let default_mute_music;
|
||||
if let Ok(_) = env::var("CARGO") {
|
||||
// Mute audio by default when run through `cargo`
|
||||
default_mute_music = cfg!(debug_assertions);
|
||||
|
||||
// Enable dev mode when running `cargo run` without `--release`
|
||||
dev_mode = cfg!(debug_assertions);
|
||||
}
|
||||
else {
|
||||
default_mute_music = false;
|
||||
dev_mode = false;
|
||||
}
|
||||
|
||||
Settings {
|
||||
dev_mode,
|
||||
god_mode: false,
|
||||
mute_sfx: default_mute_sfx,
|
||||
mute_music: default_mute_music,
|
||||
volume_sfx: 100,
|
||||
volume_music: 100,
|
||||
mouse_sensitivity: 0.7,
|
||||
fov: 50.0,
|
||||
fov_highspeed: 25.0,
|
||||
zoom_fov: 15.0,
|
||||
zoom_sensitivity_factor: 0.25,
|
||||
font_size_hud: 32.0,
|
||||
font_size_conversations: 32.0,
|
||||
chat_speed: DEFAULT_CHAT_SPEED,
|
||||
hud_active: false,
|
||||
is_zooming: false,
|
||||
third_person: false,
|
||||
rotation_stabilizer_active: true,
|
||||
key_selectobject: MouseButton::Left,
|
||||
key_zoom: MouseButton::Right,
|
||||
key_togglehud: KeyCode::Tab,
|
||||
key_exit: KeyCode::Escape,
|
||||
key_restart: KeyCode::F7,
|
||||
key_fullscreen: KeyCode::F11,
|
||||
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,
|
||||
key_camera: KeyCode::KeyF,
|
||||
key_rotate: KeyCode::KeyR,
|
||||
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,
|
||||
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,
|
||||
key_cheat_god_mode: KeyCode::KeyG,
|
||||
key_cheat_stop: KeyCode::KeyC,
|
||||
key_cheat_speed: KeyCode::KeyV,
|
||||
key_cheat_speed_backward: KeyCode::KeyB,
|
||||
key_cheat_pizza: KeyCode::F9,
|
||||
key_cheat_farview1: KeyCode::F10,
|
||||
key_cheat_farview2: KeyCode::F12,
|
||||
key_cheat_adrenaline_zero: KeyCode::F5,
|
||||
key_cheat_adrenaline_mid: KeyCode::F6,
|
||||
key_cheat_adrenaline_max: KeyCode::F8,
|
||||
key_cheat_die: KeyCode::KeyZ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(&mut self) {
|
||||
println!("Resetting settings!");
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
385
src/var.rs
Normal file
385
src/var.rs
Normal file
|
@ -0,0 +1,385 @@
|
|||
use bevy::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
||||
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 DEFAULT_CHAT_SPEED: f32 = 10.0;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct Settings {
|
||||
pub dev_mode: bool,
|
||||
pub god_mode: bool,
|
||||
pub mute_sfx: bool,
|
||||
pub mute_music: bool,
|
||||
pub volume_sfx: u8,
|
||||
pub volume_music: u8,
|
||||
pub mouse_sensitivity: f32,
|
||||
pub fov: f32,
|
||||
pub fov_highspeed: f32,
|
||||
pub zoom_fov: f32,
|
||||
pub zoom_sensitivity_factor: f32,
|
||||
pub font_size_hud: f32,
|
||||
pub font_size_conversations: f32,
|
||||
pub chat_speed: f32,
|
||||
pub hud_active: bool,
|
||||
pub is_zooming: bool,
|
||||
pub third_person: bool,
|
||||
pub rotation_stabilizer_active: bool,
|
||||
pub key_selectobject: MouseButton,
|
||||
pub key_zoom: MouseButton,
|
||||
pub key_togglehud: KeyCode,
|
||||
pub key_exit: KeyCode,
|
||||
pub key_restart: KeyCode,
|
||||
pub key_fullscreen: KeyCode,
|
||||
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_rotate: KeyCode,
|
||||
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,
|
||||
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,
|
||||
pub key_cheat_god_mode: KeyCode,
|
||||
pub key_cheat_stop: KeyCode,
|
||||
pub key_cheat_speed: KeyCode,
|
||||
pub key_cheat_speed_backward: KeyCode,
|
||||
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,
|
||||
pub key_cheat_die: KeyCode,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
let dev_mode;
|
||||
|
||||
let default_mute_sfx = false;
|
||||
let default_mute_music;
|
||||
if let Ok(_) = env::var("CARGO") {
|
||||
// Mute audio by default when run through `cargo`
|
||||
default_mute_music = cfg!(debug_assertions);
|
||||
|
||||
// Enable dev mode when running `cargo run` without `--release`
|
||||
dev_mode = cfg!(debug_assertions);
|
||||
}
|
||||
else {
|
||||
default_mute_music = false;
|
||||
dev_mode = false;
|
||||
}
|
||||
|
||||
Settings {
|
||||
dev_mode,
|
||||
god_mode: false,
|
||||
mute_sfx: default_mute_sfx,
|
||||
mute_music: default_mute_music,
|
||||
volume_sfx: 100,
|
||||
volume_music: 100,
|
||||
mouse_sensitivity: 0.7,
|
||||
fov: 50.0,
|
||||
fov_highspeed: 25.0,
|
||||
zoom_fov: 15.0,
|
||||
zoom_sensitivity_factor: 0.25,
|
||||
font_size_hud: 32.0,
|
||||
font_size_conversations: 32.0,
|
||||
chat_speed: DEFAULT_CHAT_SPEED,
|
||||
hud_active: false,
|
||||
is_zooming: false,
|
||||
third_person: false,
|
||||
rotation_stabilizer_active: true,
|
||||
key_selectobject: MouseButton::Left,
|
||||
key_zoom: MouseButton::Right,
|
||||
key_togglehud: KeyCode::Tab,
|
||||
key_exit: KeyCode::Escape,
|
||||
key_restart: KeyCode::F7,
|
||||
key_fullscreen: KeyCode::F11,
|
||||
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,
|
||||
key_camera: KeyCode::KeyF,
|
||||
key_rotate: KeyCode::KeyR,
|
||||
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,
|
||||
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,
|
||||
key_cheat_god_mode: KeyCode::KeyG,
|
||||
key_cheat_stop: KeyCode::KeyC,
|
||||
key_cheat_speed: KeyCode::KeyV,
|
||||
key_cheat_speed_backward: KeyCode::KeyB,
|
||||
key_cheat_pizza: KeyCode::F9,
|
||||
key_cheat_farview1: KeyCode::F10,
|
||||
key_cheat_farview2: KeyCode::F12,
|
||||
key_cheat_adrenaline_zero: KeyCode::F5,
|
||||
key_cheat_adrenaline_mid: KeyCode::F6,
|
||||
key_cheat_adrenaline_max: KeyCode::F8,
|
||||
key_cheat_die: KeyCode::KeyZ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(&mut self) {
|
||||
println!("Resetting settings!");
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct GameVars {
|
||||
pub db: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for GameVars {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
db: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameVars {
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, key: &str) -> Option<String> {
|
||||
if let Some(value) = self.db.get(key) {
|
||||
return Some(value.clone());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn getf(&self, key: &str) -> Option<f64> {
|
||||
if let Some(value) = self.db.get(key) {
|
||||
if let Ok(float) = value.parse::<f64>() {
|
||||
return Some(float);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn getb(&self, key: &str) -> bool {
|
||||
if let Some(value) = self.db.get(key) {
|
||||
return Self::evaluate_str_as_bool(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn evaluate_str_as_bool(string: &str) -> bool {
|
||||
return string != "0";
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
} else {
|
||||
// we got an empty string. this is bad, but handle gracefully
|
||||
fallback_scope.to_string() + SCOPE_SEPARATOR
|
||||
};
|
||||
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);
|
||||
self.db.insert(key, value);
|
||||
}
|
||||
|
||||
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];
|
||||
if part.contains(SCOPE_SEPARATOR) {
|
||||
let part = Self::normalize_varname(scope, part);
|
||||
let value_bool = self.getb(part.as_str());
|
||||
return value_bool;
|
||||
}
|
||||
else {
|
||||
return Self::evaluate_str_as_bool(part);
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{actor, audio, hud, nature, settings, stars};
|
||||
use crate::{actor, audio, hud, nature, stars, var};
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
||||
use bevy::math::{DVec3, I64Vec3};
|
||||
|
@ -385,7 +385,7 @@ fn handle_cheats(
|
|||
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||
mut q_life: Query<(&mut actor::LifeForm, &mut actor::ExperiencesGForce), With<actor::Player>>,
|
||||
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
) {
|
||||
if q_player.is_empty() || q_life.is_empty() {
|
||||
|
|
Loading…
Reference in a new issue