Guest User

ai.rs

a guest
Sep 18th, 2019
145
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×