Guest User

ai.rs

a guest
Sep 18th, 2019
139
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. use specs::prelude::*;
  2. use shrev::{EventChannel};
  3. use tcod::map::FovAlgorithm;
  4. use tcod::map::Map as TcodMap;
  5. use crate::command::{Command, CommandEvent};
  6. use crate::components::{AiControl, MyTurn, Position, Target, Seeing, PlayerControl};
  7. use crate::systems::movement::{Dir};
  8. use crate::map::{EntityMap, View};
  9. use tcod::pathfinding::Dijkstra;
  10. use array2d::Array2D;
  11.  
  12.  
  13. // use std::sync::{Arc, Mutex};
  14.  
  15.  
  16. #[derive(Debug, Copy, Clone)]
  17. pub enum AiType {
  18.     Dummy,
  19.     _Friendly,
  20.     _Monster,
  21. }
  22.  
  23. pub struct Ai;
  24. impl Ai {
  25.     fn get_command(entity: Entity, ai_type: AiType, data: &AiSystemData) -> Option<Command> {
  26.         match ai_type {
  27.             AiType::Dummy => Some(Command::Move(Self::path_to_target(entity, data))),
  28.             _ => None,
  29.         }
  30.     }
  31.  
  32.     fn rank_distance(start: (i32, i32), dest: (i32, i32), point: (i32, i32), fov_map: &TcodMap, mut pathfinder: &mut Dijkstra, entity_map: &EntityMap) -> Option<(i32, (i32, i32))> {
  33.         let x = point.0;
  34.         let y = point.1;
  35.         pathfinder.find((x, y));
  36.         let num_steps = pathfinder.len();
  37.         // println!("{}", num_steps);
  38.         let mut ranking = (((dest.0 - x).pow(2) + (dest.1 - y).pow(2)) as f32).sqrt() as i32 ;
  39.         if !fov_map.is_walkable(x as i32, y as i32) {
  40.             return None
  41.         }
  42.  
  43.         // if entity_map.actors.contains_actor(x as i32, y as i32) {
  44.         //     return None
  45.         // }
  46.         Some((ranking, (x, y)))
  47.     }
  48.  
  49.     fn choose_close_point(range: i32, start: (i32, i32), dest: (i32, i32), fov_map: &TcodMap, mut pathfinder: &mut Dijkstra, entity_map: &EntityMap) -> (i32, i32) {
  50.         let mut rankings = Vec::new();
  51.         for x in (start.0 - range)..(start.0 + range) + 1  {
  52.             for y in (start.1 - range)..(start.1 + range) + 1 {
  53.                 if x <= 0 ||
  54.                  y <= 0 || x >= entity_map.width as i32 || y >= entity_map.height as i32 {
  55.                     continue
  56.                 }
  57.                 if let Some(ranking) = Self::rank_distance(start, dest, (x, y), fov_map, pathfinder, entity_map) {
  58.                     rankings.push(ranking);
  59.                 }
  60.             }
  61.         }
  62.         if rankings.is_empty() { return start }
  63.         rankings.sort_by(|a, b| a.0.cmp(&b.0));
  64.        
  65.         // println!("{:?}", rankings[0]);
  66.         let closest = ((rankings[0].1).0 as i32, (rankings[0].1).1 as i32);
  67.         closest
  68.     }
  69.  
  70.  
  71.     fn path_to_target(entity: Entity, data: &AiSystemData) -> Dir {
  72.         if let (Some(target), Some(pos), Some(seer)) = (data.targets.get(entity), data.positions.get(entity), data.seers.get(entity)) {
  73.             if let Some(dest) = data.positions.get(target.entity) {
  74.                
  75.                 let mut fov_map = data.view.map.lock().unwrap();
  76.  
  77.                 fov_map.compute_fov(pos.x, pos.y, seer.fov, true, FovAlgorithm::Basic);
  78.                 fov_map.set(pos.x, pos.y, true, true);
  79.  
  80.                 let mut step_pos = (pos.x, pos.y);
  81.  
  82.                 let mut pathfinder = Dijkstra::new_from_map(fov_map.clone(), f32::sqrt(2.0));
  83.                 pathfinder.compute_grid(step_pos);
  84.                 let dest_point = Self::choose_close_point(20, (pos.x, pos.y), (dest.x, dest.y), &fov_map, &mut pathfinder, &data.entity_map);
  85.  
  86.                 if pathfinder.find((dest_point.0, dest_point.1)) {
  87.                     if let Some(step) = pathfinder.get(0) {
  88.                         step_pos = pathfinder.walk_one_step().unwrap();
  89.                     }
  90.                 } else {
  91.                     return Dir::Nowhere;
  92.                 }
  93.  
  94.  
  95.                 if pos.x == step_pos.0 && pos.y == step_pos.1 {
  96.                     return Dir::Nowhere;
  97.                 }
  98.  
  99.                 let dx = step_pos.0 - pos.x;
  100.                 let dy = step_pos.1 - pos.y;
  101.                 let distance = ((dx.pow(2) + dy.pow(2)) as f32).sqrt();
  102.                 let dx = (dx as f32 / distance).round() as i32;
  103.                 let dy = (dy as f32 / distance).round() as i32;
  104.  
  105.                 return Dir::pos_to_dir((dx, dy))
  106.             }
  107.         }
  108.         Dir::Nowhere
  109.     }
  110.    
  111.     fn target_player(entity: Entity, data: &AiSystemData) {
  112.         if data.targets.get(entity) != None {
  113.             return
  114.         }
  115.  
  116.         if let (Some(pos), Some(seer)) = (data.positions.get(entity), data.seers.get(entity)) {
  117.             let mut fov_map = data.view.map.lock().unwrap();
  118.  
  119.     // following code doesn't work. the .join() method fails with a cryptic error. why is that?
  120.     // error[E0599]: no method named `join` found for type `(specs::Read<'_, specs::world::EntitiesRes>, specs::Storage<'_, components::Position, shred::Fetch<'_, specs::storage::MaskedStorage<components::Position>>>, specs::Storage<'_, components::PlayerControl, shred::Fetch<'_, specs::storage::MaskedStorage<components::PlayerControl>>>)` in the current scope
  121.             for (player_entity, target_pos, player) in (data.entities, data.positions, data.players).join() {
  122.                 fov_map.compute_fov(pos.x, pos.y, seer.fov, true, FovAlgorithm::Basic);
  123.                 if fov_map.is_in_fov(target_pos.x, target_pos.y) {
  124.                     data.targets.insert(entity, Target { entity: player_entity });
  125.                 }
  126.             }
  127.         }
  128.     }
  129. }
  130.  
  131. #[derive(SystemData)]
  132. pub struct AiSystemData<'a> {
  133.    pub entities: Entities<'a>,
  134.     pub players: ReadStorage<'a, PlayerControl>,
  135.    pub entity_map: ReadExpect<'a, EntityMap>,
  136.     pub positions:  ReadStorage<'a, Position>,
  137.    pub targets:     WriteStorage<'a, Target>,
  138.     pub ai_units:    ReadStorage<'a, AiControl>,
  139.    pub seers: ReadStorage<'a, Seeing>,
  140.     pub command_event_channel:  Write<'a, EventChannel<CommandEvent>>,
  141.    pub my_turns:   WriteStorage<'a, MyTurn>,
  142.     pub world_updater:  Read<'a, LazyUpdate>,
  143.    pub game_state: ReadExpect<'a, crate::GameState>,
  144.     pub view: ReadExpect<'a, View>,
  145. }
  146.  
  147.  
  148.  
  149. impl <'a> System<'a> for Ai {
  150.    type SystemData = AiSystemData<'a>;
  151.  
  152.     fn run(&mut self, mut data: Self::SystemData) {
  153.         if data.game_state.player_turn {
  154.             return;
  155.         }
  156.         for (ent, ai_unit, _my_turn, _position) in (&data.entities, &data.ai_units, &data.my_turns, &data.positions).join() {
  157.             let ai_type = ai_unit.ai_type;
  158.             let command = Self::get_command(ent, ai_type, &data);
  159.             match command {
  160.                 None => (),
  161.                 Some(_) => {
  162.                     // attach action component to player entity
  163.                     let command_event = CommandEvent::new(command.unwrap(), ent);
  164.                     data.command_event_channel.single_write(command_event);
  165.                 }
  166.             }
  167.             data.world_updater.remove::<MyTurn>(ent);
  168.         }
  169.     }
  170.  
  171.     fn setup(&mut self, world: &mut World) {
  172.         Self::SystemData::setup(world);
  173.         let command_event_channel: EventChannel<CommandEvent> = EventChannel::new();
  174.         world.insert(command_event_channel);
  175.     }
  176. }
RAW Paste Data