Compare commits

..

13 commits

14 changed files with 15767 additions and 15747 deletions

View file

@ -49,6 +49,7 @@ Links:
- V/B: Impossible acceleration forward/backward
- Shift+V/B: Same as V/B, but a thousand times faster
- C: Impossibly instant stopping
- X: Teleport to target
# System Requirements

View file

@ -34,9 +34,8 @@ MAX_APPARENT_MAGNITUDE = 7.0
print("// This file was autogenerated by \"genrate_starchart.py\" using data from the")
print("// HYG database: https://github.com/astronexus/HYG-Database/tree/main/hyg")
print("// License: CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/")
print("")
print("// Each star's values: [x, y, z, magnitude, color index, distance, name]")
print("pub const STARS: &[(f32; f32, f32, f32, f32, f32, str)] = &[")
print("// Each star's values: (x, y, z, magnitude, color index, distance, name)")
print("[")
def render(ra, dec, mag, ci, dist, name):
@ -59,7 +58,7 @@ def render(ra, dec, mag, ci, dist, name):
#brightness = 2.512 ** (0 - mag)
print(f' ({x:.04}, {y:.04}, {z:.04}, {mag:.04}, {ci}, {dist}, "{name}"),')
print(f'({x:.04},{y:.04},{z:.04},{mag:.04},{ci},{dist},"{name}"),')
def clean_name(string):
@ -99,5 +98,5 @@ for entry in entries:
# render(entry[0], entry[1], entry[2], entry[3], entry[4])
# count_extra += 1
print("];")
print("]")
print(f"Wrote {count} stars (total={total}) + {count_extra} extra entries.", file=sys.stderr)

View file

@ -5,8 +5,8 @@ use bevy::math::DVec3;
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;
const MAX_INTERACT_DISTANCE: f32 = 30.0;
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
const MAX_INTERACT_DISTANCE: f32 = 40.0;
pub struct ActorPlugin;
impl Plugin for ActorPlugin {

View file

@ -246,13 +246,13 @@ impl ChatDB {
// - `"What's up?"`
// - `{"goto": "foo"}`
fn is_choice(&self, yaml: Option<&Value>) -> bool {
if let Some(data) = self.extract(yaml) {
if let Some(data) = self.extract_choice(yaml) {
return data.choice_text.is_some();
}
return false;
}
fn extract(&self, yaml: Option<&Value>) -> Option<Extracted> {
fn extract_choice(&self, yaml: Option<&Value>) -> Option<Extracted> {
let non_choice_tokens = NON_CHOICE_TOKENS.to_vec();
if let Some(Value::Mapping(map)) = yaml {
let mut result: Extracted = Extracted::default();
@ -269,6 +269,9 @@ impl ChatDB {
else if non_choice_tokens.contains(&key.as_str()) {
// skip over the other non-choice tokens
}
else if key.as_str().starts_with(TOKEN_IF_INLINE) {
// skip over inlined if-statements
}
else {
result.choice_text = Some(key.to_string());
}
@ -568,7 +571,7 @@ 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(data) = self.extract(self.at(chat.internal_id, &chat.position).as_ref()) {
while let Some(data) = self.extract_choice(self.at(chat.internal_id, &chat.position).as_ref()) {
if let Some(choice_text) = data.choice_text {
if reached_end_of_branch {
break;
@ -694,7 +697,6 @@ pub fn handle_chat_events(
}
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;
@ -813,6 +815,11 @@ pub fn handle_chat_scripts(
} else {
error!("Invalid parameter for command `{}`: `{}`", name, param1);
}
"repairsuit" => {
for (_, mut suit, _) in q_player.iter_mut() {
suit.integrity = 1.0;
}
}
"cryotrip" => {
if param1.is_empty() {
error!("Chat script cryotrip needs a parameter");

View file

@ -176,15 +176,21 @@
- chat: PizzaChef
- if $eat:
- Ah, they always come back.
- Ready for another round at Old Earth Pizza?
- goto: eat
- Oh hey, you found your way to the legendary Old Earth Pizza!
- Please find yourself a cozy place to drift.
- Time to loosen up! Find yourself a cozy place to drift.
- Do you have a reservation?
- label: reservation
- Reservation? Is there not enough space for everybody?:
- if: ~$reservation
...Reservation? Is there not enough space for everybody?:
- Ah, space there is.
- But I can't get overworked, can I?
- I'm running this joint all by myself, after all.
- Apart of good ol' Clippy.
- set: $reservation
- goto: reservation
- No reservation. Can I still buy something?:
- '"Buy"? Ah, this old earth thing.'
@ -193,13 +199,150 @@
- Amazing.
- Sure, you can "buy" something, watcha want?
- goto: eat
- Can I ask you some... weird questions?:
- Of course. Just hold on, let me load my gun.
- Alright, shoot.
- goto: questions
- Wh... what's a pizzeria doing here?:
- Hah, beautiful, right? I carved it out this asteroid myself!
- You know how much work it was to neutralize the rotation of the asteroid, so my valued customers don't bang against the walls?
- Do you have a reservation though?
- goto: reservation
- My head hurts, my suit is leaking, I think I'm dying...:
- 他妈的, that sound terrible.
- Unlikely that you'll die though.
- You're wearing a SecondSkyn™. It's the best, it'll take care of you.
- Would you like me to patch it up?
- label: patchup
- Yes please!:
- Here you go!
- script: repairsuit
- system: SuitPatch™ SuperGlue™ applied.
- goto: reservation
- How much will you charge me?:
- Why would I charge you? Your suit is nuclear powered.
- So what about the patch up?
- goto: patchup
- Don't touch me.:
- Suit yourself.
- What about the reservation?
- goto: reservation
- I guess not.
- What about the reservation?
- goto: reservation
- Can I ask you some questions?:
- Shoot.
- goto: generic_questions
- I gotta go.:
- Come back any time! You are always welcome.
- goto: EXIT
- I guess not.
- But I can't you leave hungry, can I?
- So far away from everything.
- Just let me know if you want something.
- label: eat
- label: questions
- set: $eat
- What's on the menu?:
- set: $knows-menu
- Today's special is Suspicious Spacefunghi.
- It's pretty wild, but 真他媽的好吃.
- But we have pretty much anything you can dream of.
- Daring Durian, Artichoke Apple Pie, you name it.
- goto: eat
- Got pineapple in stock?:
- I can totally hook you up with that.
- But why would you want to?
- It's really delicious:
- Right, of course.
- Nevermind:
- So?
- set: $knows-pineapple
- goto: eat
- I made up my mind.:
- Which emulsion of deliciousness will it be?
- if: $knows-menu
I'd like a Suspicious Spacefunghi:
- Coming right up your feeding tube!
- system: Received Suspicious Spacefunghi pizza smoothie
- goto: served
- if: $knows-menu
I'd like a Daring Durian:
- Coming right up your feeding tube!
- system: Received Daring Durian pizza smoothie
- goto: served
- if: $knows-menu
I'd like an Artichoke Apple Pie pizza:
- Coming right up your feeding tube!
- system: Received Artichoke Apple Pie pizza smoothie
- goto: served
- if: $knows-pineapple
I'd like a pineapple pizza:
- Coming right up your feeding tube!
- system: Received pineapple pizza smoothie
- goto: served
- if: $knows-coffee
I'd like a cup of that legendary Old Earth Coffee, please:
- Coming right up your feeding tube!
- system: Received Old Earth Coffee
- goto: served
- Surprise me.:
- Hmm...
- I would take you for the adventurous type.
- Daring Durian, coming right up your feeding tube!
- system: Received Daring Durian pizza smoothie
- goto: served
- Actually... I haven't decided yet.:
- goto: eat
- I'm not hungry.:
- goto: not hungry
- Got anything other than pizza?:
- Anything you need, I got you covered.
- label: non-pizza
- I'm low on oxygen, can you spare some?:
- But of course! I take care of my guests.
- script: refilloxygen 1
- system: Oxygen refilled
- goto: served
- Could you patch up my space suit?:
- Right on.
- script: repairsuit
- system: SuitPatch™ SuperGlue™ applied.
- goto: served
- Got any coffee?:
- Your suit should have a coffee dispenser built right into it.
- Naturally, it's not as good as my legendary Old Earth Coffee!
- set: knows-coffee
- goto: non-pizza
- Can't think of anything right now.:
- So what would you like to order?
- goto: eat
- Can I ask you some general questions?:
- Shoot.
- goto: generic_questions
- I'm not hungry, thanks.:
- goto: not hungry
- If you don't want anything, that's fine too.
- label: not hungry
- Feel free to hang out as long as you like.
- goto: EXIT
- label: served
- Come back any time!
- goto: EXIT
- label: generic_questions
- include: generic_questions_serenity
- See you around!
---
- chat: generic_questions_serenity
- Where are we?:
- Inside Jupiter's rings, obviously.
- We're about 150,000km away from the gas giant.
- This region is called Serenity by its inhabitants, due to the relative safety from Jupiter's magnetic field and the micros.
- goto: generic_questions
- What time is it?:
- Oh, is your Augmented Reality deactivated?
- Push the TAB button, your space suit's AR will show you the date and time.
- goto: generic_questions
- I think I'm good for now.: []

View file

@ -67,19 +67,6 @@ struct ParserState {
light_brightness: f32,
light_color: Option<Color>,
ar_model: Option<String>,
// // Chat fields
// delay: f64,
// text: String,
// level: String,
// label: String,
// goto: String,
// is_choice: bool,
// stores_item: bool,
// script: String,
// script_parameter: String,
// script_parameter2: String,
// sound: Option<String>,
}
impl Default for ParserState {
fn default() -> Self {
@ -123,52 +110,9 @@ impl Default for ParserState {
light_brightness: 0.0,
light_color: None,
ar_model: None,
// delay: 0.0,
// text: "".to_string(),
// level: "chat".to_string(),
// label: "".to_string(),
// goto: "".to_string(),
// is_choice: false,
// stores_item: false,
// script: "".to_string(),
// script_parameter: "".to_string(),
// script_parameter2: "".to_string(),
// sound: Some("chat".to_string()),
}
}
}
impl ParserState {
// fn reset_message(&mut self) {
// let default = ParserState::default();
// self.label = default.label;
// self.delay = default.delay;
// self.goto = default.goto;
// self.level = default.level;
// self.text = default.text;
// self.is_choice = default.is_choice;
// self.script = default.script;
// self.script_parameter = default.script_parameter;
// self.script_parameter2 = default.script_parameter2;
// self.sound = default.sound;
// }
// fn as_chatbranch(&self) -> chat::ChatBranch {
// return chat::ChatBranch {
// id: self.chat.clone(),
// name: self.name.clone().unwrap_or("".to_string()),
// label: self.label.clone(),
// delay: self.delay.clone(),
// sound: if self.is_choice || self.sound.is_none() { "".to_string() } else { "chat".to_string() },
// level: self.level.clone(),
// reply: if self.is_choice { "".to_string() } else { self.text.clone() },
// choice: if self.is_choice { self.text.clone() } else { "".to_string() },
// goto: self.goto.clone(),
// script: self.script.clone(),
// script_parameter: self.script_parameter.clone(),
// script_parameter2: self.script_parameter2.clone(),
// }
// }
}
pub fn load_defs(
mut ew_spawn: EventWriter<SpawnEvent>,
@ -470,104 +414,6 @@ pub fn load_defs(
["armodel", asset_name] => {
state.ar_model = Some(asset_name.to_string());
}
// Parsing chats
// ["chat", chat_name] => {
// debug!("Registering chat: {}", chat_name);
// ew_spawn.send(SpawnEvent(state));
// state = ParserState::default();
// state.class = DefClass::Chat;
// state.chat = chat_name.to_string();
// }
// ["msg", sleep, text] => {
// debug!("Registering message (sleep={}): {}", sleep, text);
// ew_spawn.send(SpawnEvent(state.clone()));
// if let Ok(sleep_float) = sleep.parse::<f64>() {
// state.delay = sleep_float;
// state.text = text.to_string();
// state.stores_item = true;
// state.is_choice = false;
// } else {
// error!("The 'sleep' value for this message is not a float: {}", line);
// continue;
// }
// }
// ["msg", sleep, label, goto, text] => {
// debug!("Registering message (sleep={}): {}", sleep, text);
// ew_spawn.send(SpawnEvent(state.clone()));
// state.reset_message();
// if let Ok(sleep_float) = sleep.parse::<f64>() {
// state.delay = sleep_float;
// state.text = text.to_string();
// state.stores_item = true;
// state.is_choice = false;
// state.goto = goto.to_string();
// state.label = label.to_string();
// } else {
// error!("The 'sleep' value for this message is not a float: {}", line);
// continue;
// }
// }
// ["choice", sleep, text] => {
// debug!("Registering choice (sleep={}): {}", sleep, text);
// ew_spawn.send(SpawnEvent(state.clone()));
// state.reset_message();
// if let Ok(sleep_float) = sleep.parse::<f64>() {
// state.delay = sleep_float;
// state.text = text.to_string();
// state.stores_item = true;
// state.is_choice = true;
// } else {
// error!("The 'sleep' value for this message is not a float: {}", line);
// continue;
// }
// }
// ["choice", sleep, label, goto, text] => {
// debug!("Registering choice (sleep={}): {}", sleep, text);
// ew_spawn.send(SpawnEvent(state.clone()));
// state.reset_message();
// if let Ok(sleep_float) = sleep.parse::<f64>() {
// state.delay = sleep_float;
// state.text = text.to_string();
// state.stores_item = true;
// state.is_choice = true;
// state.goto = goto.to_string();
// state.label = label.to_string();
// } else {
// error!("The 'sleep' value for this message is not a float: {}", line);
// continue;
// }
// }
// ["goto", label] => {
// debug!("Registering goto: {}", label);
// state.goto = label.to_string();
// }
// ["label", label] => {
// debug!("Registering label: {}", label);
// state.label = label.to_string();
// }
// ["lvl", level] => {
// debug!("Registering level: {}", level);
// state.level = level.to_string();
// }
// ["script", scriptname] => {
// state.script = scriptname.to_string();
// state.script_parameter = "".to_string();
// state.script_parameter2 = "".to_string();
// }
// ["script", scriptname, parameter] => {
// state.script = scriptname.to_string();
// state.script_parameter = parameter.to_string();
// state.script_parameter2 = "".to_string();
// }
// ["script", scriptname, parameter, parameter2] => {
// state.script = scriptname.to_string();
// state.script_parameter = parameter.to_string();
// state.script_parameter2 = parameter2.to_string();
// }
// ["sound", "none"] => {
// state.sound = None;
// }
_ => {
error!("No match for [{}]", parts.join(","));
}
@ -682,7 +528,7 @@ fn spawn_entities(
actor.insert(PointLightBundle {
point_light: PointLight {
intensity: state.light_brightness,
color: color,
color,
range: 100.0,
radius: 100.0,
..default()

15550
src/data/stars.in Normal file

File diff suppressed because it is too large Load diff

View file

@ -177,14 +177,14 @@ actor -3300 10 0 pizzeria
wants maxrotation 0
wants maxvelocity 0
thrust 15 6 3 400 0.5
rotationy -0.5
rotationy -0.7
scale 3
chatid SubduedClippy
actor -35 0 0 suit
actor -45 -4 -4 suit
relativeto pizzeria
name "Space Pizza™"
chatid SpacePizzaChef
chatid PizzaChef
armodel suit_ar_chefhat
alive yes
scale 2
@ -192,7 +192,7 @@ actor -3300 10 0 pizzeria
thrust 1.2 1 1 10 1.5
wants maxrotation 0
wants maxvelocity 0
rotationy 1
rotationy -0.5
angularmomentum 0 0 0
pronoun he

View file

@ -119,15 +119,15 @@ impl Log {
self.add(message, "".to_string(), LogLevel::Notice);
}
pub fn add(&mut self, message: String, sender: String, level: LogLevel) {
pub fn add(&mut self, text: String, sender: String, level: LogLevel) {
if self.logs.len() == LOG_MAX {
self.logs.pop_front();
}
if let Ok(epoch) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
self.logs.push_back(Message {
text: message,
sender: sender,
level: level,
text,
sender,
level,
time: epoch.as_secs(),
});
self.needs_rerendering = true;
@ -377,7 +377,7 @@ fn setup(
left: Val::Vw(50.0),
..default()
},
visibility: visibility,
visibility,
background_color: Color::rgb(0.4, 0.4, 0.6).into(),
..default()
},

View file

@ -5,7 +5,6 @@ mod chat;
mod commands;
mod effects;
mod hud;
mod stars;
mod var;
mod world;

View file

@ -12,6 +12,9 @@ pub const PARSEC2METER: f64 = 3.0857e16;
pub const DIST_JUPTER_SUN: f64 = 778479.0e6;
pub const EARTH_GRAVITY: f32 = 9.81;
// Each star's values: (x, y, z, magnitude, color index, distance, name)
pub const STARS: &[(f32, f32, f32, f32, f32, f32, &str)] = &include!("data/stars.in");
pub fn star_color_index_to_rgb(color_index: f32) -> (f32, f32, f32) {
let temperature = 4600.0 * ((1.0 / (0.92 * color_index + 1.7)) + (1.0 / (0.92 * color_index + 0.62)));

15551
src/stars.rs

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ 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 = "~";
pub const DEFAULT_CHAT_SPEED: f32 = 10.0;
@ -72,6 +73,7 @@ pub struct Settings {
pub key_cheat_stop: KeyCode,
pub key_cheat_speed: KeyCode,
pub key_cheat_speed_backward: KeyCode,
pub key_cheat_teleport: KeyCode,
pub key_cheat_pizza: KeyCode,
pub key_cheat_farview1: KeyCode,
pub key_cheat_farview2: KeyCode,
@ -113,7 +115,7 @@ impl Default for Settings {
zoom_sensitivity_factor: 0.25,
font_size_hud: 32.0,
font_size_conversations: 32.0,
chat_speed: DEFAULT_CHAT_SPEED,
chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 },
hud_active: false,
is_zooming: false,
third_person: false,
@ -157,6 +159,7 @@ impl Default for Settings {
key_cheat_stop: KeyCode::KeyC,
key_cheat_speed: KeyCode::KeyV,
key_cheat_speed_backward: KeyCode::KeyB,
key_cheat_teleport: KeyCode::KeyX,
key_cheat_pizza: KeyCode::F9,
key_cheat_farview1: KeyCode::F10,
key_cheat_farview2: KeyCode::F12,
@ -295,13 +298,18 @@ impl GameVars {
// 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;
return value_bool ^ negate;
}
else {
return Self::evaluate_str_as_bool(part);
return Self::evaluate_str_as_bool(part) ^ negate;
}
} else if parts.len() == 2 {

View file

@ -1,4 +1,4 @@
use crate::{actor, audio, hud, nature, stars, var};
use crate::{actor, audio, hud, nature, var};
use bevy::prelude::*;
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
use bevy::math::{DVec3, I64Vec3};
@ -12,7 +12,7 @@ use fastrand;
const ASTEROID_UPDATE_INTERVAL: f32 = 0.1; // seconds
const ASTEROID_SIZE_FACTOR: f32 = 10.0;
const RING_THICKNESS: f64 = 8.0e6;
const STARS_MAX_MAGNITUDE: f32 = 5.5;
const STARS_MAX_MAGNITUDE: f32 = 5.5; // max 7.0, see generate_starchart.py
const CENTER_WORLD_ON_PLAYER: bool = true;
@ -126,14 +126,15 @@ pub fn setup(
commands.insert_resource(AsteroidModel2(asset_server.load(ASSET_ASTEROID2)));
// Generate starmap
let sphere_handle = meshes.add(Sphere::new(1.0));
let sphere_handle = meshes.add(Circle::new(1.0));
let mut starcount = 0;
for star in stars::STARS {
for star in nature::STARS {
let mag = star.3;
if mag > STARS_MAX_MAGNITUDE {
continue;
}
let is_sun = mag < -20.0;
let mag = mag.min(6.0);
let scale_color = {|color: f32|
if is_sun {
color * 13.0f32
@ -167,6 +168,12 @@ pub fn setup(
} else {
star.6.to_string()
};
let translation = Vec3::new(
mesh_distance * star.0,
mesh_distance * star.1,
mesh_distance * star.2,
);
let rotation = Quat::from_rotation_arc(Vec3::Z, (-translation).normalize());
commands.spawn((
Star,
hud::IsClickable {
@ -176,12 +183,11 @@ pub fn setup(
PbrBundle {
mesh: sphere_handle.clone(),
material: star_color_handle,
transform: Transform::from_xyz(
mesh_distance * star.0,
mesh_distance * star.1,
mesh_distance * star.2,
)
.with_scale(Vec3::splat(scale_size(mag))),
transform: Transform {
translation,
rotation,
scale: Vec3::splat(scale_size(mag)),
},
..default()
}
));
@ -384,6 +390,7 @@ fn handle_cheats(
key_input: Res<ButtonInput<KeyCode>>,
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>>,
q_target: Query<(&Transform, &Position, &LinearVelocity), (With<hud::IsTargeted>, Without<actor::PlayerCamera>)>,
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
mut settings: ResMut<var::Settings>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
@ -420,6 +427,14 @@ fn handle_cheats(
gforce.ignore_gforce_seconds = 1.0;
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -boost));
}
if key_input.just_pressed(settings.key_cheat_teleport) {
if let Ok((transform, target_pos, target_v)) = q_target.get_single() {
let offset: DVec3 = 4.0 * (**pos - **target_pos).normalize() * transform.scale.as_dvec3();
pos.0 = **target_pos + offset;
*v = target_v.clone();
}
}
if !settings.dev_mode {
return;
}