Commit 8a381b4e authored by anon's avatar anon

Merge branch 'rahix/changes' into 'master'

Difficulty Scaling

See merge request engel-simulator-2020/game!49
parents fd64e440 0761cdeb
use crate::gamestate;
use anyhow::Context;
use wasm_bindgen::prelude::*;
static mut SMHANDLE: Option<gamestate::StateMachineHandle> = None;
static mut CHEAT_PASSWORD: Option<String> = None;
pub fn initialize_cheats(handle: gamestate::StateMachineHandle) {
// SAFETY: We know that concurrency is impossible because Javascript is (in this case)
// single-threaded.
unsafe {
SMHANDLE = Some(handle);
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum CheatCommand {
SetSanity(f32),
}
fn get_cheat_state() -> anyhow::Result<&'static gamestate::StateMachineHandle> {
// SAFETY: We know that concurrency is impossible because Javascript is (in this case)
// single-threaded.
unsafe {
if CHEAT_PASSWORD.as_deref() != Some(option_env!("ENGEL_CHEAT_CODE").unwrap_or("uhagre7")) {
anyhow::bail!("you shall not cheat!");
}
SMHANDLE.as_ref().context("cheats not initialized")
}
}
#[wasm_bindgen]
pub fn cheat_enable(password: &str) {
// SAFETY: We know that concurrency is impossible because Javascript is (in this case)
// single-threaded.
unsafe {
CHEAT_PASSWORD = Some(
password
.chars()
.map(|c| match c {
'A'...'M' | 'a'...'m' => ((c as u8) + 13) as char,
'N'...'Z' | 'n'...'z' => ((c as u8) - 13) as char,
'0'...'9' => (0x39 - (c as u8) + 0x30) as char,
_ => c,
})
.collect(),
);
}
}
#[wasm_bindgen]
pub fn cheat_set_sanity(val: f32) -> Result<(), wasm_bindgen::JsValue> {
match || -> anyhow::Result<()> {
// this is nice
let state = get_cheat_state()?;
state.do_cheat(CheatCommand::SetSanity(val));
Ok(())
}() {
// this is not nice
Ok(()) => Ok(()),
Err(err) => Err(wasm_bindgen::JsValue::from_str(&format!("{}", err))),
}
}
......@@ -2,6 +2,9 @@
pub struct Player {
pub sanity: f32,
pub collected_hours: u32,
pub shifts_completed: u32,
pub difficulty: f32,
}
impl Player {
......@@ -9,6 +12,8 @@ impl Player {
Player {
sanity: 1.0,
collected_hours: 0,
shifts_completed: 0,
difficulty: 0.0,
}
}
}
......@@ -4,11 +4,15 @@ use crate::sprites;
use crate::svg_loader;
use rand::seq::SliceRandom;
pub fn create_stationary_obstacles(world: &mut legion::World, level: &svg_loader::SvgLevel) {
pub fn create_stationary_obstacles(
world: &mut legion::World,
level: &svg_loader::SvgLevel,
player: &components::Player,
) {
let spawn_locations_barriers = level
.spawnpoints
.get("stationary_obstacle_type_1")
.map_or(&[][..], |x| &x[..]);
.map_or([].as_ref(), |x| x.as_ref());
for obs in spawn_locations_barriers.choose_multiple(&mut rand::thread_rng(), 3) {
let orientation = *[true, false].choose(&mut rand::thread_rng()).unwrap();
let new_obs = components::ObstacleBarrier::new(orientation);
......@@ -19,17 +23,19 @@ pub fn create_stationary_obstacles(world: &mut legion::World, level: &svg_loader
));
}
let spawn_locations_insanity = level
.spawnpoints
.get("stationary_obstacle_type_2")
.map_or(&[][..], |x| &x[..]);
for obs in spawn_locations_insanity.choose_multiple(&mut rand::thread_rng(), 1) {
let new_obs = components::ObstacleInsanity::new();
world.push((
new_obs,
components::Position::new(obs.x, obs.y),
colliders::Collider::new_sensor_circle(new_obs.r),
components::Sprite::new(sprites::Sprite::TrojanHorse),
));
if player.difficulty > 0.25 {
let spawn_locations_insanity = level
.spawnpoints
.get("stationary_obstacle_type_2")
.map_or([].as_ref(), |x| x.as_ref());
for obs in spawn_locations_insanity.choose_multiple(&mut rand::thread_rng(), 1) {
let new_obs = components::ObstacleInsanity::new();
world.push((
new_obs,
components::Position::new(obs.x, obs.y),
colliders::Collider::new_sensor_circle(new_obs.r),
components::Sprite::new(sprites::Sprite::TrojanHorse),
));
}
}
}
......@@ -59,6 +59,7 @@ pub trait State {
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Event<'a> {
MouseClick {
......@@ -67,6 +68,7 @@ pub enum Event<'a> {
},
KeyDown(&'a str),
KeyUp(&'a str),
Cheat(crate::cheats::CheatCommand),
}
struct EventHandlers {
......@@ -179,6 +181,14 @@ impl StateMachineHandle {
let t = StateMachine::active(&self.0).event(event);
self.do_transition(t)
}
pub fn do_cheat(&self, cheat: crate::cheats::CheatCommand) {
self.do_event(Event::Cheat(cheat))
}
pub fn active_state(&self) -> std::cell::RefMut<Box<dyn State>> {
std::cell::RefMut::map(StateMachine::active(&self.0), |storage| &mut storage.state)
}
}
pub struct StateInitializer<'a> {
......@@ -284,6 +294,8 @@ impl StateMachine {
loop_scheduled: false,
}));
crate::cheats::initialize_cheats(StateMachineHandle::new(&this));
// Sadly Rc::new_cyclic() isn't stable yet ...
let loop_handler = {
let this = this.clone();
......
......@@ -3,6 +3,7 @@ use js_sys;
use wasm_bindgen::prelude::*;
pub mod angel_shifts;
pub mod cheats;
pub mod colliders;
pub mod colors;
pub mod components;
......
use crate::angel_shifts;
use crate::cheats;
use crate::colors;
use crate::components;
use crate::gamestate;
......@@ -21,7 +22,7 @@ impl HeavenState {
pub fn new(player: Option<components::Player>) -> HeavenState {
let (node_world, resources, node_schedule) = init_orbiting_nodes();
let player = player.unwrap_or_else(|| {
let mut player = player.unwrap_or_else(|| {
// Initialize the game as this is the first run.
components::Player::new()
});
......@@ -46,6 +47,9 @@ impl HeavenState {
// Assign a random shift
let assigned_shift = angel_shifts::generate_random_shift(&mut rand::thread_rng());
// Decide difficulty for the next shift
player.difficulty = ((player.shifts_completed as f32 + 1.0) * 0.1).min(1.0);
// Display the shift info
let shift_meta = assigned_shift.metadata();
utils::get_element_by_id::<web_sys::Element>("heaven-shift-title")
......@@ -117,8 +121,12 @@ impl gamestate::State for HeavenState {
self.player.clone(),
self.assigned_shift.take().unwrap(),
)),
gamestate::Event::Cheat(cheats::CheatCommand::SetSanity(val)) => {
self.player.sanity = val;
gamestate::Transition::Keep
}
event => {
crate::console_log!("unknown event {:?}", event);
crate::console_warn!("unknown event: {:?}", event);
gamestate::Transition::Keep
}
}
......
use crate::angel_shifts;
use crate::cheats;
use crate::colliders;
use crate::colors;
use crate::components;
......@@ -38,8 +39,8 @@ impl InGameState {
resources.insert(resources::Camera::new(1920.0, 1080.0));
resources.insert(colliders::CollisionWorld::new());
let obstacles = entities::create_stationary_obstacles(&mut world, &level, &player);
let player = entities::create_player(&mut world, &level, player);
let obstacles = entities::create_stationary_obstacles(&mut world, &level);
resources.insert(resources::Player(player));
resources.insert(obstacles);
......@@ -110,10 +111,11 @@ impl gamestate::State for InGameState {
fn event(&mut self, event: gamestate::Event) -> gamestate::Transition {
use legion::IntoQuery;
let player = self.resources.get::<resources::Player>().unwrap().0.clone();
let player_movable = <&mut components::Movable>::query()
.get_mut(&mut self.world, player)
.unwrap();
let player_id = self.resources.get::<resources::Player>().unwrap().0.clone();
let (player_movable, player) =
<(&mut components::Movable, &mut components::Player)>::query()
.get_mut(&mut self.world, player_id)
.unwrap();
match event {
gamestate::Event::KeyDown("w") | gamestate::Event::KeyDown("ArrowUp") => {
player_movable.velocity.y = -300.0
......@@ -139,7 +141,12 @@ impl gamestate::State for InGameState {
gamestate::Event::KeyUp("d") | gamestate::Event::KeyUp("ArrowRight") => {
player_movable.velocity.x = 0.0
}
_ => (),
gamestate::Event::Cheat(cheats::CheatCommand::SetSanity(val)) => {
player.sanity = val;
}
event => {
crate::console_warn!("unknown event: {:?}", event);
}
}
if player_movable.velocity.x != 0.0 || player_movable.velocity.y != 0.0 {
player_movable.velocity = player_movable.velocity.normalize() * 300.0;
......@@ -169,7 +176,11 @@ impl gamestate::State for InGameState {
let player: &components::Player = <&components::Player>::query()
.get(&self.world, player_ent)
.unwrap();
gamestate::Transition::replace(states::HeavenState::new(Some(player.clone())))
let mut player = player.clone();
player.shifts_completed += 1;
gamestate::Transition::replace(states::HeavenState::new(Some(player)))
} else if game_manager.wants_game_over() {
gamestate::Transition::replace(states::GameOverState::new())
} else {
......
......@@ -3,3 +3,8 @@ import * as wasm from "engel-simulator-2020";
import "./styles.scss";
wasm.start();
(window as any).cheats = {
set_sanity: wasm.cheat_set_sanity,
enable: wasm.cheat_enable,
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment