Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2013-11-04 16:01:21 +0000
committerStijn Buys <ingar@osirion.org>2013-11-04 16:01:21 +0000
commit5f74a6b0f3e84ec00e68cda63da6e66df33a8149 (patch)
tree4dff3ee1d4e40ac9b42ec304aefc1a8191cffe2e /src/game
parent8126e1941666f5dccd61e9ecc60db162049bb8ff (diff)
Added support for NPC patrol routes.
Diffstat (limited to 'src/game')
-rw-r--r--src/game/base/npc.cc31
-rw-r--r--src/game/base/npc.h3
-rw-r--r--src/game/base/patrol.cc198
-rw-r--r--src/game/base/patrol.h29
-rw-r--r--src/game/base/shipmodel.cc3
-rw-r--r--src/game/base/shipmodel.h18
6 files changed, 274 insertions, 8 deletions
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;