diff --git a/crates/border-wars/src/main.rs b/crates/border-wars/src/main.rs index a7c9a63..b6b2301 100644 --- a/crates/border-wars/src/main.rs +++ b/crates/border-wars/src/main.rs @@ -6,6 +6,7 @@ use border_wars::map::generation::MapGenerationPlugin; use border_wars::map::ownership::OwnershipPlugin; use border_wars::map::renderer::RendererPlugin; use border_wars::map::selected_tile::SelectTilePlugin; +use border_wars::map::spawnpoint::SpawnpointPlugin; use border_wars::networking::NetworkingPlugin; use border_wars::scenes::ScenesPlugin; use border_wars::ui::UiPlugin; @@ -20,6 +21,7 @@ fn main() { .add_plugins(NetworkingPlugin) .add_plugins(MapGenerationPlugin) .add_plugins(UiPlugin) + .add_plugins(SpawnpointPlugin) .add_plugins(OwnershipPlugin) .run(); } diff --git a/crates/border-wars/src/map/mod.rs b/crates/border-wars/src/map/mod.rs index 709fae2..d974e7f 100644 --- a/crates/border-wars/src/map/mod.rs +++ b/crates/border-wars/src/map/mod.rs @@ -5,6 +5,7 @@ pub mod hex; pub mod ownership; pub mod renderer; pub mod selected_tile; +pub mod spawnpoint; use bevy::prelude::*; diff --git a/crates/border-wars/src/map/spawnpoint.rs b/crates/border-wars/src/map/spawnpoint.rs new file mode 100644 index 0000000..5dd59e6 --- /dev/null +++ b/crates/border-wars/src/map/spawnpoint.rs @@ -0,0 +1,72 @@ +//! All code related to set the spawn point of the players. + +use bevy::prelude::*; + +use super::generation::EndMapGeneration; +use super::ownership::Owner; +use super::{Tile, TilePosition}; +use crate::Player; + +/// The plugin that initialize the spawn point at the start of the game. +pub struct SpawnpointPlugin; + +impl Plugin for SpawnpointPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Update, init_spawn_point); + } +} + +/// Initialize the spawn point when the map is generated. +fn init_spawn_point( + mut commands: Commands, + mut end_map_event: EventReader, + players: Query<&Player>, + mut map: Query<(Entity, &TilePosition, &mut Tile)>, +) { + for _ in end_map_event.read() { + // Calculate the radius of the map. + let Some(radius) = map.iter().map(|(_, p, _)| p.0.abs()).max() else { + warn!("The map is empty"); + return; + }; + + if radius == 0 { + warn!("The map is empty"); + return; + } + + let mut sorted_players = players.iter().collect::>(); + sorted_players.sort_by(|a: &&Player, b: &&Player| a.uuid.cmp(&b.uuid)); + + let mut sorted_players = sorted_players.iter(); + + // Calculate the distance between the players. It must be an integer because + // this is how the map is generated. + let interval = radius as usize * 3 / sorted_players.len(); + + for (i, position) in TilePosition::new(0, 0) + .ring(radius as usize / 2) + .enumerate() + { + // Check the interval between players. + if i % interval != 0 { + continue; + } + + // Find the target tile. + let Some((entity, _, mut tile)) = map.iter_mut().find(|(_, p, _)| **p == position) + else { + continue; + }; + + // Get the current player. + let Some(player) = sorted_players.next() else { + continue; + }; + + // Set the spawn point. + *tile = Tile::Castle; + commands.entity(entity).insert(Owner(Player::clone(player))); + } + } +}