From 8126e1941666f5dccd61e9ecc60db162049bb8ff Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sun, 3 Nov 2013 23:35:59 +0000 Subject: Added initial support for NPC patrol routes, added support for lawfull/unlawfull factions. --- src/game/base/Makefile.am | 2 + src/game/base/faction.cc | 4 ++ src/game/base/faction.h | 10 +++ src/game/base/game.cc | 119 +++++++++++++++++++++++++------ src/game/base/game.h | 1 + src/game/base/jumppoint.cc | 20 +++--- src/game/base/jumppoint.h | 12 ++-- src/game/base/npc.cc | 9 +++ src/game/base/npc.h | 24 ++++++- src/game/base/patrol.cc | 173 +++++++++++++++++++++++++++++++++++++++++++++ src/game/base/patrol.h | 96 +++++++++++++++++++++++++ 11 files changed, 431 insertions(+), 39 deletions(-) create mode 100644 src/game/base/patrol.cc create mode 100644 src/game/base/patrol.h diff --git a/src/game/base/Makefile.am b/src/game/base/Makefile.am index 3d6840a..634a571 100644 --- a/src/game/base/Makefile.am +++ b/src/game/base/Makefile.am @@ -11,6 +11,7 @@ noinst_HEADERS = \ jumppoint.h \ navpoint.h \ npc.h \ + patrol.h \ planet.h \ racetrack.h \ savegame.h \ @@ -30,6 +31,7 @@ libbase_la_SOURCES = \ jumppoint.cc \ navpoint.cc \ npc.cc \ + patrol.cc \ planet.cc \ racetrack.cc \ savegame.cc \ diff --git a/src/game/base/faction.cc b/src/game/base/faction.cc index 323a199..80dfc9f 100644 --- a/src/game/base/faction.cc +++ b/src/game/base/faction.cc @@ -52,6 +52,7 @@ bool Faction::init() Faction *faction = 0; std::string strvalue; math::Color colorvalue; + bool b = false; while (inifile.getline()) { @@ -86,6 +87,8 @@ bool Faction::init() } else if (inifile.got_key_color("colorsecond", colorvalue)) { faction->set_color_second(colorvalue); + } else if (inifile.got_key_bool("lawfull", b)) { + faction->set_lawfull(b); } else { inifile.unknown_key(); } @@ -118,6 +121,7 @@ Faction::Faction() : faction_color(), faction_color_second() { + faction_lawfull = true; } Faction::~Faction() diff --git a/src/game/base/faction.h b/src/game/base/faction.h index 997b6fc..3775043 100644 --- a/src/game/base/faction.h +++ b/src/game/base/faction.h @@ -30,6 +30,10 @@ public: return faction_color_second; } + inline const bool lawfull() const { + return faction_lawfull; + } + /* --- actors ----------------------------------------------------- */ /** @@ -47,6 +51,10 @@ public: faction_color_second.assign(color_second); } + inline void set_lawfull(const bool lawfull) { + faction_lawfull = lawfull; + } + /* --- static ----------------------------------------------------- */ /** @@ -70,6 +78,8 @@ private: math::Color faction_color; math::Color faction_color_second; + bool faction_lawfull; + /* --- static ----------------------------------------------------- */ static core::InfoType *faction_infotype; diff --git a/src/game/base/game.cc b/src/game/base/game.cc index ad6a28c..0bdf2cc 100644 --- a/src/game/base/game.cc +++ b/src/game/base/game.cc @@ -25,6 +25,7 @@ #include "base/navpoint.h" #include "base/jumppoint.h" #include "base/npc.h" +#include "base/patrol.h" #include "base/planet.h" #include "base/savegame.h" #include "base/spacemine.h" @@ -1922,13 +1923,16 @@ bool Game::load_zone(core::Zone *zone) core::Inventory *inventory = 0; core::Item *item = 0; - Station *station = 0; - Planet *planet = 0; - Star *star = 0; - NavPoint *navpoint = 0; - JumpPoint *jumppoint = 0; - RaceTrack *racetrack = 0; - CheckPoint *checkpoint = 0; + Station *station = 0; + Planet *planet = 0; + Star *star = 0; + NavPoint *navpoint = 0; + JumpPoint *jumppoint = 0; + RaceTrack *racetrack = 0; + CheckPoint *racetrack_checkpoint = 0; + + Patrol *patrol = 0; + Patrol::WayPoint *patrol_waypoint = 0; bool b; long l; @@ -1973,17 +1977,36 @@ bool Game::load_zone(core::Zone *zone) entity = racetrack; racetrack->set_zone(zone); racetrack->set_radius(0); + + racetrack_checkpoint = 0; } else if (zoneini.got_section("checkpoint")) { + racetrack_checkpoint = 0; if (!racetrack) { - zoneini.unknown_error("checkpoint without racetrack"); - entity = 0; - checkpoint = 0; + zoneini.unknown_error("checkpoint definition without racetrack"); + } else { + racetrack_checkpoint = new CheckPoint(racetrack); + entity = racetrack_checkpoint; + racetrack_checkpoint->set_radius(0); + } + + } else if (zoneini.got_section("patrol")) { + patrol = new Patrol(); + entity = patrol; + patrol->set_zone(zone); + + patrol_waypoint = 0; + + } else if (zoneini.got_section("waypoint")) { + patrol_waypoint = 0; + + if (!entity || !patrol) { + zoneini.unknown_error("waypoint definition without patrol"); + } else if ((entity->moduletype() != patrol_enttype)) { + zoneini.unknown_error("waypoint definition for invalid entity type"); } else { - checkpoint = new CheckPoint(racetrack); - entity = checkpoint; - checkpoint->set_radius(0); + patrol_waypoint = patrol->add_waypoint(); } } else if (zoneini.got_section("planet")) { @@ -2028,7 +2051,7 @@ bool Game::load_zone(core::Zone *zone) if (!entity) { zoneini.unknown_error("ship definition without entity"); - } else if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype)) { + } else if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype) && (entity->moduletype() != patrol_enttype)) { zoneini.unknown_error("ship definition for invalid entity type"); } else { inventory = entity->inventory(); @@ -2128,7 +2151,7 @@ bool Game::load_zone(core::Zone *zone) if (core::Parser::got_entity_key(zoneini, jumppoint)) { continue; } else if (zoneini.got_key_string("target", strval)) { - jumppoint->set_targetlabel(strval); + jumppoint->set_target_label(strval); continue; } else { zoneini.unknown_key(); @@ -2152,11 +2175,48 @@ bool Game::load_zone(core::Zone *zone) entitytemplate->apply(jumppoint); } } else if (zoneini.got_key_string("target", strval)) { - jumppoint->set_targetlabel(strval); + jumppoint->set_target_label(strval); continue; } else { zoneini.unknown_key(); } + + } else if (zoneini.in_section("patrol")) { + if (core::Parser::got_entity_key(zoneini, patrol)) { + continue; + } else if (zoneini.got_key_label("profile", strval)) { + if (strval.compare("convoy")) { + patrol->set_profile(NPC::ProfileConvoy); + } else if (strval.compare("patrol")) { + patrol->set_profile(NPC::ProfilePatrol); + } else { + zoneini.unknown_error("unknown profile '" + strval + "'"); + } + } else if (zoneini.got_key_label("faction", strval)) { + Faction *faction = Faction::find(strval); + if (!faction) { + zoneini.unknown_error("unknown faction '" + strval + "'"); + } else { + faction->apply(patrol); + } + } else { + zoneini.unknown_key(); + } + + } else if (zoneini.in_section("waypoint")) { + if (!patrol_waypoint) { + continue; + } else if (zoneini.got_key_string("target", strval)) { + patrol_waypoint->set_target_label(strval); + continue; + } else if (zoneini.got_key_string("buy", strval)) { + patrol_waypoint->set_buy_label(strval); + continue; + } else if (zoneini.got_key_bool("dock", b)) { + patrol_waypoint->set_dock(b); + } else { + zoneini.unknown_key(); + } } else if (zoneini.in_section("planet")) { if (core::Parser::got_entity_key(zoneini, planet)) { @@ -2223,7 +2283,9 @@ bool Game::load_zone(core::Zone *zone) } } else if (zoneini.in_section("checkpoint")) { - if (core::Parser::got_entity_key(zoneini, checkpoint)) { + if (!racetrack_checkpoint) { + continue; + } else if (core::Parser::got_entity_key(zoneini, racetrack_checkpoint)) { continue; } else { zoneini.unknown_key(); @@ -2357,17 +2419,30 @@ bool Game::load_zone(core::Zone *zone) if (zoneini.got_key_label("label", strval)) { ShipModel *shipmodel= ShipModel::find(strval); if (shipmodel) { - item = inventory->find(shipmodel); + + if (entity->moduletype() == patrol_enttype) { + item = 0; + } else { + item = inventory->find(shipmodel); + } + if (!item) { item = new core::Item(shipmodel); - item->set_amount(-1); + if ((entity->moduletype() == patrol_enttype)) { + item->set_amount(1); + } else { + item->set_amount(-1); + } item->set_price(shipmodel->price()); inventory->add(item); } } else { zoneini.unknown_error("unknown ship type '" + strval + "'"); } - + } else if ((entity->moduletype() == patrol_enttype) && zoneini.got_key_long("amount", l)) { + if (item) { + item->set_amount(l); + } } else if (zoneini.got_key_long("price", l)) { if (item) { item->set_price(l); @@ -2399,6 +2474,10 @@ bool Game::validate_zone(core::Zone *zone) // validate jump gate JumpGate *jumpgate = static_cast(entity); jumpgate->validate(); + } else if (entity->entity_moduletypeid == patrol_enttype) { + // validate jump gate + Patrol *patrol = static_cast(entity); + patrol->validate(); } else { if (entity->has_flag(core::Entity::Dockable)) { generate_entity_menus(entity); diff --git a/src/game/base/game.h b/src/game/base/game.h index 2fc5d95..bb1c9ae 100644 --- a/src/game/base/game.h +++ b/src/game/base/game.h @@ -36,6 +36,7 @@ const unsigned int station_enttype = 262; const unsigned int cargopod_enttype = 263; const unsigned int spacemine_enttype = 264; const unsigned int race_enttype = 280; +const unsigned int patrol_enttype = 512; // ship engine delay times const float jump_timer_delay = 5.0f; diff --git a/src/game/base/jumppoint.cc b/src/game/base/jumppoint.cc index e1b9c7e..d173aee 100644 --- a/src/game/base/jumppoint.cc +++ b/src/game/base/jumppoint.cc @@ -40,30 +40,30 @@ JumpPoint::~JumpPoint() { } -void JumpPoint::set_targetlabel(const std::string &label) +void JumpPoint::set_target_label(const std::string &label) { - jumppoint_targetlabel.assign(label); + jumppoint_target_label.assign(label); } void JumpPoint::validate() { jumppoint_target = 0; - if (targetlabel().size() == 0) + if (target_label().size() == 0) return; - if (targetlabel().size() < 3) { - con_warn << " Jumppoint '" << label() << "' has invalid target '" << targetlabel() << "'\n"; + if (target_label().size() < 3) { + con_warn << " Jumppoint '" << label() << "' has invalid target '" << target_label() << "'\n"; return; } - size_t pos = targetlabel().find(':'); - if ((pos == std::string::npos) || (pos < 1) || (pos >= (targetlabel().size() - 1))) { - con_warn << " Jumppoint '" << label() << "' has invalid target '" << targetlabel() << "'\n"; + size_t pos = target_label().find(':'); + if ((pos == std::string::npos) || (pos < 1) || (pos >= (target_label().size() - 1))) { + con_warn << " Jumppoint '" << label() << "' has invalid target '" << target_label() << "'\n"; return; } - std::string zonelabel(targetlabel().substr(0, pos)); - std::string entitylabel(targetlabel().substr(pos + 1, targetlabel().size() - pos)); + std::string zonelabel(target_label().substr(0, pos)); + std::string entitylabel(target_label().substr(pos + 1, target_label().size() - pos)); core::Zone *targetzone = core::Zone::find(zonelabel); if (!targetzone) { diff --git a/src/game/base/jumppoint.h b/src/game/base/jumppoint.h index 33a9f9f..655d133 100644 --- a/src/game/base/jumppoint.h +++ b/src/game/base/jumppoint.h @@ -31,8 +31,8 @@ public: JumpPoint(); virtual ~JumpPoint(); - inline std::string const & targetlabel() { - return jumppoint_targetlabel; + inline std::string const & target_label() { + return jumppoint_target_label; } inline JumpPoint *target() { @@ -40,9 +40,9 @@ public: } /// set trget label - void set_targetlabel(const std::string &label); + void set_target_label(const std::string &label); - /// validate the targetlabel and set target() + /// validate the target_label and set target() virtual void validate(); static inline void set_template (const Template *entitytemplate) { @@ -50,7 +50,7 @@ public: } private: - std::string jumppoint_targetlabel; + std::string jumppoint_target_label; JumpPoint *jumppoint_target; static const Template *jumppoint_template; @@ -63,7 +63,7 @@ public: JumpGate(); virtual ~JumpGate(); - /// validate the targetlabel and set target() + /// validate the target_label and set target() virtual void validate(); /// a ship wants to use the jumpgate diff --git a/src/game/base/npc.cc b/src/game/base/npc.cc index 8b81f04..f8c27d9 100644 --- a/src/game/base/npc.cc +++ b/src/game/base/npc.cc @@ -6,6 +6,7 @@ #include "base/npc.h" #include "base/game.h" +#include "base/patrol.h" namespace game { @@ -72,6 +73,9 @@ NPC::NPC(const Profile profile, const ShipModel *shipmodel) : Ship(0, shipmodel) npc_profile = profile; npc_mood = MoodWander; npc_destroyed_timestamp = 0; + + npc_patrol = 0; + npc_leader = 0; } void NPC::set_mood(const Mood mood) @@ -84,6 +88,11 @@ void NPC::set_leader(Ship *leader) npc_leader = leader; } +void NPC::set_patrol(Patrol *patrol) +{ + npc_patrol = patrol; +} + void NPC::frame(const unsigned long elapsed) { if (state() == core::Entity::Destroyed) { diff --git a/src/game/base/npc.h b/src/game/base/npc.h index 4a89529..5a7e176 100644 --- a/src/game/base/npc.h +++ b/src/game/base/npc.h @@ -12,6 +12,8 @@ namespace game { +class Patrol; + class NPC : public Ship { public: @@ -20,11 +22,12 @@ public: * The NPC profile is set at creating time and can not be altered. * * Freelancer fallback value - * Trader Trade convoy member, prefers trade routes - * Military Police or military, prefers patrol routes + * Convoy Trade convoy member, prefers trade routes + * Patrol Police or military, prefers patrol routes + * Guard Guard an area * Wingman wingman, prefers protecting its leader * */ - enum Profile { ProfileFreelancer = 0, ProfileTrader = 1, ProfileMilitary = 2, ProfilePirate = 3, ProfileWingman = 4 }; + enum Profile { ProfileFreelancer = 0, ProfileConvoy = 1, ProfilePatrol = 2, ProfileGuard = 3, ProfileWingman = 4 }; /** * @brief Defines the general moode of the NPC @@ -62,6 +65,14 @@ public: return npc_leader; } + /** + * @brief returns this NPC's patrol. + * */ + inline Patrol *patrol() + { + return npc_patrol; + } + /* ---- mutators ------------------------------------------- */ /** @@ -74,6 +85,11 @@ public: * */ void set_leader(Ship *leader); + /** + * @brief set the NPC's patrol + * */ + void set_patrol(Patrol *patrol); + /** * @brief game frame * */ @@ -92,6 +108,8 @@ private: Ship *npc_leader; + Patrol *npc_patrol; + unsigned long npc_destroyed_timestamp; }; // class NPC diff --git a/src/game/base/patrol.cc b/src/game/base/patrol.cc new file mode 100644 index 0000000..db13260 --- /dev/null +++ b/src/game/base/patrol.cc @@ -0,0 +1,173 @@ +/* + base/patrol.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "base/patrol.h" +#include "base/game.h" + +namespace game { + +/* --- WayPoint atrol ------------------------------------------------------ */ + +Patrol::WayPoint::WayPoint() { + waypoint_target = 0; + waypoint_dock = false; +} + +Patrol::WayPoint::~WayPoint() { + waypoint_target = 0; +} + +void Patrol::WayPoint::set_target_label(const std::string &label) +{ + waypoint_target_label.assign(label); +} + +void Patrol::WayPoint::set_target(core::Entity *entity) +{ + waypoint_target = entity; +} + +void Patrol::WayPoint::set_dock(const bool dock) +{ + waypoint_dock = dock; +} + +void Patrol::WayPoint::set_buy_label(const std::string &label) +{ + waypoint_buy_label.assign(label); +} + +/* --- Patrol ------------------------------------------------------ */ + +Patrol::Patrol() : core::Entity() +{ + // this is a server-side only entity + set_serverside(true); + + unset_flag(core::Entity::ShowOnMap); + set_flag(core::Entity::NonSolid); + + entity_moduletypeid = patrol_enttype; + + set_label("patrol"); + set_radius(1.0f); + + patrol_profile = NPC::ProfilePatrol; +} + + +Patrol::~Patrol() +{ + for (WayPoints::iterator it = patrol_waypoints.begin(); it != patrol_waypoints.end(); ++it) { + delete (*it); + (*it) = 0; + } + patrol_waypoints.clear(); +} + +void Patrol::set_profile(const NPC::Profile profile) +{ + patrol_profile = profile; +} + +void Patrol::validate() +{ + int waypoint_counter = 1; + + for (WayPoints::iterator it = patrol_waypoints.begin(); it != patrol_waypoints.end(); ++it) { + WayPoint *waypoint = (*it); + + if (waypoint->target_label().size() == 0) { + con_warn << " Patrol '" << label() << "' WayPoint " << waypoint_counter << " has no target" << "'\n"; + break; + } + + std::string entitylabel; + std::string zonelabel; + + core::Zone *targetzone = 0; + + size_t pos = waypoint->target_label().find(':'); + if ((pos == std::string::npos) || (pos < 1) || (pos >= (waypoint->target_label().size() - 1))) { + targetzone = zone(); + + zonelabel.assign(zone()->label()); + entitylabel.assign(waypoint->target_label()); + } else { + zonelabel.assign(waypoint->target_label().substr(0, pos)); + entitylabel.assign(waypoint->target_label().substr(pos + 1, waypoint->target_label().size() - pos)); + + core::Zone::find(zonelabel); + if (!targetzone) { + con_warn << " Patrol '" << label() << "' waypoint " << waypoint_counter << " has invalid target zone '" << zonelabel << "'\n"; + break; + } + } + + core::Entity *targetentity = targetzone->find_entity(entitylabel); + if (!targetentity) { + con_warn << " Patrol '" << label() << "' waypoint " << waypoint_counter << " has unknown target '" << entitylabel << "' in zone '" << zonelabel << "'\n"; + 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"; + } + + waypoint->set_target(targetentity); + } + + // remove invalid waypoints + for (WayPoints::iterator it = patrol_waypoints.begin(); it != patrol_waypoints.end(); ) { + WayPoint *waypoint = (*it); + + if (!waypoint->target()) { + delete waypoint; + (*it) = 0; + + patrol_waypoints.erase(it++); + } else { + ++it; + } + } + + size_t nbships = 0; + 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()) { + nbships++; + } + } + + if (patrol_waypoints.size() == 0) { + con_warn << " Patrol '" << label() << "' without waypoints" << "\n"; + die(); + + } else if (nbships == 0) { + con_warn << " Patrol '" << label() << "' without ship types" << "\n"; + die(); + + } else { + con_debug << " " << label() << " patrol with " << patrol_waypoints.size() << "waypoints" << " and " << nbships << " ship " << aux::plural("type", nbships) << std::endl; + } +} + +Patrol::WayPoint *Patrol::add_waypoint() +{ + WayPoint *waypoint = new WayPoint(); + + patrol_waypoints.push_back(waypoint); + + return waypoint; +} + +void Patrol::frame(const unsigned long elapsed) +{ + +} + +} diff --git a/src/game/base/patrol.h b/src/game/base/patrol.h new file mode 100644 index 0000000..3e15d3d --- /dev/null +++ b/src/game/base/patrol.h @@ -0,0 +1,96 @@ +/* + base/patrol.h + This file is part of the Osirion project and is distributed under + the terms and conditions of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_BASE_PATROL_H__ +#define __INCLUDED_BASE_PATROL_H__ + +#include "core/entity.h" +#include "base/faction.h" +#include "base/npc.h" + +namespace game +{ + +/** + * @brief a patrol entity manages a group of NPCs. + * A Patrol instance is a server-side entity used to manage + * a group of NPC ships. It manages group purpose, group commands + * and respawning by giving orders to the member NPCs. + * A Patrol can manage any kind of NPC group: + * be it a patrol, a trade convoy or a player wing. + * */ +class Patrol: public core::Entity { + +public: + /** + * @brief a node in the patrol's travel path + * */ + class WayPoint { + public: + WayPoint(); + ~WayPoint(); + + inline core::Entity *target() + { + return waypoint_target; + } + + inline const std::string & target_label() const { + return waypoint_target_label; + } + + inline const bool dock() const { + return waypoint_dock; + } + + inline const std::string & buy_label() const { + return waypoint_buy_label; + } + + void set_target(core::Entity *entity); + + void set_target_label(const std::string &label); + + void set_buy_label(const std::string &label); + + void set_dock(const bool dock); + + private: + std::string waypoint_target_label; + + core::Entity *waypoint_target; + + std::string waypoint_buy_label; + + bool waypoint_dock; + }; + + typedef std::list WayPoints; + + Patrol(); + virtual ~Patrol(); + + inline const NPC::Profile profile() const { + return patrol_profile; + } + + void set_profile(const NPC::Profile profile); + + WayPoint *add_waypoint(); + + virtual void validate(); + + virtual void frame(const unsigned long elapsed); + +private: + WayPoints patrol_waypoints; + + NPC::Profile patrol_profile; +}; + +} // namespace game + +#endif // __INCLUDED_BASE_PATROL_H__ \ No newline at end of file -- cgit v1.2.3