// ▄████████▄ + ███ + ▄█████████ ███ + // ███▀ ▀███ + + ███ ███▀ + ███ + + // ███ + ███ ███ ███ █████████ ███ ███ ███ ███ // ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███ // ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███ // ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███ // ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████ // + + + ███ // + ▀████████████████████████████████████████████████████▀ // // This module handles player input, and coordinates interplay between other modules use crate::prelude::*; use bevy::prelude::*; use bevy::math::DVec3; use bevy::scene::SceneInstance; use bevy_xpbd_3d::prelude::*; use std::collections::HashMap; pub struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { app.add_systems(Update, handle_cheats); app.add_systems(PreUpdate, handle_player_death); app.add_systems(PostUpdate, update_id2pos); app.insert_resource(Id2Pos(HashMap::new())); app.add_event::(); } } #[derive(Event)] pub struct PlayerDiesEvent(pub actor::DamageType); #[derive(Resource)] pub struct Id2Pos(pub HashMap); fn handle_player_death( mut cmd: Commands, mut er_playerdies: EventReader, q_scenes: Query<(Entity, &SceneInstance), With>, q_noscenes: Query, Without)>, mut scene_spawner: ResMut, mut active_asteroids: ResMut, mut ew_effect: EventWriter, mut ew_deathscreen: EventWriter, mut log: ResMut, mut settings: ResMut, ) { for death in er_playerdies.read() { if settings.god_mode { return; } settings.reset_player_settings(); active_asteroids.0.clear(); for entity in &q_noscenes { cmd.entity(entity).despawn(); } for (entity, sceneinstance) in &q_scenes { cmd.entity(entity).despawn(); scene_spawner.despawn_instance(**sceneinstance); } log.clear(); match death.0 { actor::DamageType::Mental => { settings.death_cause = "Brain Damage".to_string(); ew_effect.send(visual::SpawnEffectEvent { class: visual::Effects::FadeIn(Color::BLACK), duration: 4.0, }); } actor::DamageType::Asphyxiation => { settings.death_cause = "Suffocation".to_string(); ew_effect.send(visual::SpawnEffectEvent { class: visual::Effects::FadeIn(Color::BLACK), duration: 1.0, }); } actor::DamageType::Trauma => { settings.death_cause = "Trauma".to_string(); ew_effect.send(visual::SpawnEffectEvent { class: visual::Effects::FadeIn(Color::MAROON), duration: 1.0, }); } actor::DamageType::GForce => { settings.death_cause = "Trauma from excessive g forces".to_string(); ew_effect.send(visual::SpawnEffectEvent { class: visual::Effects::FadeIn(Color::MAROON), duration: 1.0, }); } _ => { settings.death_cause = "Unknown".to_string(); ew_effect.send(visual::SpawnEffectEvent { class: visual::Effects::FadeIn(Color::MAROON), duration: 1.0, }); } } ew_deathscreen.send(menu::DeathScreenEvent::Show); return; } } fn handle_cheats( key_input: Res>, mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With>, mut q_life: Query<(&mut actor::LifeForm, &mut actor::ExperiencesGForce), With>, q_target: Query<(&Transform, &Position, Option<&LinearVelocity>), (With, Without)>, mut ew_playerdies: EventWriter, mut settings: ResMut, id2pos: Res, mut ew_sfx: EventWriter, ) { if q_player.is_empty() || q_life.is_empty() { return; } let (trans, mut pos, mut v) = q_player.get_single_mut().unwrap(); let (mut lifeform, mut gforce) = q_life.get_single_mut().unwrap(); let boost = if key_input.pressed(KeyCode::ShiftLeft) { 1e6 } else { 1e3 }; if key_input.just_pressed(settings.key_cheat_god_mode) { settings.god_mode ^= true; if settings.god_mode { ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle)); } } if !settings.god_mode && !settings.dev_mode { return; } if key_input.just_pressed(settings.key_cheat_stop) { gforce.ignore_gforce_seconds = 1.0; v.0 = DVec3::ZERO; } if key_input.pressed(settings.key_cheat_speed) { gforce.ignore_gforce_seconds = 1.0; v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, boost)); } if key_input.pressed(settings.key_cheat_speed_backward) { 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; if let Some(target_v) = target_v { *v = target_v.clone(); } } } if !settings.dev_mode { return; } if key_input.just_pressed(settings.key_cheat_pizza) { if let Some(target) = id2pos.0.get(&"pizzeria".to_string()) { pos.0 = *target + DVec3::new(-60.0, 0.0, 0.0); gforce.ignore_gforce_seconds = 1.0; } } if key_input.just_pressed(settings.key_cheat_farview1) { if let Some(target) = id2pos.0.get(&"busstopclippy2".to_string()) { pos.0 = *target + DVec3::new(0.0, -1000.0, 0.0); gforce.ignore_gforce_seconds = 1.0; } } if key_input.just_pressed(settings.key_cheat_farview2) { if let Some(target) = id2pos.0.get(&"busstopclippy3".to_string()) { pos.0 = *target + DVec3::new(0.0, -1000.0, 0.0); gforce.ignore_gforce_seconds = 1.0; } } if key_input.pressed(settings.key_cheat_adrenaline_zero) { lifeform.adrenaline = 0.0; } if key_input.pressed(settings.key_cheat_adrenaline_mid) { lifeform.adrenaline = 0.5; } if key_input.pressed(settings.key_cheat_adrenaline_max) { lifeform.adrenaline = 1.0; } if key_input.just_pressed(settings.key_cheat_die) { settings.god_mode = false; ew_playerdies.send(PlayerDiesEvent(actor::DamageType::Trauma)); } } fn update_id2pos( mut id2pos: ResMut, q_id: Query<(&Position, &actor::Identifier)>, ) { id2pos.0.clear(); for (pos, id) in &q_id { id2pos.0.insert(id.0.clone(), pos.0); } }