From fd9444462aa349587bc1b3ebc35f2c3561584098 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Mon, 27 May 2019 12:18:14 +0100
Subject: [PATCH 1/3] Added enemies

Former-commit-id: 2c07c9e52a7cbfb85508e7098c528bddd9b12997
---
 common/src/comp/agent.rs |  3 +++
 common/src/sys/agent.rs  | 48 +++++++++++++++++++++++++++++++++++++---
 server/src/cmd.rs        | 32 +++++++++++++++++++++++++++
 server/src/lib.rs        |  3 ++-
 4 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs
index 37a9faf6e6..97fa052c6b 100644
--- a/common/src/comp/agent.rs
+++ b/common/src/comp/agent.rs
@@ -8,6 +8,9 @@ pub enum Agent {
         target: EcsEntity,
         offset: Vec2<f32>,
     },
+    Enemy {
+        target: Option<EcsEntity>,
+    },
 }
 
 impl Component for Agent {
diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index 8a5687ccfe..8c8a7dd0b8 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -1,25 +1,31 @@
 // Library
 use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
 use vek::*;
+use rand::Rng;
 
 // Crate
-use crate::comp::{phys::Pos, Agent, Control, Jumping};
+use crate::{
+    comp::{phys::Pos, Agent, Control, Jumping, Attacking},
+    state::Time,
+};
 
 // Basic ECS AI agent system
 pub struct Sys;
 
 impl<'a> System<'a> for Sys {
     type SystemData = (
+        Read<'a, Time>,
         Entities<'a>,
         WriteStorage<'a, Agent>,
         ReadStorage<'a, Pos>,
         WriteStorage<'a, Control>,
         WriteStorage<'a, Jumping>,
+        WriteStorage<'a, Attacking>,
     );
 
     fn run(
         &mut self,
-        (entities, mut agents, positions, mut controls, mut jumpings): Self::SystemData,
+        (time, entities, mut agents, positions, mut controls, mut jumpings, mut attackings): Self::SystemData,
     ) {
         for (entity, agent, pos, control) in
             (&entities, &mut agents, &positions, &mut controls).join()
@@ -64,7 +70,43 @@ impl<'a> System<'a> for Sys {
                             Vec2::new(rand::random::<f32>() - 0.5, rand::random::<f32>() - 0.5)
                                 * 10.0;
                     }
-                }
+                },
+                Agent::Enemy { target } => {
+                    let choose_new = match target.map(|tgt| positions.get(tgt)).flatten() {
+                        Some(tgt_pos) => {
+                            let dist = Vec2::<f32>::from(tgt_pos.0 - pos.0).magnitude();
+                            if dist < 2.0 {
+                                control.move_dir = Vec2::zero();
+
+                                if rand::random::<f32>() < 0.2 {
+                                    attackings.insert(entity, Attacking::start());
+                                }
+
+                                false
+                            } else if dist < 60.0 {
+                                control.move_dir = Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
+
+                                false
+                            } else {
+                                true
+                            }
+                        },
+                        None => {
+                            control.move_dir = Vec2::one();
+                            rand::random::<f32>().fract() < 0.25
+                        },
+                    };
+
+                    if choose_new {
+                        let entities = (&entities, &positions)
+                            .join()
+                            .filter(|(_, e_pos)| Vec2::<f32>::from(e_pos.0 - pos.0).magnitude() < 30.0)
+                            .map(|(e, _)| e)
+                            .collect::<Vec<_>>();
+
+                        *target = rand::thread_rng().choose(&entities).cloned();
+                    }
+                },
             }
         }
     }
diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index 74c975eccb..5771e06090 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -93,6 +93,12 @@ lazy_static! {
             "/wolf : Spawn a test wolf NPC",
             handle_petwolf
         ),
+        ChatCommand::new(
+            "enemy",
+            "{}",
+            "/enemy : Spawn a test enemy NPC",
+            handle_enemy
+        ),
         ChatCommand::new(
             "help", "", "/help: Display this message", handle_help)
     ];
@@ -266,6 +272,32 @@ fn handle_petwolf(server: &mut Server, entity: EcsEntity, args: String, action:
             .notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
     }
 }
+fn handle_enemy(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
+    match server
+        .state
+        .read_component_cloned::<comp::phys::Pos>(entity)
+    {
+        Some(mut pos) => {
+            pos.0.x += 1.0; // Temp fix TODO: Solve NaN issue with positions of pets
+            server
+                .create_npc(
+                    pos,
+                    "Tobermory".to_owned(),
+                    comp::Body::Humanoid(comp::HumanoidBody::random()),
+                )
+                .with(comp::Agent::Enemy {
+                    target: None,
+                })
+                .build();
+            server
+                .clients
+                .notify(entity, ServerMsg::Chat("Spawned enemy!".to_owned()));
+        }
+        None => server
+            .clients
+            .notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
+    }
+}
 fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
     for cmd in CHAT_COMMANDS.iter() {
         server
diff --git a/server/src/lib.rs b/server/src/lib.rs
index ca9e52afa2..23e055bbf9 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -136,12 +136,13 @@ impl Server {
             .ecs_mut()
             .create_entity_synced()
             .with(pos)
-            .with(comp::Control::default())
             .with(comp::phys::Vel(Vec3::zero()))
             .with(comp::phys::Dir(Vec3::unit_y()))
+            .with(comp::Control::default())
             .with(comp::AnimationInfo::default())
             .with(comp::Actor::Character { name, body })
             .with(comp::Stats::default())
+            .with(comp::phys::ForceUpdate)
     }
 
     pub fn create_player_character(

From 15979d5528032c1202ae5011b7aaec51f1be68a5 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Tue, 28 May 2019 00:04:25 +0100
Subject: [PATCH 2/3] Sort of fixed enemy freezes

Former-commit-id: 30933b3ff7d16428a107ade6163cb83562668b66
---
 common/src/sys/agent.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index 8c8a7dd0b8..a9dcf46dc8 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -93,7 +93,7 @@ impl<'a> System<'a> for Sys {
                         },
                         None => {
                             control.move_dir = Vec2::one();
-                            rand::random::<f32>().fract() < 0.25
+                            true
                         },
                     };
 

From e2f65627af48896cf312ba7820245cdc75536a19 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Tue, 28 May 2019 19:59:32 +0100
Subject: [PATCH 3/3] fmt

Former-commit-id: 7535fe743722967dd59e383aa93cb78cb3be6e23
---
 common/src/sys/agent.rs | 19 +++++++++++--------
 server/src/cmd.rs       |  4 +---
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index a9dcf46dc8..1b8e359d31 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -1,11 +1,11 @@
 // Library
+use rand::Rng;
 use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
 use vek::*;
-use rand::Rng;
 
 // Crate
 use crate::{
-    comp::{phys::Pos, Agent, Control, Jumping, Attacking},
+    comp::{phys::Pos, Agent, Attacking, Control, Jumping},
     state::Time,
 };
 
@@ -70,7 +70,7 @@ impl<'a> System<'a> for Sys {
                             Vec2::new(rand::random::<f32>() - 0.5, rand::random::<f32>() - 0.5)
                                 * 10.0;
                     }
-                },
+                }
                 Agent::Enemy { target } => {
                     let choose_new = match target.map(|tgt| positions.get(tgt)).flatten() {
                         Some(tgt_pos) => {
@@ -84,29 +84,32 @@ impl<'a> System<'a> for Sys {
 
                                 false
                             } else if dist < 60.0 {
-                                control.move_dir = Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
+                                control.move_dir =
+                                    Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
 
                                 false
                             } else {
                                 true
                             }
-                        },
+                        }
                         None => {
                             control.move_dir = Vec2::one();
                             true
-                        },
+                        }
                     };
 
                     if choose_new {
                         let entities = (&entities, &positions)
                             .join()
-                            .filter(|(_, e_pos)| Vec2::<f32>::from(e_pos.0 - pos.0).magnitude() < 30.0)
+                            .filter(|(_, e_pos)| {
+                                Vec2::<f32>::from(e_pos.0 - pos.0).magnitude() < 30.0
+                            })
                             .map(|(e, _)| e)
                             .collect::<Vec<_>>();
 
                         *target = rand::thread_rng().choose(&entities).cloned();
                     }
-                },
+                }
             }
         }
     }
diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index 5771e06090..d21c554416 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -285,9 +285,7 @@ fn handle_enemy(server: &mut Server, entity: EcsEntity, args: String, action: &C
                     "Tobermory".to_owned(),
                     comp::Body::Humanoid(comp::HumanoidBody::random()),
                 )
-                .with(comp::Agent::Enemy {
-                    target: None,
-                })
+                .with(comp::Agent::Enemy { target: None })
                 .build();
             server
                 .clients