use crate::ecs::{ components::*, systems::* };
use crate::coordinates::Distance;
use std::collections::HashMap;
pub struct World
{
pub hecs_world : hecs::World,
movement_requests : HashMap< hecs::Entity, String >, events : Vec< GameEvent >,
elapsed_time : f32,
}
impl World
{
pub fn new() -> Self
{
Self
{
hecs_world : hecs::World::new(),
movement_requests : HashMap::new(),
events : Vec::new(),
elapsed_time : 0.0,
}
}
pub fn spawn( &mut self, components : impl hecs::DynamicBundle ) -> hecs::Entity
{
self.hecs_world.spawn( components )
}
pub fn despawn( &mut self, entity : hecs::Entity ) -> Result< (), hecs::NoSuchEntity >
{
self.hecs_world.despawn( entity )
}
pub fn query< Q : hecs::Query >( &self ) -> hecs::QueryBorrow< '_, Q >
{
self.hecs_world.query::< Q >()
}
pub fn query_mut< Q : hecs::Query >( &mut self ) -> hecs::QueryMut< '_, Q >
{
self.hecs_world.query_mut::< Q >()
}
pub fn get< T : hecs::Component >( &self, entity : hecs::Entity ) -> Result< hecs::Ref< '_, T >, hecs::ComponentError >
{
self.hecs_world.get::< &T >( entity )
}
pub fn get_mut< T : hecs::Component >( &mut self, entity : hecs::Entity ) -> Result< hecs::RefMut< '_, T >, hecs::ComponentError >
{
self.hecs_world.get::< &mut T >( entity )
}
pub fn update( &mut self, dt : f32 )
{
self.elapsed_time += dt;
self.events.clear();
AnimationSystem::update_animations( &mut self.hecs_world, dt );
AISystem::update_ai( &mut self.hecs_world, dt );
self.process_movement_requests();
let combat_events = CombatSystem::process_combat( &mut self.hecs_world );
self.process_combat_events( combat_events );
let defeated_entities = CleanupSystem::cleanup_defeated_entities( &mut self.hecs_world );
for entity in defeated_entities
{
self.events.push( GameEvent::EntityDestroyed { entity } );
}
}
pub fn request_movement< C >( &mut self, entity : hecs::Entity, _target : C )
where
C : 'static + Clone,
{
self.movement_requests.insert( entity, "movement_requested".to_string() );
}
pub fn events( &self ) -> &[ GameEvent ]
{
&self.events
}
pub fn clear_events( &mut self )
{
self.events.clear();
}
pub fn elapsed_time( &self ) -> f32
{
self.elapsed_time
}
pub fn find_entities_in_range< C >
(
&self,
center : &Position< C >,
range : u32,
) -> Vec< ( hecs::Entity, Position< C > ) >
where
C : Distance + Clone + Send + Sync + 'static,
{
find_entities_in_range( &self.hecs_world, center, range )
}
pub fn find_nearest_entity< C >
(
&self,
center : &Position< C >,
) -> Option< ( hecs::Entity, Position< C >, u32 ) >
where
C : Distance + Clone + Send + Sync + 'static,
{
find_nearest_entity( &self.hecs_world, center )
}
#[ allow( dead_code ) ]
fn process_ai_actions< C >( &mut self, actions : Vec< AIAction< C > > )
where
C : 'static + Clone,
{
for action in actions
{
match action
{
AIAction::MoveToward { entity, target_position } =>
{
self.request_movement( entity, target_position );
}
AIAction::Attack { entity, target } =>
{
self.events.push( GameEvent::AttackAttempt { attacker : entity, target } );
}
AIAction::StartPursuit { entity, target, .. } =>
{
self.events.push( GameEvent::PursuitStarted { pursuer : entity, target } );
}
AIAction::StartPatrol { entity } =>
{
self.events.push( GameEvent::PatrolStarted { entity } );
}
}
}
}
fn process_movement_requests( &mut self )
{
self.movement_requests.clear();
}
fn process_combat_events( &mut self, combat_events : Vec< CombatEvent > )
{
for event in combat_events
{
match event
{
CombatEvent::Damage { attacker, target, damage } =>
{
self.events.push( GameEvent::Damage { attacker, target, damage } );
}
CombatEvent::Defeated { entity } =>
{
self.events.push( GameEvent::EntityDefeated { entity } );
}
}
}
}
}
impl Default for World
{
fn default() -> Self
{
Self::new()
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq ) ]
pub enum GameEvent
{
EntitySpawned
{
entity : hecs::Entity,
},
EntityDestroyed
{
entity : hecs::Entity,
},
EntityDefeated
{
entity : hecs::Entity,
},
Damage
{
attacker : hecs::Entity,
target : hecs::Entity,
damage : u32,
},
PursuitStarted
{
pursuer : hecs::Entity,
target : hecs::Entity,
},
PatrolStarted
{
entity : hecs::Entity,
},
AttackAttempt
{
attacker : hecs::Entity,
target : hecs::Entity,
},
EntityMoved
{
entity : hecs::Entity,
},
TriggerActivated
{
trigger_entity : hecs::Entity,
activated_by : hecs::Entity,
},
}
pub struct EntityBuilder;
impl EntityBuilder
{
pub fn unit< C >( position : C, health : u32, stats : Stats, team : Team ) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
Health::new( health ),
stats,
team,
Size::single(),
)
}
pub fn player< C >
(
position : C,
health : u32,
stats : Stats,
player_id : u32
) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
Health::new( health ),
Movable::new( 3 ).with_diagonal(),
stats,
Team::new( 0 ), PlayerControlled::new( player_id ),
Size::single(),
)
}
pub fn enemy< C >
(
position : C,
health : u32,
stats : Stats,
team : Team,
) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
Health::new( health ),
Movable::new( 2 ),
stats,
team,
AI::new( 1.0 ), Size::single(),
)
}
pub fn obstacle< C >( position : C ) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
Size::single(),
)
}
pub fn trigger< C >( position : C, trigger_type : TriggerType ) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
Trigger::new( trigger_type ),
Size::single(),
)
}
pub fn decoration< C >( position : C, sprite : Sprite ) -> impl hecs::DynamicBundle
where
C : 'static + Send + Sync,
{
(
Position::new( position ),
sprite,
Size::single(),
)
}
}