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-10 01:48:41 +0000
committerStijn Buys <ingar@osirion.org>2013-11-10 01:48:41 +0000
commit9dc3cc532820349a0f0e087afb60132927fd3411 (patch)
treebfdc9d515df65cde07f9fe217e7c87ed1556801f /src/game
parentd4f8d1c8fde01a58bc757b588c9850e69225bc24 (diff)
Corrected a bug which prevented the patrol profile from being set correctly,
corrected a bug where 'give ship' would forget the last spawn, have NPC ships fire on nearby enemies, made patrol leaders hunt nearby enemies.
Diffstat (limited to 'src/game')
-rw-r--r--src/game/base/faction.h6
-rw-r--r--src/game/base/game.cc5
-rw-r--r--src/game/base/npc.cc90
-rw-r--r--src/game/base/npc.h5
-rw-r--r--src/game/base/patrol.cc268
-rw-r--r--src/game/base/patrol.h4
-rw-r--r--src/game/base/ship.cc70
-rw-r--r--src/game/base/ship.h10
8 files changed, 328 insertions, 130 deletions
diff --git a/src/game/base/faction.h b/src/game/base/faction.h
index c78c2f2..b459899 100644
--- a/src/game/base/faction.h
+++ b/src/game/base/faction.h
@@ -42,7 +42,7 @@ public:
/**
* @brief player reputation with a specific faction
* */
- inline const float reputation(const Info *faction) const {
+ inline const float reputation(const core::Info *faction) const {
if (faction == this) {
return 100.0f;
} else {
@@ -88,6 +88,10 @@ public:
* */
static void apply_default(core::Reputation & reputation);
+ static inline const core::InfoType *infotype() {
+ return faction_infotype;
+ }
+
private:
/* --- attributes ------------------------------------------------- */
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
index d5e541b..c4d6069 100644
--- a/src/game/base/game.cc
+++ b/src/game/base/game.cc
@@ -410,6 +410,7 @@ void Game::func_give(core::Player *player, const std::string &args)
ship->get_location().assign(player->control()->location());
ship->set_dock(oldship->dock());
+ ship->set_spawn(oldship->spawn());
ship->get_axis().assign(player->control()->axis());
ship->set_thrust(player->control()->thrust());
@@ -2099,9 +2100,9 @@ bool Game::load_zone(core::Zone *zone)
if (core::Parser::got_entity_key(zoneini, patrol)) {
continue;
} else if (zoneini.got_key_label("profile", strval)) {
- if (strval.compare("convoy")) {
+ if (strval.compare("convoy") == 0) {
patrol->set_profile(Patrol::ProfileConvoy);
- } else if (strval.compare("patrol")) {
+ } else if (strval.compare("patrol") == 0) {
patrol->set_profile(Patrol::ProfilePatrol);
} else {
zoneini.unknown_error("unknown profile '" + strval + "'");
diff --git a/src/game/base/npc.cc b/src/game/base/npc.cc
index fa0ef44..992ba6c 100644
--- a/src/game/base/npc.cc
+++ b/src/game/base/npc.cc
@@ -4,6 +4,8 @@
the terms of the GNU General Public License version 2
*/
+#include "core/range.h"
+
#include "base/npc.h"
#include "base/game.h"
#include "base/patrol.h"
@@ -99,6 +101,79 @@ void NPC::set_patrol(Patrol *patrol)
npc_patrol = patrol;
}
+Ship *NPC::target_closest_enemy()
+{
+ // scan for enemies
+ Ship *current_enemy = 0;
+ float current_distance = 0.0f;
+
+
+ for (core::Zone::Content::iterator zit = zone()->content().begin(); zit != zone()->content().end(); ++zit) {
+ if (((*zit)->moduletype() == ship_enttype) && ((*zit) != this)) {
+ Ship *ship = static_cast<Ship *>((*zit));
+
+ if ((ship->state() != Normal) && (ship->state() != ImpulseInitiate) && (ship->state() != Impulse)) {
+ continue;
+ }
+
+ const float d = math::distance(location(), ship->location());
+ const float r = radius() + ship->radius();
+
+ // too far
+ if (d > r + core::range::fxdistance * 2.0f) {
+ continue;
+ }
+
+ // further than current target
+ if ((current_distance > 0.0f) && (d > current_distance)) {
+ continue;
+ }
+
+ float reputation = 0.0f;
+ if (ship->owner()) {
+ // check owner reputation for the faction the NPC belongs to
+ reputation = ship->owner()->reputation(faction());
+
+ } else if (faction() && (faction()->type() == Faction::infotype())) {
+ //check NPC faction reputation for the other ships's faction
+ reputation = static_cast<const Faction *>(faction())->reputation(ship->faction());
+ }
+
+ // reputation threshold to get attacked
+ if (reputation >= -50.0f) {
+ continue;
+ }
+
+ // reputation threshold to get hunted
+ if (d > core::range::fxdistance + r) {
+
+ if ((!ship->owner()) || (reputation > -100.0f)) {
+ continue;;
+ }
+ }
+
+ current_enemy = ship;
+ current_distance = d;
+ }
+ }
+
+ // 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)) {
+ // activate weapons
+ set_target_controlflag(core::EntityControlable::ControlFlagFire);
+ // rudimentary aim currention
+ target_aim.assign(current_enemy->location() + current_enemy->axis().forward() * (current_enemy->radius() * 0.25f) );
+ } else {
+ // deactivate weapons
+ unset_target_controlflag(core::EntityControlable::ControlFlagFire);
+ }
+
+ return current_enemy;
+}
+
void NPC::frame(const unsigned long elapsed)
{
if (state() == core::Entity::Destroyed) {
@@ -107,13 +182,11 @@ void NPC::frame(const unsigned long elapsed)
npc_destroyed_timestamp = core::game()->time();
} else if (npc_destroyed_timestamp + 10.0f < core::game()->time()) {
- // stay alive for 10 more seconds while explosion particles are drawn
-
+ // stay alive for 10 more seconds while explosion particles are drawn
die();
}
} else {
-
// TODO pilot magic and mood witchcraft
if (leader()) {
@@ -154,7 +227,6 @@ void NPC::frame(const unsigned long elapsed)
} else {
if (state() == core::Entity::Docked) {
-
// FIXME check launch conditions when docked at another player's ship
launch();
@@ -166,14 +238,7 @@ void NPC::frame(const unsigned long elapsed)
unset_autopilot_flag(Ship::AutoPilotDock);
set_autopilot_flag(Ship::AutoPilotFormation);
- /*
- if (leader()->has_target_controlflag(core::EntityControlable::ControlFlagFire)) {
- set_target_controlflag(core::EntityControlable::ControlFlagFire);
- target_aim.assign(leader()->aim());
- } else {
- unset_target_controlflag(core::EntityControlable::ControlFlagFire);
- }
- */
+ target_closest_enemy();
}
}
@@ -218,7 +283,6 @@ void NPC::frame(const unsigned long elapsed)
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 8139c9a..68620e1 100644
--- a/src/game/base/npc.h
+++ b/src/game/base/npc.h
@@ -81,6 +81,11 @@ public:
* @brief factory function for wingman NPCs
* */
static NPC *add_wingman(Ship *leader);
+
+ /**
+ * @brief aim at closest enemy in range, returns target
+ * */
+ Ship *target_closest_enemy();
private:
Mood npc_mood;
diff --git a/src/game/base/patrol.cc b/src/game/base/patrol.cc
index fbe02df..d1bbe15 100644
--- a/src/game/base/patrol.cc
+++ b/src/game/base/patrol.cc
@@ -197,6 +197,33 @@ void Patrol::validate()
}
}
+void Patrol::print() const
+{
+ core::Entity::print();
+ con_print << " ^Nprofile ^B";
+ switch (profile()) {
+ case(ProfileFreelancer):
+ con_print << "freelancer";
+ break;
+ case(ProfileConvoy):
+ con_print << "convoy";
+ break;
+ case(ProfilePatrol):
+ con_print << "patrol";
+ break;
+ case(ProfileGuard):
+ con_print << "guard";
+ break;
+ case(ProfileWingman):
+ con_print << "wingman";
+ break;
+ }
+ con_print << std::endl;
+ con_print << " ^Nwaypoints ^B" << patrol_waypoints.size() << std::endl;
+ con_print << " ^Nnpc types ^B" << patrol_npctypes.size() << std::endl;
+ con_print << " ^Nmembers ^B" << patrol_members.size() << std::endl;
+}
+
Patrol::WayPoint *Patrol::add_waypoint()
{
WayPoint *waypoint = new WayPoint();
@@ -269,123 +296,133 @@ bool Patrol::route_alive() const
return false;
}
-void Patrol::frame(const unsigned long elapsed)
-{
- if (patrol_waypoints.size() < 2) {
- return;
+void Patrol::create_patrol()
+{
+ if (patrol_waypoint_current == patrol_waypoints.end() || !(*patrol_waypoint_current)->dock()) {
+ patrol_waypoint_current = patrol_waypoints.begin();
}
-
- if (patrol_members.size() == 0) {
- // there are no members, verify if the spawn zone has players in it and create a new patrol
- if (patrol_waypoint_current == patrol_waypoints.end() || !(*patrol_waypoint_current)->dock()) {
- patrol_waypoint_current = patrol_waypoints.begin();
- }
- if (route_alive()) {
- core::Entity *spawn = waypoint()->target();
-
- if (spawn->has_flag(core::Entity::Dockable)) {
- // create NPC members for every NPC type
- for (NPCTypes::const_iterator it = patrol_npctypes.begin(); it != patrol_npctypes.end(); ++it) {
-
- NPCType *npctype = (*it);
-
- if (!npctype->shipmodel()) {
- continue;
- }
+ core::Entity *spawn = waypoint()->target();
+
+ if (spawn->has_flag(core::Entity::Dockable)) {
+
+ // create NPC members for every NPC type
+ for (NPCTypes::const_iterator it = patrol_npctypes.begin(); it != patrol_npctypes.end(); ++it) {
+
+ NPCType *npctype = (*it);
+
+ if (!npctype->shipmodel()) {
+ continue;
+ }
+
+ if (npctype->amount() <= 0) {
+ continue;
+ }
+
+ const size_t nbships = 1 + math::randomi((unsigned int) npctype->amount());
+ for (size_t i = 0; i < nbships; i++) {
+
+ // add NPC
+ NPC *npc = new NPC(npctype->shipmodel());
+ npc->set_mood(NPC::MoodFormation);
+
+ // set NPC name
+ if (npctype->name().size()) {
+ std::string str(npctype->name());
+ npc->set_name(str);
- if (npctype->amount() <= 0) {
- continue;
+ aux::to_label(str);
+ npc->set_label(str);
+ }
+
+ // set NPC color
+ if (npctype->faction()) {
+ npctype->faction()->apply(npc);
+ } else if (faction()) {
+ faction()->apply(npc);
+ }
+
+ // 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();
+ }
+
+ // install inventory
+ if (!npc->inventory()) {
+ npc->add_inventory();
+ }
+
+ // install slots
+ if (!npc->slots()) {
+ npc->add_slots();
+ slots()->load(model());
+ }
+
+ // install weapons
+ for (core::Slots::iterator slit = npc->slots()->begin(); slit != npc->slots()->end(); ++slit) {
+ core::Slot *slot = (*slit);
- const size_t nbships = 1 + math::randomi((unsigned int) npctype->amount());
- for (size_t i = 0; i < nbships; i++) {
+ core::Item *item = 0;
- // add NPC
- NPC *npc = new NPC(npctype->shipmodel());
- npc->set_mood(NPC::MoodFormation);
-
- // set NPC name
- if (npctype->name().size()) {
- npc->set_name(npctype->name());
- }
-
- // set NPC color
- if (npctype->faction()) {
- npctype->faction()->apply(npc);
- } else if (faction()) {
- faction()->apply(npc);
- }
-
- // 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();
+ if (slot->type() == model::Weapon::Cannon) {
+ if (npctype->cannon()) {
+ item = new core::Item(npctype->cannon());
}
-
- // install inventory
- if (!npc->inventory()) {
- npc->add_inventory();
+ } else if (slot->type() == model::Weapon::Turret) {
+ if (npctype->turret()) {
+ item = new core::Item(npctype->turret());
}
+ }
+
+ if (item) {
+ // add item
+ item->set_flag(core::Item::Unique);
+ item->set_flag(core::Item::Mountable);
+ item->set_flag(core::Item::Unrestricted);
+ item->set_amount(1);
+ npc->inventory()->add(item);
- // install slots
- if (!npc->slots()) {
- npc->add_slots();
- slots()->load(model());
- }
-
- // install weapons
- for (core::Slots::iterator slit = npc->slots()->begin(); slit != npc->slots()->end(); ++slit) {
- core::Slot *slot = (*slit);
-
- core::Item *item = 0;
-
- if (slot->type() == model::Weapon::Cannon) {
- if (npctype->cannon()) {
- item = new core::Item(npctype->cannon());
- }
- } else if (slot->type() == model::Weapon::Turret) {
- if (npctype->turret()) {
- item = new core::Item(npctype->turret());
- }
- }
-
- if (item) {
- // add item
- item->set_flag(core::Item::Unique);
- item->set_flag(core::Item::Mountable);
- item->set_flag(core::Item::Unrestricted);
- item->set_amount(1);
- npc->inventory()->add(item);
-
- // mount weapon
- slot->set_item(item);
- slot->set_flag(core::Slot::Active);
- slot->set_flag(core::Slot::Mounted);
- }
- }
-
- npc->inventory()->recalculate();
-
- // dock npc at spawn
- npc->set_zone(spawn->zone());
- npc->set_dock(spawn);
-
- // add NPC to patrol
- add_member(npc);
+ // mount weapon
+ slot->set_item(item);
+ slot->set_flag(core::Slot::Active);
+ slot->set_flag(core::Slot::Mounted);
}
}
- set_leader();
+ npc->inventory()->recalculate();
+
+ // dock npc at spawn
+ npc->set_zone(spawn->zone());
+ npc->set_dock(spawn);
- patrol_launch_timeout = core::server()->timestamp() + 15000 + (unsigned long) math::randomi(30000);
+ // add NPC to patrol
+ add_member(npc);
}
}
+
+ set_leader();
+
+ patrol_launch_timeout = core::server()->timestamp() + 15000 + (unsigned long) math::randomi(30000);
+ }
+}
+void Patrol::frame(const unsigned long elapsed)
+{
+ if (patrol_waypoints.size() < 2) {
+ return;
+ }
+
+ if (patrol_members.size() == 0) {
+ if (route_alive()) {
+ create_patrol();
+ }
+ return;
+
} else if (patrol_leader) {
if (patrol_leader->state() == core::Entity::Docked) {
@@ -468,12 +505,31 @@ void Patrol::frame(const unsigned long elapsed)
} 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()) {
+ Ship *enemy = 0;
+
+ if (profile() == ProfilePatrol) {
+ enemy = patrol_leader->target_closest_enemy();
+ }
+
+ if (enemy) {
+ // combat conditions
+ if (patrol_leader->autopilot_target() != enemy) {
+ patrol_leader->set_autopilot_target(enemy);
+ }
+ patrol_leader->set_autopilot_flag(Ship::AutoPilotEnabled);
+ patrol_leader->set_autopilot_flag(Ship::AutoPilotCombat);
+ patrol_leader->unset_autopilot_flag(Ship::AutoPilotFormation);
+ patrol_leader->unset_autopilot_flag(Ship::AutoPilotDock);
+
+ } else if (waypoint()->target()->zone() == patrol_leader->zone()) {
+
+ // current waypoint is in this zone
patrol_leader->set_autopilot_target(waypoint()->target());
patrol_leader->set_autopilot_flag(Ship::AutoPilotEnabled);
patrol_leader->unset_autopilot_flag(Ship::AutoPilotFormation);
+ patrol_leader->unset_autopilot_flag(Ship::AutoPilotCombat);
if ( (waypoint()->dock()) && (waypoint()->target()->has_flag(core::Entity::Dockable)) ) {
patrol_leader->set_autopilot_flag(Ship::AutoPilotDock);
@@ -505,10 +561,12 @@ void Patrol::frame(const unsigned long elapsed)
}
}
}
+
} else {
// current waypoint is in different zone
+ patrol_leader->unset_autopilot_flag(Ship::AutoPilotCombat);
- // check if a jumpgate got use here
+ // check if the leader got here through a jumpgate
JumpGate *jumpgate = (waypoint()->target()->moduletype() == jumpgate_enttype ? static_cast<JumpGate *>(waypoint()->target()) : 0 );
if (jumpgate && jumpgate->target()->zone() == patrol_leader->zone()) {
@@ -537,7 +595,7 @@ void Patrol::frame(const unsigned long elapsed)
}
} else {
- // we're lost: delete patrol
+ // we're lost: delete patrol members
for (Members::iterator it = patrol_members.begin(); it != patrol_members.end(); ++it) {
(*it)->die();
diff --git a/src/game/base/patrol.h b/src/game/base/patrol.h
index cc3bf61..c99c244 100644
--- a/src/game/base/patrol.h
+++ b/src/game/base/patrol.h
@@ -127,6 +127,8 @@ public:
virtual void frame(const unsigned long elapsed);
+ virtual void print() const;
+
void add_member(NPC *npc);
void erase_member(NPC *npc);
@@ -134,6 +136,8 @@ public:
private:
void set_leader();
+ void create_patrol();
+
bool route_alive() const;
WayPoints patrol_waypoints;
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index 5be9a00..2a5d68f 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -1194,14 +1194,16 @@ void Ship::frame_autopilot(const unsigned long elapsed)
const float dock_distance = (autopilot_target()->moduletype() == planet_enttype ? r + PLANET_SAFE_DISTANCE : r);
if (!has_target_controlflag(core::EntityControlable::ControlFlagOverride)) {
-
// thruster and speed control
- if (has_autopilot_flag(AutoPilotFormation) && (distance < 4.0f * r)) {
+ if (has_autopilot_flag(AutoPilotCombat) && (distance < r + COMBAT_DISTANCE)) {
+ frame_autopilot_combat(elapsed, autopilot_target());
+
+ } else if (has_autopilot_flag(AutoPilotFormation) && (distance < 4.0f * r)) {
frame_autopilot_formation(elapsed, autopilot_target());
} else if (has_autopilot_flag(AutoPilotDock) && (distance < dock_distance)) {
frame_autopilot_dock(elapsed, autopilot_target());
-
+
} else {
frame_autopilot_goto(elapsed, autopilot_target());
}
@@ -1292,6 +1294,63 @@ void Ship::frame_autopilot_goto(const unsigned long elapsed, core::Entity *targe
}
}
+void Ship::frame_autopilot_combat(const unsigned long elapsed, core::Entity *target)
+{
+ if ((state() == core::Entity::Impulse) || (state() == core::Entity::ImpulseInitiate)) {
+ func_impulse();
+ }
+
+ // desired direction
+ math::Vector3f direction(target->location() - location());
+ const float distance = direction.length();
+ // normalize
+ direction /= distance;
+
+ // transform direction from world coordinates to local entity coordinates
+ direction = axis().transpose() * direction;
+
+ if (direction.x() < 0) {
+ // target is behind the ship
+ target_direction = (direction.y() > 0 ? 1.0f : -1.0f);
+ target_pitch = 0.0f;
+
+ } else if (direction.x() + MIN_DELTA < 1.0f) {
+ // target is in front of the ship
+ target_direction = direction.y();
+ target_pitch = direction.z();
+ } else {
+ target_direction = 0.0f;
+ target_pitch = 0.0f;
+ }
+
+ // transform the target's axis into local coordinates
+ const math::Axis reference(axis().transpose() * target->axis());
+ if (reference.up().z() < 0.0f) {
+ // upward-down
+ target_roll = (reference.up().y() > 0 ? 1.0f : 0.0f);
+
+ } else if (reference.up().z() + MIN_DELTA < 1.0f) {
+ target_roll = reference.up().y();
+
+ } else {
+ target_roll = 0.0f;
+ }
+
+ // reference radius used in calculations
+ const float r = radius() + target->radius();
+
+ // thruster
+ if (distance > 2.0f * r) {
+ target_thrust = 1.0f;
+
+ } else if (distance > r ) {
+ target_thrust = math::max(0.1f, (distance - r ) / r);
+
+ } else {
+ target_thrust = 0.0f;
+ }
+}
+
void Ship::frame_autopilot_dock(const unsigned long elapsed, core::Entity *target)
{
// reference radius used in calculations
@@ -1300,10 +1359,7 @@ void Ship::frame_autopilot_dock(const unsigned long elapsed, core::Entity *targe
if ((state() == core::Entity::Impulse) || (state() == core::Entity::ImpulseInitiate)) {
func_impulse();
- return;
- }
-
- if (state() != core::Entity::Normal) {
+ } else if (state() != core::Entity::Normal) {
return;
}
diff --git a/src/game/base/ship.h b/src/game/base/ship.h
index e8a6505..d627295 100644
--- a/src/game/base/ship.h
+++ b/src/game/base/ship.h
@@ -20,6 +20,7 @@ const float MIN_DELTA = 0.000001f;
// planet docking distance
const float PLANET_SAFE_DISTANCE = 50.0f;
+const float COMBAT_DISTANCE = 100.0f;
/**
@@ -28,7 +29,7 @@ const float PLANET_SAFE_DISTANCE = 50.0f;
class Ship : public core::EntityControlable
{
public:
- enum AutoPilotFlags { AutoPilotDisabled = 0, AutoPilotEnabled = 1, AutoPilotDock = 2, AutoPilotFormation = 4 };
+ enum AutoPilotFlags { AutoPilotDisabled = 0, AutoPilotEnabled = 1, AutoPilotDock = 2, AutoPilotFormation = 4, AutoPilotCombat = 8 };
Ship(core::Player *owner, const ShipModel *shipmodel);
~Ship();
@@ -234,7 +235,12 @@ protected:
void frame_autopilot_goto(const unsigned long elapsed, core::Entity *target);
/**
- * @brief autopilot goto target
+ * @brief autopilot combat
+ * */
+ void frame_autopilot_combat(const unsigned long elapsed, core::Entity *target);
+
+ /**
+ * @brief autopilo dock target
* */
void frame_autopilot_dock(const unsigned long elapsed, core::Entity *target);