diff options
| -rw-r--r-- | src/client/keyboard.cc | 2 | ||||
| -rw-r--r-- | src/game/base/npc.cc | 31 | ||||
| -rw-r--r-- | src/game/base/npc.h | 3 | ||||
| -rw-r--r-- | src/game/base/patrol.cc | 198 | ||||
| -rw-r--r-- | src/game/base/patrol.h | 29 | ||||
| -rw-r--r-- | src/game/base/shipmodel.cc | 3 | ||||
| -rw-r--r-- | src/game/base/shipmodel.h | 18 | 
7 files changed, 275 insertions, 9 deletions
diff --git a/src/client/keyboard.cc b/src/client/keyboard.cc index 7658041..c762a29 100644 --- a/src/client/keyboard.cc +++ b/src/client/keyboard.cc @@ -178,7 +178,7 @@ Keyboard::Keyboard()  	add_key("pageup", SDLK_PAGEUP);  	add_key("pagedown", SDLK_PAGEDOWN); -	add_key("f1", SDLK_F1); +	add_key("f1", SDLK_F1, 0, "freeflight");  	add_key("f2", SDLK_F2, 0, "@goto");  	add_key("f3", SDLK_F3, 0, "@dock");  	key = add_key("f4", SDLK_F4, 0, "@formation"); diff --git a/src/game/base/npc.cc b/src/game/base/npc.cc index f8c27d9..0997ed2 100644 --- a/src/game/base/npc.cc +++ b/src/game/base/npc.cc @@ -67,7 +67,7 @@ NPC *NPC::add_wingman(Ship *leader)  	return npc;  } -	 +  NPC::NPC(const Profile profile, const ShipModel *shipmodel) : Ship(0, shipmodel)  {  	npc_profile = profile; @@ -78,6 +78,13 @@ NPC::NPC(const Profile profile, const ShipModel *shipmodel) : Ship(0, shipmodel)  	npc_leader = 0;  } +NPC::~NPC() +{ +	if (npc_patrol) { +		npc_patrol->erase_member(this); +	} +} +  void NPC::set_mood(const Mood mood)  {  	npc_mood = mood; @@ -195,6 +202,28 @@ void NPC::frame(const unsigned long elapsed)  					unset_autopilot_flag(Ship::AutoPilotFormation);  				}  			} +			 +		} else if (patrol()) { +			// patrol leader behaviour +			 +			// autopilot_target() is set by patrol +			if (!autopilot_target()) { +				 +				target_direction = 0; +				target_pitch = 0; +				target_roll = 0; +				target_strafe = 0.0f; +				target_vstrafe = 0.0f; +				 +				target_afterburner = 0.0f; +				target_thrust = 0; +				 +				if (state() == core::Entity::Impulse) { + +					func_impulse(); +				} + +			}	  		}  	} diff --git a/src/game/base/npc.h b/src/game/base/npc.h index 5a7e176..48fff35 100644 --- a/src/game/base/npc.h +++ b/src/game/base/npc.h @@ -37,6 +37,7 @@ public:  	enum Mood { MoodWander = 0, MoodFormation = 1 };  	NPC(const Profile profile, const ShipModel *shipmodel); +	virtual ~NPC();  	/* ---- inspectors ----------------------------------------- */ @@ -65,7 +66,7 @@ public:  		return npc_leader;  	} -		/** +	/**  	 * @brief returns this NPC's patrol.  	 * */  	inline Patrol *patrol() diff --git a/src/game/base/patrol.cc b/src/game/base/patrol.cc index db13260..27bb6a3 100644 --- a/src/game/base/patrol.cc +++ b/src/game/base/patrol.cc @@ -55,17 +55,33 @@ Patrol::Patrol() : core::Entity()  	set_label("patrol");  	set_radius(1.0f); +	patrol_leader = 0; +	  	patrol_profile = NPC::ProfilePatrol; +	 +	patrol_waypoint_current == patrol_waypoints.end();  }  Patrol::~Patrol()  { +	// delete waypoints  	for (WayPoints::iterator it = patrol_waypoints.begin(); it != patrol_waypoints.end(); ++it) {  		delete (*it);  		(*it) = 0;  	}  	patrol_waypoints.clear(); +	 +	// detach and delete remaining members +	for (Members::iterator it = patrol_members.begin(); it != patrol_members.end(); ++it) { +		NPC *member = (*it); +		 +		member->set_patrol(0); +		member->die(); +		 +		(*it) = 0; +	} +	patrol_members.clear();  }  void Patrol::set_profile(const NPC::Profile profile) @@ -113,8 +129,9 @@ void Patrol::validate()  			break;  		} -		if(waypoint->dock() && !targetentity->has_flag(core::Entity::Dockable)) { -			con_warn << "  Patrol '" << label() << "' waypoint " << waypoint_counter << " set to dock at non-doackable target '" << entitylabel << "' in zone '" << zonelabel << "'\n"; +		if (waypoint->dock() && !targetentity->has_flag(core::Entity::Dockable)) { +			con_warn << "  Patrol '" << label() << "' waypoint " << waypoint_counter << " set to dock at non-dockable target '" << entitylabel << "' in zone '" << zonelabel << "'\n"; +			break;  		}  		waypoint->set_target(targetentity); @@ -150,9 +167,15 @@ void Patrol::validate()  	} else if (nbships == 0) {  		con_warn << "  Patrol '" << label() << "' without ship types" << "\n";  		die(); -		 +	} else if (!(*patrol_waypoints.begin())->target()->has_flag(core::Entity::Dockable)) { +		con_warn << "  Patrol '" << label() << "' spawn set to non-dockable target" << "\n"; +		die();	  	} else { -		con_debug << "  " << label() << " patrol with " << patrol_waypoints.size() << "waypoints" << " and " << nbships << " ship " << aux::plural("type", nbships) << std::endl; +		// spawn waypoint is dockable +		(*patrol_waypoints.begin())->set_dock(true); +		 +		con_debug << "  " << label() << " patrol " << patrol_waypoints.size() << " " << aux::plural("waypoint", patrol_waypoints.size()) << " " +		          << nbships << " ship " << aux::plural("type", nbships) << std::endl;  	}  } @@ -165,9 +188,174 @@ Patrol::WayPoint *Patrol::add_waypoint()  	return waypoint;  } -void Patrol::frame(const unsigned long elapsed) +void Patrol::add_member(NPC *npc) +{ +	npc->set_patrol(this); +	patrol_members.push_back(npc); +} + +void Patrol::erase_member(NPC *npc)  { +	Members::iterator it = patrol_members.begin();  +	 +	while (it != patrol_members.end()) { +		if ((*it) == npc) { +			(*it)->set_patrol(0); +			(*it) = 0; +			 +			patrol_members.erase(it); +			it = patrol_members.end(); +		} else { +			++it; +		} +	} +	 +	set_leader(); +} +void Patrol::set_leader() +{ +	patrol_leader = ( (patrol_members.size() > 0 ) ? (*patrol_members.begin()) : 0 ); +		 +	for (Members::iterator it = patrol_members.begin(); it != patrol_members.end(); ++it) { +		if ((*it) == patrol_leader)  { +			(*it)->set_leader(0); +		} else { +			(*it)->set_leader(patrol_leader); +		} +	} +} + +void Patrol::frame(const unsigned long elapsed) +{ +	if (patrol_waypoints.size() < 2) { +		return; +	} +	 +	if (patrol_members.size() == 0) { +		// there are no members, verify if the spawn zone has players in it and create a new patrol +		 +		patrol_waypoint_current = patrol_waypoints.begin(); +		core::Entity *spawn = waypoint()->target(); +			 +		if (spawn->has_flag(core::Entity::Dockable)) { +		 +			for (core::Inventory::Items::const_iterator it = inventory()->items().begin(); it != inventory()->items().end(); it++) { +				core::Item *item = (*it); +		 +				if (item->info()->type() != ShipModel::infotype()) { +					continue; +				} +				 +				// find shipmodel +				ShipModel *shipmodel = ShipModel::find(item->info()->label()); +				if (!shipmodel) { +					continue; +				} +				 +				// add NPC +				NPC *npc = new NPC(patrol_profile, shipmodel); +				 +				// set NPC name +				if (shipmodel->npc_name().size()) { +					npc->set_name(shipmodel->npc_name()); +				} +				 +				// patrol ships are not dockable +				if (npc->has_flag(core::Entity::Dockable)) {					 +					unset_flag(core::Entity::Dockable); +					// delete menus +					for (Menus::iterator mit = npc->menus().begin(); mit != npc->menus().end(); mit++) { +						delete (*mit); +						(*mit) = 0; +					} +					npc->menus().clear(); +				} +				 +				// dock npc at spawn +				npc->set_zone(spawn->zone()); +				npc->set_dock(spawn); +				 +				// add NPC to patrol +				add_member(npc); +			} +			 +			set_leader(); +		} +		 +	} else if (patrol_leader) { +		 +		if (patrol_leader->state() == core::Entity::Docked) { +			 +			if (patrol_leader->dock() == waypoint()->target()) { +				 +				// verify everyone in the patrol is docked +				bool group_docked = true;				 +				for (Members::iterator it = patrol_members.begin(); it != patrol_members.end(); ++it) { +					if ((*it)->state() != core::Entity::Docked) { +						group_docked = false; +					} +				} +				 +				// next waypoint +				if (group_docked) { +					patrol_waypoint_current++; +					if (patrol_waypoint_current == patrol_waypoints.end()) { +						patrol_waypoint_current = patrol_waypoints.begin(); +					} +					patrol_leader->set_autopilot_target(waypoint()->target()); +				} +				 +			} else { +				 +				patrol_leader->launch(); +			} +					 +		} else if ((patrol_leader->state() == core::Entity::Normal) || (patrol_leader->state() == core::Entity::ImpulseInitiate) || (patrol_leader->state() == core::Entity::Impulse)) { +			 +			if (waypoint()->target()->zone() == patrol_leader->zone()) { +				 +				patrol_leader->set_autopilot_target(waypoint()->target()); +					 +				patrol_leader->set_autopilot_flag(Ship::AutoPilotEnabled); +				patrol_leader->unset_autopilot_flag(Ship::AutoPilotFormation); +				 +				if ( (waypoint()->dock()) && (waypoint()->target()->has_flag(core::Entity::Dockable)) ) { +					patrol_leader->set_autopilot_flag(Ship::AutoPilotDock); +					 +				} else { +					patrol_leader->unset_autopilot_flag(Ship::AutoPilotDock); +					 +					if ( math::distance(patrol_leader->location(), waypoint()->target()->location()) < PLANET_SAFE_DISTANCE + patrol_leader->radius() + waypoint()->target()->radius() ) { +						 +						// check if other group memebers are near +						bool group_present = true; +						for (Members::iterator it = patrol_members.begin(); it != patrol_members.end(); ++it) { +							if ( math::distance(patrol_leader->location(), (*it)->location()) > 4.0f *  (patrol_leader->radius() + (*it)->radius()) ) { +								group_present = false; +							} +						} +						 +						// next waypoint +						if (group_present) { +							patrol_waypoint_current++; +							if (patrol_waypoint_current == patrol_waypoints.end()) { +								patrol_waypoint_current = patrol_waypoints.begin(); +							} +							patrol_leader->set_autopilot_target(waypoint()->target()); +						} else { +							patrol_leader->set_autopilot_target(0); +						} +					} +				} +				 +			} else { +				patrol_leader->set_autopilot_target(0); +			} +		 +		} +	 +	}  }  } diff --git a/src/game/base/patrol.h b/src/game/base/patrol.h index 3e15d3d..a747a89 100644 --- a/src/game/base/patrol.h +++ b/src/game/base/patrol.h @@ -25,6 +25,9 @@ namespace game  class Patrol: public core::Entity {  public: +	 +	/* --- WayPoint -------------------------------------------- */ +	  	/**  	 * @brief a node in the patrol's travel path  	 * */ @@ -67,15 +70,27 @@ public:  		bool 		waypoint_dock;  	}; +		 +	/* --- Patrol ---------------------------------------------- */  	typedef std::list<WayPoint *> WayPoints; +	 +	typedef std::list<NPC *> Members;  	Patrol();  	virtual ~Patrol();  	inline const NPC::Profile profile() const {  		return patrol_profile; -	}	 +	} +	 +	inline WayPoint * waypoint() { +		if (patrol_waypoint_current == patrol_waypoints.end()) { +			return 0; +		} else { +			return (*patrol_waypoint_current); +		} +	}  	void set_profile(const NPC::Profile profile); @@ -84,11 +99,23 @@ public:  	virtual void validate();  	virtual void frame(const unsigned long elapsed); +	 +	void add_member(NPC *npc); +	 +	void erase_member(NPC *npc);  private: +	void set_leader(); +	  	WayPoints		patrol_waypoints; +	WayPoints::iterator	patrol_waypoint_current; +	 +	Members			patrol_members; +	  	NPC::Profile		patrol_profile; +	 +	NPC			*patrol_leader;  };  } // namespace game diff --git a/src/game/base/shipmodel.cc b/src/game/base/shipmodel.cc index 6fd809b..3582517 100644 --- a/src/game/base/shipmodel.cc +++ b/src/game/base/shipmodel.cc @@ -74,6 +74,9 @@ bool ShipModel::init()  				} else if (inifile.got_key_string("name", str)) {  					shipmodel->set_name(str);  					continue; +				} else if (inifile.got_key_string("npcname", str)) { +					shipmodel->set_npc_name(str); +					continue;  				} else if (inifile.got_key_string("info", str)) {  					shipmodel->add_text(str);  					continue; diff --git a/src/game/base/shipmodel.h b/src/game/base/shipmodel.h index ef37cbf..2231fea 100644 --- a/src/game/base/shipmodel.h +++ b/src/game/base/shipmodel.h @@ -114,6 +114,14 @@ public:  		return shipmodel_radius;  	} +	/** +	 * @brief name used for NPCs with this ship model +	 * */ +	inline const std::string & npc_name() const +	{ +		return shipmodel_npc_name; +	} +	  	/// entity template  	inline const Template *model_template() const  	{ @@ -231,6 +239,14 @@ protected:  		shipmodel_angular_damping = angular_damping;  	} +	/** +	 * @brief set the name used for NPCs with this ship model +	 * */ +	inline void set_npc_name(const std::string name) +	{ +		shipmodel_npc_name.assign(name); +	} +	  public:  	/**  	 * @brief generate specifications info. @@ -279,6 +295,8 @@ private:  	const Template		*shipmodel_template; +	std::string		shipmodel_npc_name; +	  	/* --- static ----------------------------------------------------- */  	static core::InfoType *shipmodel_infotype;  | 
