From f009487bbe6120f8f487302f5e1bb4ae606a51af Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Sun, 10 Nov 2013 19:01:43 +0000
Subject: Made NPCs only fire weapons on enemies within weapon range.

---
 src/game/base/npc.cc    | 44 ++++++++++++++++++++++++++++++++++++++++----
 src/game/base/npc.h     |  9 ++++++++-
 src/game/base/patrol.cc |  2 ++
 src/game/base/ship.cc   |  2 +-
 src/game/base/weapon.h  |  8 ++++++++
 5 files changed, 59 insertions(+), 6 deletions(-)

(limited to 'src/game/base')

diff --git a/src/game/base/npc.cc b/src/game/base/npc.cc
index ca2a1c2..bb716c9 100644
--- a/src/game/base/npc.cc
+++ b/src/game/base/npc.cc
@@ -65,6 +65,8 @@ NPC *NPC::add_wingman(Ship *leader)
 		npc_slot->set_flag(core::Slot::Mounted);
 	}
 	
+	npc->calculate_weapon_range();
+	
 	npc->reset();
 	
 	return npc;
@@ -77,6 +79,8 @@ NPC::NPC(const ShipModel *shipmodel) : Ship(0, shipmodel)
 	
 	npc_patrol = 0;
 	npc_leader = 0;
+	
+	npc_weapon_range = 0.0f;
 }
 
 NPC::~NPC()
@@ -86,6 +90,38 @@ NPC::~NPC()
 	}
 }
 
+void NPC::calculate_weapon_range()
+{
+	npc_weapon_range = 0.0f;
+	
+	if (!slots()) {
+		return;
+	}
+	
+	for (core::Slots::const_iterator it = slots()->begin(); it != slots()->end(); it++) {
+		core::Slot *slot = (*it);
+		
+		if (!slot->has_flag(core::Slot::Mounted)) {
+			continue;
+				
+		} else if (!slot->item() || (slot->item()->info()->type() != Weapon::infotype())) {
+			continue;
+				
+		} else {
+			const Weapon *weapon = static_cast<const Weapon *>(slot->item()->info());
+				
+			if ((weapon->subtype() != Weapon::Cannon) && (weapon->subtype() != Weapon::Turret) ) {
+				continue;
+			}
+			const float r = weapon->projectile_range();
+			
+			if (r > npc_weapon_range) {
+				npc_weapon_range = r;
+			}
+		}
+	}
+}
+
 void NPC::set_mood(const Mood mood)
 {
 	npc_mood = mood;
@@ -107,6 +143,9 @@ Ship *NPC::target_closest_enemy()
 	Ship *current_enemy = 0;
 	float current_distance = 0.0f;
 	
+	if (!npc_weapon_range) {
+		return 0;
+	}
 
 	for (core::Zone::Content::iterator zit = zone()->content().begin(); zit != zone()->content().end(); ++zit) {
 		if (((*zit)->moduletype() == ship_enttype) && ((*zit) != this)) {
@@ -149,11 +188,8 @@ Ship *NPC::target_closest_enemy()
 		}
 	}
 	
-	// FIXME calculate weaposn range, arbitrarily set to 10 km
-	const float weapons_range = COMBAT_DISTANCE;
-	
 	// set aim
-	if ((state() == Normal) && current_enemy && (current_distance <= weapons_range)) {
+	if ((state() == Normal) && current_enemy && (current_distance <= radius() + npc_weapon_range)) {
 		// activate weapons
 		set_target_controlflag(core::EntityControlable::ControlFlagFire);
 		// rudimentary aim currention
diff --git a/src/game/base/npc.h b/src/game/base/npc.h
index 68620e1..39395c0 100644
--- a/src/game/base/npc.h
+++ b/src/game/base/npc.h
@@ -76,7 +76,6 @@ public:
 	 * */
 	virtual void frame(const unsigned long elapsed);
 	
-	
 	/**
 	 * @brief factory function for wingman NPCs
 	 * */
@@ -86,6 +85,12 @@ public:
 	 * @brief aim at closest enemy in range, returns target
 	 * */
 	Ship *target_closest_enemy();
+	
+	/**
+	 * @brief calculate weapon range
+	 * Calling calculate_weapon_range() will set npc_weapon_range.
+	 * */
+	void calculate_weapon_range();
 
 private:
 	Mood			npc_mood;
@@ -96,6 +101,8 @@ private:
 	
 	unsigned long		npc_destroyed_timestamp;
 	
+	float			npc_weapon_range;
+	
 }; // class NPC
 
 } // namespace game
diff --git a/src/game/base/patrol.cc b/src/game/base/patrol.cc
index 6640cb8..3df277a 100644
--- a/src/game/base/patrol.cc
+++ b/src/game/base/patrol.cc
@@ -362,6 +362,8 @@ void Patrol::create_patrol()
 				
 				npc->inventory()->recalculate();
 				
+				npc->calculate_weapon_range();
+				
 				// dock npc at spawn
 				npc->set_zone(spawn->zone());
 				npc->set_dock(spawn);
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index 9c2605d..368fc11 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -1142,7 +1142,7 @@ void Ship::frame(const unsigned long elapsed)
 			if (!slot->has_flag(core::Slot::Mounted)) {
 				continue;
 				
-			} else if ( !(slot->item() && (slot->item()->info()->type() == Weapon::infotype()))) {
+			} else if (!slot->item() || (slot->item()->info()->type() != Weapon::infotype())) {
 				continue;
 				
 			} else {
diff --git a/src/game/base/weapon.h b/src/game/base/weapon.h
index ee67cfc..a6a5731 100644
--- a/src/game/base/weapon.h
+++ b/src/game/base/weapon.h
@@ -56,6 +56,14 @@ public:
 		return weapon_projectile_speed;
 	}
 	
+	/**
+	 * @brief projectile range, in game units
+	 * */
+	inline const float projectile_range() const
+	{
+		return (weapon_projectile_speed * ((float) weapon_projectile_lifespan) / 1000.0f);
+	}
+	
 	/**
 	 * @brief interval between consequtive projectils fired by this weapon, in milliseconds
 	 * */
-- 
cgit v1.2.3