From f02f96a12e40b6dc006e7f89a82d03271747b66c Mon Sep 17 00:00:00 2001
From: Louis Capitanchik <contact@louiscap.co>
Date: Mon, 3 Oct 2022 05:32:11 +0100
Subject: [PATCH] Allow player actions on timer, create AI components

---
 game_core/src/control/ai.rs      | 13 +++++++++++
 game_core/src/control/mod.rs     |  1 +
 game_core/src/control/player.rs  | 25 ++++++++++++++-------
 game_core/src/entities/timing.rs | 37 ++++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 8 deletions(-)
 create mode 100644 game_core/src/control/ai.rs

diff --git a/game_core/src/control/ai.rs b/game_core/src/control/ai.rs
new file mode 100644
index 0000000..ba6e5cb
--- /dev/null
+++ b/game_core/src/control/ai.rs
@@ -0,0 +1,13 @@
+use bevy::prelude::*;
+
+#[derive(Copy, Clone, Debug, Component)]
+pub struct VisionRange(usize);
+#[derive(Copy, Clone, Debug, Component)]
+pub struct AggroTarget(Entity);
+#[derive(Copy, Clone, Debug, Component)]
+pub struct MoveTarget(UVec2);
+#[derive(Copy, Clone, Debug, Component)]
+pub struct Meander;
+
+#[derive(Copy, Clone, Debug, Component)]
+pub struct ShouldAct;
diff --git a/game_core/src/control/mod.rs b/game_core/src/control/mod.rs
index 632784b..09bbf08 100644
--- a/game_core/src/control/mod.rs
+++ b/game_core/src/control/mod.rs
@@ -1,4 +1,5 @@
 pub mod actions;
+pub mod ai;
 pub mod player;
 
 mod __plugin {
diff --git a/game_core/src/control/player.rs b/game_core/src/control/player.rs
index 44f5296..9d55493 100644
--- a/game_core/src/control/player.rs
+++ b/game_core/src/control/player.rs
@@ -1,31 +1,40 @@
+use std::time::Duration;
+
 use bevy::math::ivec2;
 use bevy::prelude::*;
 
 use crate::entities::lifecycle::Player;
+use crate::entities::timing::ActionCooldown;
 use crate::world::level_map::GridPosition;
 
 pub fn handle_player_input(
+	mut commands: Commands,
 	input: Res<Input<KeyCode>>,
-	mut query: Query<&mut GridPosition, With<Player>>,
+	mut query: Query<(Entity, &mut GridPosition), (With<Player>, Without<ActionCooldown>)>,
 ) {
 	let mut dx = 0;
 	let mut dy = 0;
 
-	if input.just_released(KeyCode::D) || input.just_released(KeyCode::Right) {
+	if input.pressed(KeyCode::D) || input.pressed(KeyCode::Right) {
 		dx += 1;
 	}
-	if input.just_released(KeyCode::W) || input.just_released(KeyCode::Up) {
+	if input.pressed(KeyCode::W) || input.pressed(KeyCode::Up) {
 		dy += 1;
 	}
-	if input.just_released(KeyCode::A) || input.just_released(KeyCode::Left) {
+	if input.pressed(KeyCode::A) || input.pressed(KeyCode::Left) {
 		dx -= 1;
 	}
-	if input.just_released(KeyCode::S) || input.just_released(KeyCode::Down) {
+	if input.pressed(KeyCode::S) || input.pressed(KeyCode::Down) {
 		dy -= 1;
 	}
 
-	for mut position in &mut query {
-		let next_position = (position.0.as_ivec2()) + ivec2(dx, dy);
-		**position = next_position.as_uvec2();
+	for (entity, mut position) in &mut query {
+		if dx != 0 || dy != 0 {
+			let next_position = (position.0.as_ivec2()) + ivec2(dx, dy);
+			**position = next_position.as_uvec2();
+			commands
+				.entity(entity)
+				.insert(ActionCooldown::from(Duration::from_millis(250)));
+		}
 	}
 }
diff --git a/game_core/src/entities/timing.rs b/game_core/src/entities/timing.rs
index e6c3586..e210d3c 100644
--- a/game_core/src/entities/timing.rs
+++ b/game_core/src/entities/timing.rs
@@ -1,3 +1,4 @@
+use std::ops::{Deref, DerefMut};
 use std::time::Duration;
 
 use bevy::prelude::*;
@@ -78,6 +79,41 @@ pub fn remove_global_timer_ui(mut commands: Commands, query: Query<Entity, With<
 	}
 }
 
+#[derive(Copy, Clone, Debug, Component)]
+#[repr(transparent)]
+#[component(storage = "SparseSet")]
+pub struct ActionCooldown(Duration);
+impl From<Duration> for ActionCooldown {
+	fn from(other: Duration) -> Self {
+		ActionCooldown(other)
+	}
+}
+impl Deref for ActionCooldown {
+	type Target = Duration;
+	fn deref(&self) -> &Self::Target {
+		&self.0
+	}
+}
+impl DerefMut for ActionCooldown {
+	fn deref_mut(&mut self) -> &mut Self::Target {
+		&mut self.0
+	}
+}
+
+pub fn tick_cooldown(
+	time: Res<Time>,
+	mut commands: Commands,
+	mut query: Query<(Entity, &mut ActionCooldown)>,
+) {
+	let delta = time.delta();
+	for (entity, mut cooldown) in &mut query {
+		**cooldown = cooldown.saturating_sub(delta);
+		if cooldown.is_zero() {
+			commands.entity(entity).remove::<ActionCooldown>();
+		}
+	}
+}
+
 pub struct TimingPlugin;
 impl Plugin for TimingPlugin {
 	fn build(&self, app: &mut App) {
@@ -88,6 +124,7 @@ impl Plugin for TimingPlugin {
 				ConditionSet::new()
 					.run_in_state(AppState::InGame)
 					.with_system(update_global_timer_ui)
+					.with_system(tick_cooldown)
 					.into(),
 			)
 			.add_exit_system(AppState::InGame, remove_global_timer_ui);
-- 
GitLab