Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2008-09-28 15:05:13 +0000
committerStijn Buys <ingar@osirion.org>2008-09-28 15:05:13 +0000
commitfd778219e40c5fbb4d0af1839cbc313caaf10d9d (patch)
treeb6e413f4c1a5ba4091503ba97c784278485d3933 /src/game/base
parentbedcff956d253621ec00aa7d2919c22a4c88b0b2 (diff)
move base game module to new subdirectory
Diffstat (limited to 'src/game/base')
-rw-r--r--src/game/base/Makefile.am8
-rw-r--r--src/game/base/base.cc661
-rw-r--r--src/game/base/base.h77
-rw-r--r--src/game/base/game.cc661
-rw-r--r--src/game/base/jumppoint.cc29
-rw-r--r--src/game/base/jumppoint.h40
-rw-r--r--src/game/base/navpoint.cc27
-rw-r--r--src/game/base/navpoint.h27
-rw-r--r--src/game/base/planet.cc27
-rw-r--r--src/game/base/planet.h27
-rw-r--r--src/game/base/racetrack.cc195
-rw-r--r--src/game/base/racetrack.h63
-rw-r--r--src/game/base/ship.cc464
-rw-r--r--src/game/base/ship.h60
-rw-r--r--src/game/base/shipmodel.cc72
-rw-r--r--src/game/base/shipmodel.h70
-rw-r--r--src/game/base/star.cc25
-rw-r--r--src/game/base/star.h29
18 files changed, 2562 insertions, 0 deletions
diff --git a/src/game/base/Makefile.am b/src/game/base/Makefile.am
new file mode 100644
index 0000000..a8258b2
--- /dev/null
+++ b/src/game/base/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/game
+METASOURCES = AUTO
+libbase_la_LDFLAGS = -avoid-version
+noinst_LTLIBRARIES = libbase.la
+libbase_la_SOURCES = base.cc jumppoint.cc navpoint.cc planet.cc racetrack.cc \
+ ship.cc shipmodel.cc star.cc
+noinst_HEADERS = base.h jumppoint.h navpoint.h planet.h racetrack.h ship.h \
+ shipmodel.h star.h
diff --git a/src/game/base/base.cc b/src/game/base/base.cc
new file mode 100644
index 0000000..70d9335
--- /dev/null
+++ b/src/game/base/base.cc
@@ -0,0 +1,661 @@
+/*
+ base/base.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include <vector>
+#include <string>
+
+#include "auxiliary/functions.h"
+#include "core/gameserver.h"
+#include "filesystem/filesystem.h"
+#include "filesystem/inifile.h"
+#include "base/base.h"
+#include "base/navpoint.h"
+#include "base/jumppoint.h"
+#include "base/planet.h"
+#include "base/racetrack.h"
+#include "base/ship.h"
+#include "base/star.h"
+#include "math/mathlib.h"
+#include "sys/sys.h"
+
+namespace base
+{
+
+ShipModel *default_shipmodel = 0;
+core::Zone *default_zone = 0;
+
+/*----- engine game functions ------------------------------------- */
+
+/// list the ship model registry
+void func_list_ship(std::string const &args)
+{
+ ShipModel::list();
+}
+
+/// a player joins the game
+void func_join(core::Player *player, std::string const &args)
+{
+ if (player->control())
+ return;
+
+ player->set_zone(default_zone);
+ Ship *ship = new Ship(player, default_shipmodel);
+ ship->set_zone(default_zone);
+ player->set_control(ship);
+
+ core::server()->send_sound(player, "game/buy-ship");
+
+ std::string message("^B");
+ message.append(player->name());
+ message.append("^B joins the game.");
+ core::server()->broadcast(message);
+
+ player->player_dirty = true;
+}
+
+/// a player joins the spectators
+void func_spectate(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+
+ std::string message("^B");
+ message.append(player->name());
+ message.append("^B spectates.");
+ core::server()->broadcast(message);
+
+ if (player->control()) {
+ player->remove_asset(player->control());
+ }
+}
+
+/// a player buys a ship
+void func_buy(core::Player *player, std::string const &args)
+{
+
+ std::string shipname;
+ std::string helpstr;
+ std::istringstream is(args);
+ is >> shipname;
+ aux::to_lowercase(shipname);
+
+ ShipModel *shipmodel = 0;
+ for (ShipModel::iterator smit = ShipModel::registry.begin(); smit != ShipModel::registry.end(); smit++) {
+ if (shipname == (*smit).first) {
+ shipmodel = (*smit).second;
+ break;
+ }
+
+ if (helpstr.size())
+ helpstr.append("^N|^B");
+ helpstr.append((*smit).second->label());
+ }
+
+ if (shipmodel) {
+ // player has only ship for now
+ if (player->control()) {
+ player->remove_asset(player->control());
+ }
+
+ Ship * ship = new Ship(player, shipmodel);
+ if (player->zone()) {
+ ship->set_zone(player->zone());
+ } else {
+ ship->set_zone(default_zone);
+ }
+ player->set_control(ship);
+
+ core::server()->broadcast("^B" + player->name() + " ^Bpurchased " + aux::article(shipmodel->name()));
+ core::server()->send_sound(player, "game/buy-ship");
+
+ } else {
+ core::server()->send(player, "Usage: buy [^B" + helpstr + "^N]");
+ }
+}
+
+/// a player sends standard hails
+void func_hail(core::Player *player, std::string const &args)
+{
+ std::string target;
+ std::istringstream is(args);
+ if (!(is >> target)) {
+ core::server()->send(player, "Usage: hail [player]");
+ return;
+ }
+
+ core::Player *targetplayer = core::server()->find_player(target);
+ if (!targetplayer) {
+ core::server()->send(player, "^BPlayer " + target + "^B not found.");
+ return;
+ }
+
+ core::server()->send(player, "^BYou hail " + targetplayer->name() + "^B.");
+ core::server()->send_sound(player, "com/hail");
+
+ core::server()->send(targetplayer, "^B" + player->name() + "^B hails you!");
+ core::server()->send_sound(targetplayer, "com/hail");
+}
+
+/// a player actives the hyperspace jump drive on his ship
+void func_jump(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+ if (!player->control()->moduletype() == ship_enttype)
+ return;
+ Ship * ship = static_cast<Ship *>(player->control());
+ ship->jump(args);
+}
+
+/// a player actives the kinetic impulse drive on his ship
+void func_impulse(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+ if (!player->control()->moduletype() == ship_enttype)
+ return;
+ Ship * ship = static_cast<Ship *>(player->control());
+ ship->impulse();
+}
+
+/* ---- The Game class --------------------------------------------- */
+
+Base *Base::game_instance = 0;
+
+Base::Base() : core::Module("Project::OSiRiON")
+{
+ game_instance = this;
+ g_impulsespeed = 0;
+}
+
+Base::~Base()
+{
+ game_instance = 0;
+}
+
+void Base::init()
+{
+ module_running = false;
+
+ ShipModel::clear();
+
+ if (!load_world()) {
+ abort();
+ return;
+ }
+
+ if (!load_ships()) {
+ abort();
+ return;
+ }
+
+ // add engine game functions
+ core::Func *func = 0;
+
+ func = core::Func::add("join", (core::GameFuncPtr) func_join);
+ func->set_info("join the game");
+ func = core::Func::add("hail", (core::GameFuncPtr) func_hail);
+ func->set_info("send a standard hail");
+ func = core::Func::add("spectate", (core::GameFuncPtr) func_spectate);
+ func->set_info("leave the game and spectate");
+
+ func = core::Func::add("buy", (core::GameFuncPtr) func_buy);
+ func->set_info("buy a ship");
+
+ func = core::Func::add("jump", (core::GameFuncPtr) func_jump);
+ func->set_info("[string] activate or deactivate hyperspace jump drive");
+
+ func = core::Func::add("impulse", (core::GameFuncPtr) func_impulse);
+ func->set_info("activate are deactive kinetic impulse drive");
+
+ // add engine core functions
+ func = core::Func::add("list_ship", (core::FuncPtr) func_list_ship);
+ func->set_info("list ship statistics");
+
+ g_impulsespeed = core::Cvar::get("g_impulsespeed", "15", core::Cvar::Game | core::Cvar::Archive);
+ g_impulsespeed->set_info("[float] speed of the impulse drive");
+
+ g_impulseacceleration = core::Cvar::get("g_impulseacceleration", "5", core::Cvar::Game | core::Cvar::Archive);
+ g_impulseacceleration->set_info("[float] acceleration of the impulse drive");
+
+ g_strafespeed = core::Cvar::get("g_strafespeed", "0.003", core::Cvar::Game | core::Cvar::Archive);
+ g_strafespeed->set_info("[float] strafe speed");
+
+ g_jumppointrange = core::Cvar::get("g_jumppointrange", "512", core::Cvar::Game | core::Cvar::Archive);
+ g_jumppointrange->set_info("[float] jumppoint range");
+
+ g_devel = core::Cvar::get("g_devel", "0", core::Cvar::Archive);
+ g_devel->set_info("[bool] enable or disable developer mode");
+
+ // indicate the module is ready to run frames
+ module_running = true;
+}
+
+void Base::shutdown()
+{
+ g_impulsespeed = 0;
+ // game functions are automaticly removed
+
+ // remove engine core functions
+ core::Func::remove("list_ship");
+
+ ShipModel::clear();
+ module_running = false;
+}
+
+bool Base::load_world()
+{
+ std::string inifilename("world");
+
+ filesystem::IniFile worldini;
+ worldini.open(inifilename);
+
+ if (!worldini.is_open()) {
+ con_error << "Could not open " << worldini.name() << std::endl;
+ return false;
+ }
+
+ core::Zone *zone = 0;
+ std::string label;
+
+ while (worldini.getline()) {
+
+ if (worldini.got_section()) {
+
+ if (worldini.got_section("world")) {
+ continue;
+ } else {
+ con_warn << worldini.name() << " unknown section '" << worldini.section() << "' at line " << worldini.line() << std::endl;
+ }
+
+ } else if (worldini.section().compare("world") == 0 ) {
+ if (worldini.got_key_string("zone", label)) {
+ aux::to_label(label);
+ zone = new core::Zone(label);
+ core::Zone::add(zone);
+ }
+ }
+ }
+ worldini.close();
+
+ if (!core::Zone::registry().size()) {
+ con_error << "No zones found!" << std::endl;
+ return false;
+ }
+
+ con_debug << " " << worldini.name() << " " << core::Zone::registry().size() << " zones" << std::endl;
+
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ if (!load_zone((*it).second)) {
+ return false;
+ }
+ }
+
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ if (!validate_zone((*it).second)) {
+ return false;
+ }
+ }
+
+ if (!default_zone) {
+ con_error << "No default zone found!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool Base::got_entity_key(filesystem::IniFile &inifile, core::Entity *entity)
+{
+ std::string shapename;
+ std::string strval;
+ float direction;
+ float pitch;
+ float roll;
+
+ if (inifile.got_key_string("shape", shapename)) {
+
+ if (shapename.compare("axis") == 0) {
+ entity->entity_shape = core::Entity::Axis;
+ return true;
+ } else if (shapename.compare("cube") == 0) {
+ entity->entity_shape = core::Entity::Cube;
+ return true;
+ } else if (shapename.compare("diamond") == 0) {
+ entity->entity_shape = core::Entity::Diamond;
+ return true;
+ } else if (shapename.compare("sphere") == 0) {
+ entity->entity_shape = core::Entity::Sphere;
+ return true;
+ } else {
+ con_warn << inifile.name() << " unknown shape '" << shapename << "' at line " << inifile.line() << std::endl;
+ return false;
+ }
+
+ } else if (inifile.got_key_string("label", strval)) {
+ aux::to_label(strval);
+ entity->entity_label.assign(strval);
+ return true;
+ } else if (inifile.got_key_string("name", strval)) {
+ aux::strip_quotes(strval);
+ entity->entity_name.assign(strval);
+ return true;
+ } else if (inifile.got_key_string("model", entity->entity_modelname)) {
+ return true;
+ } else if (inifile.got_key_angle("direction", direction)) {
+ entity->axis().change_direction(direction);
+ return true;
+ } else if (inifile.got_key_angle("pitch", pitch)) {
+ entity->axis().change_pitch(pitch);
+ return true;
+ } else if (inifile.got_key_angle("roll", roll)) {
+ entity->axis().change_roll(roll);
+ return true;
+ } else if (inifile.got_key_angle("radius", entity->entity_radius)) {
+ return true;
+ } else if (inifile.got_key_vector3f("location", entity->entity_location)) {
+ return true;
+ } else if (inifile.got_key_color("color", entity->entity_color)) {
+ return true;
+ } else if (inifile.got_key_color("colorsecond", entity->entity_color_second)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool Base::load_zone(core::Zone *zone)
+{
+ using math::Vector3f;
+ using math::Color;
+
+ std::string inifilename("zones/");
+ inifilename.append(zone->label());
+
+ filesystem::IniFile zoneini;
+ zoneini.open(inifilename);
+
+ if (!zoneini.is_open()) {
+ con_error << "Could not open " << zoneini.name() << std::endl;
+ return false;
+ }
+
+ size_t count = 0;
+
+ Planet *planet = 0;
+ Star *star = 0;
+ NavPoint *navpoint = 0;
+ JumpPoint *jumppoint = 0;
+ RaceTrack *racetrack = 0;
+ CheckPoint *checkpoint = 0;
+ core::Entity *entity = 0;
+
+ bool b;
+
+ std::string strval;
+
+ // set th default sky
+ zone->set_sky("sky");
+
+ while (zoneini.getline()) {
+ if (zoneini.got_key()) {
+ if (zoneini.section().compare("zone") == 0) {
+ if (zoneini.got_key_string("name", strval)) {
+ aux::strip_quotes(strval);
+ zone->set_name(strval);
+ continue;
+ } else if (zoneini.got_key_string("sky", strval)) {
+ zone->set_sky(strval);
+ continue;
+ } else if (zoneini.got_key_bool("default", b)) {
+ if (b) default_zone = zone;
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("star") == 0) {
+ if (got_entity_key(zoneini, star)) {
+ continue;
+ } else if (zoneini.got_key_string("texture", star->entity_texture)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("navpoint") == 0) {
+ if (got_entity_key(zoneini, navpoint)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("jumppoint") == 0) {
+ if (got_entity_key(zoneini, jumppoint)) {
+ continue;
+ } else if (zoneini.got_key_string("target", jumppoint->jumppoint_targetlabel)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("planet") == 0) {
+ if (got_entity_key(zoneini, planet)) {
+ continue;
+ } else if (zoneini.got_key_string("texture", planet->entity_texture)) {
+ continue;
+ } else if (zoneini.got_key_float("rotationspeed", planet->entity_rotationspeed)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("racetrack") == 0) {
+ if (got_entity_key(zoneini, racetrack)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("checkpoint") == 0) {
+ if (got_entity_key(zoneini, checkpoint)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("entity") == 0) {
+ if (got_entity_key(zoneini, entity)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ }
+ } else if (zoneini.got_section("zone")) {
+ continue;
+
+ } else if (zoneini.got_section("star")) {
+ star = new Star();
+ star->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("navpoint")) {
+ navpoint = new NavPoint();
+ navpoint->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("jumppoint")) {
+ jumppoint = new JumpPoint();
+ jumppoint->set_zone(zone);
+ count ++;
+
+ } else if(zoneini.got_section("racetrack")) {
+ racetrack = new RaceTrack();
+ racetrack->set_zone(zone);
+
+ } else if(zoneini.got_section("checkpoint")) {
+ checkpoint = new CheckPoint(racetrack);
+ if (!racetrack) {
+ con_warn << zoneini.name() << " checkpoint without racetrack at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.got_section("planet")) {
+ planet = new Planet();
+ planet->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("entity")) {
+ entity = new core::Entity();
+ entity->entity_flags += core::Entity::Static;
+ entity->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section()) {
+ con_warn << zoneini.name() << " unknown section '" << zoneini.section() << "' at line " << zoneini.line() << std::endl;
+ }
+ }
+ zoneini.close();
+
+ con_debug << " " << zoneini.name() << " " << zone->content().size() << " entities" << std::endl;
+
+
+ return true;
+}
+
+bool Base::validate_zone(core::Zone *zone)
+{
+ con_debug << " validating " << zone->name() << std::endl;
+
+ for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+ core::Entity *entity = (*it);
+
+ if (entity->entity_moduletypeid == jumppoint_enttype) {
+ JumpPoint *jumppoint = static_cast<JumpPoint *>(entity);
+
+ if (jumppoint->targetlabel().size() < 3) {
+ con_warn << " Jumppoint with invalid target label '" << jumppoint->targetlabel() << "'\n";
+ continue;
+ }
+ size_t pos = jumppoint->targetlabel().find(':');
+ if ((pos < 1 ) || (pos >= (jumppoint->targetlabel().size()-1))) {
+ con_warn << " Jumppoint with invalid target label '" << jumppoint->targetlabel() << "'\n";
+ continue;
+ }
+
+ std::string zonelabel(jumppoint->targetlabel().substr(0, pos));
+ std::string entitylabel(jumppoint->targetlabel().substr(pos+1, jumppoint->targetlabel().size()-pos));
+
+ core::Zone *targetzone = core::Zone::find(zonelabel);
+ if (!targetzone) {
+ con_warn << " Jumppoint with invalid target zone '" << zonelabel << "'\n";
+ continue;
+ }
+
+ core::Entity *targetentity = targetzone->find_entity(entitylabel);
+ if (!targetentity) {
+ con_warn << " Could not find target jumppoint '" << entitylabel << "'\n";
+ continue;
+ }
+
+ if (targetentity->moduletype() != jumppoint_enttype) {
+ con_warn << " Jumppoint with invalid target jumppoint '" << entitylabel << "'\n";
+ continue;
+ }
+
+ jumppoint->jumppoint_target = static_cast<JumpPoint *>(targetentity);
+
+ //con_debug << " Jumppoint " << zone->label() << ":" << jumppoint->label() << " with target " << jumppoint->targetlabel() << std::endl;
+ }
+ }
+
+ return true;
+}
+
+// read ship model specifications
+bool Base::load_ships()
+{
+ using math::Vector3f;
+ using math::Color;
+
+ default_shipmodel = 0;
+
+ filesystem::IniFile shipsini;
+ shipsini.open("ships");
+ if (!shipsini.is_open()) {
+ con_error << "Could not open ini/ships.ini!" << std::endl;
+ return false;
+ }
+
+ ShipModel *shipmodel = 0;
+ std::string label;
+ bool b;
+
+ while (shipsini.getline()) {
+ if (shipsini.got_key()) {
+ if (shipsini.section().compare("ship") == 0) {
+ if (shipsini.got_key_string("label", label)) {
+ aux::to_label(label);
+ shipmodel->shipmodel_label.assign(label);
+ ShipModel::add(shipmodel);
+ continue;
+ } else if (shipsini.got_key_string("name",shipmodel->shipmodel_name)) {
+ continue;
+ } else if (shipsini.got_key_string("model", shipmodel->shipmodel_modelname)) {
+ continue;
+ } else if (shipsini.got_key_bool("default", b)) {
+ if (b) default_shipmodel = shipmodel;
+ continue;
+ } else if (shipsini.got_key_bool("jumpdrive", shipmodel->shipmodel_jumpdrive)) {
+ continue;
+ } else if (shipsini.got_key_float("acceleration", shipmodel->shipmodel_acceleration)) {
+ continue;
+ } else if (shipsini.got_key_float("maxspeed", shipmodel->shipmodel_maxspeed)) {
+ continue;
+ } else if (shipsini.got_key_float("turnspeed", shipmodel->shipmodel_turnspeed)) {
+ math::clamp(shipmodel->shipmodel_turnspeed, 0.0f, 90.0f);
+ continue;
+ } else {
+ con_warn << shipsini.name() << " unknown key '" << shipsini.key() << "' at line " << shipsini.line() << std::endl;
+ }
+ }
+ } else if (shipsini.got_section("ship")) {
+ shipmodel = new ShipModel();
+
+ if (!default_shipmodel)
+ default_shipmodel = shipmodel;
+
+ } else if (shipsini.got_section()) {
+ con_warn << shipsini.name() << " unknown section '" << shipsini.section() << "' at line " << shipsini.line() << std::endl;
+ }
+ }
+ shipsini.close();
+
+ con_debug << " " << shipsini.name() << " " << ShipModel::registry.size() << " ship models" << std::endl;
+
+ if (!default_shipmodel) {
+ con_error << "No default ship model found!\n";
+ return false;
+ }
+
+ return true;
+}
+
+void Base::frame(float seconds)
+{
+ if (!running())
+ return;
+}
+
+void Base::player_connect(core::Player *player)
+{
+ std::string args;
+ player->set_zone(default_zone);
+ func_spectate(player, args);
+}
+
+void Base::player_disconnect(core::Player *player)
+{
+ player->remove_asset(player->control());
+}
+
+} // namespace game
+
diff --git a/src/game/base/base.h b/src/game/base/base.h
new file mode 100644
index 0000000..fea1919
--- /dev/null
+++ b/src/game/base/base.h
@@ -0,0 +1,77 @@
+/*
+ game/game.h
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_BASE_H__
+#define __INCLUDED_BASE_H__
+
+#include <vector>
+#include <string>
+
+#include "base/ship.h"
+#include "base/star.h"
+#include "core/core.h"
+#include "filesystem/inifile.h"
+#include "sys/sys.h"
+
+/// the base game module
+/** the base game module containis the game-specific code for Project::Osirion
+ */
+namespace base
+{
+
+// entity type constants
+const unsigned int ship_enttype = 256;
+const unsigned int star_enttype = 257;
+const unsigned int planet_enttype = 258;
+const unsigned int navpoint_enttype = 259;
+const unsigned int jumppoint_enttype = 260;
+
+class Base : public core::Module {
+public:
+ Base();
+ ~Base();
+
+ /// initialize the game
+ void init();
+
+ /// shutdown the game
+ void shutdown();
+
+ /// run one time frame
+ void frame(float seconds);
+
+ /// is called when a player connects
+ void player_connect(core::Player *player);
+
+ /// is called when a player disconnects
+ void player_disconnect(core::Player *player);
+
+ static inline Base *instance() { return game_instance; }
+
+ core::Cvar *g_impulsespeed;
+ core::Cvar *g_impulseacceleration;
+ core::Cvar *g_strafespeed;
+ core::Cvar *g_jumppointrange;
+ core::Cvar *g_devel;
+
+private:
+ bool got_entity_key(filesystem::IniFile &inifile, core::Entity *entity);
+
+ bool load_world();
+
+ bool load_zone(core::Zone *zone);
+
+ bool validate_zone(core::Zone *zone);
+
+ bool load_ships();
+
+ static Base *game_instance;
+};
+
+}
+
+#endif // __INCLUDED_BASE_H__
+
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
new file mode 100644
index 0000000..4d66cbe
--- /dev/null
+++ b/src/game/base/game.cc
@@ -0,0 +1,661 @@
+/*
+ game/game.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include <vector>
+#include <string>
+
+#include "auxiliary/functions.h"
+#include "core/gameserver.h"
+#include "filesystem/filesystem.h"
+#include "filesystem/inifile.h"
+#include "game/game.h"
+#include "game/navpoint.h"
+#include "game/jumppoint.h"
+#include "game/planet.h"
+#include "game/racetrack.h"
+#include "game/ship.h"
+#include "game/star.h"
+#include "math/mathlib.h"
+#include "sys/sys.h"
+
+namespace game
+{
+
+ShipModel *default_shipmodel = 0;
+core::Zone *default_zone = 0;
+
+/*----- engine game functions ------------------------------------- */
+
+/// list the ship model registry
+void func_list_ship(std::string const &args)
+{
+ ShipModel::list();
+}
+
+/// a player joins the game
+void func_join(core::Player *player, std::string const &args)
+{
+ if (player->control())
+ return;
+
+ player->set_zone(default_zone);
+ Ship *ship = new Ship(player, default_shipmodel);
+ ship->set_zone(default_zone);
+ player->set_control(ship);
+
+ core::server()->send_sound(player, "game/buy-ship");
+
+ std::string message("^B");
+ message.append(player->name());
+ message.append("^B joins the game.");
+ core::server()->broadcast(message);
+
+ player->player_dirty = true;
+}
+
+/// a player joins the spectators
+void func_spectate(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+
+ std::string message("^B");
+ message.append(player->name());
+ message.append("^B spectates.");
+ core::server()->broadcast(message);
+
+ if (player->control()) {
+ player->remove_asset(player->control());
+ }
+}
+
+/// a player buys a ship
+void func_buy(core::Player *player, std::string const &args)
+{
+
+ std::string shipname;
+ std::string helpstr;
+ std::istringstream is(args);
+ is >> shipname;
+ aux::to_lowercase(shipname);
+
+ ShipModel *shipmodel = 0;
+ for (ShipModel::iterator smit = ShipModel::registry.begin(); smit != ShipModel::registry.end(); smit++) {
+ if (shipname == (*smit).first) {
+ shipmodel = (*smit).second;
+ break;
+ }
+
+ if (helpstr.size())
+ helpstr.append("^N|^B");
+ helpstr.append((*smit).second->label());
+ }
+
+ if (shipmodel) {
+ // player has only ship for now
+ if (player->control()) {
+ player->remove_asset(player->control());
+ }
+
+ Ship * ship = new Ship(player, shipmodel);
+ if (player->zone()) {
+ ship->set_zone(player->zone());
+ } else {
+ ship->set_zone(default_zone);
+ }
+ player->set_control(ship);
+
+ core::server()->broadcast("^B" + player->name() + " ^Bpurchased " + aux::article(shipmodel->name()));
+ core::server()->send_sound(player, "game/buy-ship");
+
+ } else {
+ core::server()->send(player, "Usage: buy [^B" + helpstr + "^N]");
+ }
+}
+
+/// a player sends standard hails
+void func_hail(core::Player *player, std::string const &args)
+{
+ std::string target;
+ std::istringstream is(args);
+ if (!(is >> target)) {
+ core::server()->send(player, "Usage: hail [player]");
+ return;
+ }
+
+ core::Player *targetplayer = core::server()->find_player(target);
+ if (!targetplayer) {
+ core::server()->send(player, "^BPlayer " + target + "^B not found.");
+ return;
+ }
+
+ core::server()->send(player, "^BYou hail " + targetplayer->name() + "^B.");
+ core::server()->send_sound(player, "com/hail");
+
+ core::server()->send(targetplayer, "^B" + player->name() + "^B hails you!");
+ core::server()->send_sound(targetplayer, "com/hail");
+}
+
+/// a player actives the hyperspace jump drive on his ship
+void func_jump(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+ if (!player->control()->moduletype() == ship_enttype)
+ return;
+ Ship * ship = static_cast<Ship *>(player->control());
+ ship->jump(args);
+}
+
+/// a player actives the kinetic impulse drive on his ship
+void func_impulse(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+ if (!player->control()->moduletype() == ship_enttype)
+ return;
+ Ship * ship = static_cast<Ship *>(player->control());
+ ship->impulse();
+}
+
+/* ---- The Game class --------------------------------------------- */
+
+Game *Game::game_instance = 0;
+
+Game::Game() : core::Module("Project::OSiRiON")
+{
+ game_instance = this;
+ g_impulsespeed = 0;
+}
+
+Game::~Game()
+{
+ game_instance = 0;
+}
+
+void Game::init()
+{
+ module_running = false;
+
+ ShipModel::clear();
+
+ if (!load_world()) {
+ abort();
+ return;
+ }
+
+ if (!load_ships()) {
+ abort();
+ return;
+ }
+
+ // add engine game functions
+ core::Func *func = 0;
+
+ func = core::Func::add("join", (core::GameFuncPtr) func_join);
+ func->set_info("join the game");
+ func = core::Func::add("hail", (core::GameFuncPtr) func_hail);
+ func->set_info("send a standard hail");
+ func = core::Func::add("spectate", (core::GameFuncPtr) func_spectate);
+ func->set_info("leave the game and spectate");
+
+ func = core::Func::add("buy", (core::GameFuncPtr) func_buy);
+ func->set_info("buy a ship");
+
+ func = core::Func::add("jump", (core::GameFuncPtr) func_jump);
+ func->set_info("[string] activate or deactivate hyperspace jump drive");
+
+ func = core::Func::add("impulse", (core::GameFuncPtr) func_impulse);
+ func->set_info("activate are deactive kinetic impulse drive");
+
+ // add engine core functions
+ func = core::Func::add("list_ship", (core::FuncPtr) func_list_ship);
+ func->set_info("list ship statistics");
+
+ g_impulsespeed = core::Cvar::get("g_impulsespeed", "15", core::Cvar::Game | core::Cvar::Archive);
+ g_impulsespeed->set_info("[float] speed of the impulse drive");
+
+ g_impulseacceleration = core::Cvar::get("g_impulseacceleration", "5", core::Cvar::Game | core::Cvar::Archive);
+ g_impulseacceleration->set_info("[float] acceleration of the impulse drive");
+
+ g_strafespeed = core::Cvar::get("g_strafespeed", "0.003", core::Cvar::Game | core::Cvar::Archive);
+ g_strafespeed->set_info("[float] strafe speed");
+
+ g_jumppointrange = core::Cvar::get("g_jumppointrange", "512", core::Cvar::Game | core::Cvar::Archive);
+ g_jumppointrange->set_info("[float] jumppoint range");
+
+ g_devel = core::Cvar::get("g_devel", "0", core::Cvar::Archive);
+ g_devel->set_info("[bool] enable or disable developer mode");
+
+ // indicate the module is ready to run frames
+ module_running = true;
+}
+
+void Game::shutdown()
+{
+ g_impulsespeed = 0;
+ // game functions are automaticly removed
+
+ // remove engine core functions
+ core::Func::remove("list_ship");
+
+ ShipModel::clear();
+ module_running = false;
+}
+
+bool Game::load_world()
+{
+ std::string inifilename("world");
+
+ filesystem::IniFile worldini;
+ worldini.open(inifilename);
+
+ if (!worldini.is_open()) {
+ con_error << "Could not open " << worldini.name() << std::endl;
+ return false;
+ }
+
+ core::Zone *zone = 0;
+ std::string label;
+
+ while (worldini.getline()) {
+
+ if (worldini.got_section()) {
+
+ if (worldini.got_section("world")) {
+ continue;
+ } else {
+ con_warn << worldini.name() << " unknown section '" << worldini.section() << "' at line " << worldini.line() << std::endl;
+ }
+
+ } else if (worldini.section().compare("world") == 0 ) {
+ if (worldini.got_key_string("zone", label)) {
+ aux::to_label(label);
+ zone = new core::Zone(label);
+ core::Zone::add(zone);
+ }
+ }
+ }
+ worldini.close();
+
+ if (!core::Zone::registry().size()) {
+ con_error << "No zones found!" << std::endl;
+ return false;
+ }
+
+ con_debug << " " << worldini.name() << " " << core::Zone::registry().size() << " zones" << std::endl;
+
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ if (!load_zone((*it).second)) {
+ return false;
+ }
+ }
+
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ if (!validate_zone((*it).second)) {
+ return false;
+ }
+ }
+
+ if (!default_zone) {
+ con_error << "No default zone found!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool Game::got_entity_key(filesystem::IniFile &inifile, core::Entity *entity)
+{
+ std::string shapename;
+ std::string strval;
+ float direction;
+ float pitch;
+ float roll;
+
+ if (inifile.got_key_string("shape", shapename)) {
+
+ if (shapename.compare("axis") == 0) {
+ entity->entity_shape = core::Entity::Axis;
+ return true;
+ } else if (shapename.compare("cube") == 0) {
+ entity->entity_shape = core::Entity::Cube;
+ return true;
+ } else if (shapename.compare("diamond") == 0) {
+ entity->entity_shape = core::Entity::Diamond;
+ return true;
+ } else if (shapename.compare("sphere") == 0) {
+ entity->entity_shape = core::Entity::Sphere;
+ return true;
+ } else {
+ con_warn << inifile.name() << " unknown shape '" << shapename << "' at line " << inifile.line() << std::endl;
+ return false;
+ }
+
+ } else if (inifile.got_key_string("label", strval)) {
+ aux::to_label(strval);
+ entity->entity_label.assign(strval);
+ return true;
+ } else if (inifile.got_key_string("name", strval)) {
+ aux::strip_quotes(strval);
+ entity->entity_name.assign(strval);
+ return true;
+ } else if (inifile.got_key_string("model", entity->entity_modelname)) {
+ return true;
+ } else if (inifile.got_key_angle("direction", direction)) {
+ entity->axis().change_direction(direction);
+ return true;
+ } else if (inifile.got_key_angle("pitch", pitch)) {
+ entity->axis().change_pitch(pitch);
+ return true;
+ } else if (inifile.got_key_angle("roll", roll)) {
+ entity->axis().change_roll(roll);
+ return true;
+ } else if (inifile.got_key_angle("radius", entity->entity_radius)) {
+ return true;
+ } else if (inifile.got_key_vector3f("location", entity->entity_location)) {
+ return true;
+ } else if (inifile.got_key_color("color", entity->entity_color)) {
+ return true;
+ } else if (inifile.got_key_color("colorsecond", entity->entity_color_second)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool Game::load_zone(core::Zone *zone)
+{
+ using math::Vector3f;
+ using math::Color;
+
+ std::string inifilename("zones/");
+ inifilename.append(zone->label());
+
+ filesystem::IniFile zoneini;
+ zoneini.open(inifilename);
+
+ if (!zoneini.is_open()) {
+ con_error << "Could not open " << zoneini.name() << std::endl;
+ return false;
+ }
+
+ size_t count = 0;
+
+ Planet *planet = 0;
+ Star *star = 0;
+ NavPoint *navpoint = 0;
+ JumpPoint *jumppoint = 0;
+ RaceTrack *racetrack = 0;
+ CheckPoint *checkpoint = 0;
+ core::Entity *entity = 0;
+
+ bool b;
+
+ std::string strval;
+
+ // set th default sky
+ zone->set_sky("sky");
+
+ while (zoneini.getline()) {
+ if (zoneini.got_key()) {
+ if (zoneini.section().compare("zone") == 0) {
+ if (zoneini.got_key_string("name", strval)) {
+ aux::strip_quotes(strval);
+ zone->set_name(strval);
+ continue;
+ } else if (zoneini.got_key_string("sky", strval)) {
+ zone->set_sky(strval);
+ continue;
+ } else if (zoneini.got_key_bool("default", b)) {
+ if (b) default_zone = zone;
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("star") == 0) {
+ if (got_entity_key(zoneini, star)) {
+ continue;
+ } else if (zoneini.got_key_string("texture", star->entity_texture)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("navpoint") == 0) {
+ if (got_entity_key(zoneini, navpoint)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("jumppoint") == 0) {
+ if (got_entity_key(zoneini, jumppoint)) {
+ continue;
+ } else if (zoneini.got_key_string("target", jumppoint->jumppoint_targetlabel)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ } else if (zoneini.section().compare("planet") == 0) {
+ if (got_entity_key(zoneini, planet)) {
+ continue;
+ } else if (zoneini.got_key_string("texture", planet->entity_texture)) {
+ continue;
+ } else if (zoneini.got_key_float("rotationspeed", planet->entity_rotationspeed)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("racetrack") == 0) {
+ if (got_entity_key(zoneini, racetrack)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("checkpoint") == 0) {
+ if (got_entity_key(zoneini, checkpoint)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.section().compare("entity") == 0) {
+ if (got_entity_key(zoneini, entity)) {
+ continue;
+ } else {
+ con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl;
+ }
+ }
+ } else if (zoneini.got_section("zone")) {
+ continue;
+
+ } else if (zoneini.got_section("star")) {
+ star = new Star();
+ star->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("navpoint")) {
+ navpoint = new NavPoint();
+ navpoint->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("jumppoint")) {
+ jumppoint = new JumpPoint();
+ jumppoint->set_zone(zone);
+ count ++;
+
+ } else if(zoneini.got_section("racetrack")) {
+ racetrack = new RaceTrack();
+ racetrack->set_zone(zone);
+
+ } else if(zoneini.got_section("checkpoint")) {
+ checkpoint = new CheckPoint(racetrack);
+ if (!racetrack) {
+ con_warn << zoneini.name() << " checkpoint without racetrack at line " << zoneini.line() << std::endl;
+ }
+
+ } else if (zoneini.got_section("planet")) {
+ planet = new Planet();
+ planet->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section("entity")) {
+ entity = new core::Entity();
+ entity->entity_flags += core::Entity::Static;
+ entity->set_zone(zone);
+ count ++;
+
+ } else if (zoneini.got_section()) {
+ con_warn << zoneini.name() << " unknown section '" << zoneini.section() << "' at line " << zoneini.line() << std::endl;
+ }
+ }
+ zoneini.close();
+
+ con_debug << " " << zoneini.name() << " " << zone->content().size() << " entities" << std::endl;
+
+
+ return true;
+}
+
+bool Game::validate_zone(core::Zone *zone)
+{
+ con_debug << " validating " << zone->name() << std::endl;
+
+ for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+ core::Entity *entity = (*it);
+
+ if (entity->entity_moduletypeid == jumppoint_enttype) {
+ JumpPoint *jumppoint = static_cast<JumpPoint *>(entity);
+
+ if (jumppoint->targetlabel().size() < 3) {
+ con_warn << " Jumppoint with invalid target label '" << jumppoint->targetlabel() << "'\n";
+ continue;
+ }
+ size_t pos = jumppoint->targetlabel().find(':');
+ if ((pos < 1 ) || (pos >= (jumppoint->targetlabel().size()-1))) {
+ con_warn << " Jumppoint with invalid target label '" << jumppoint->targetlabel() << "'\n";
+ continue;
+ }
+
+ std::string zonelabel(jumppoint->targetlabel().substr(0, pos));
+ std::string entitylabel(jumppoint->targetlabel().substr(pos+1, jumppoint->targetlabel().size()-pos));
+
+ core::Zone *targetzone = core::Zone::find(zonelabel);
+ if (!targetzone) {
+ con_warn << " Jumppoint with invalid target zone '" << zonelabel << "'\n";
+ continue;
+ }
+
+ core::Entity *targetentity = targetzone->find_entity(entitylabel);
+ if (!targetentity) {
+ con_warn << " Could not find target jumppoint '" << entitylabel << "'\n";
+ continue;
+ }
+
+ if (targetentity->moduletype() != jumppoint_enttype) {
+ con_warn << " Jumppoint with invalid target jumppoint '" << entitylabel << "'\n";
+ continue;
+ }
+
+ jumppoint->jumppoint_target = static_cast<JumpPoint *>(targetentity);
+
+ //con_debug << " Jumppoint " << zone->label() << ":" << jumppoint->label() << " with target " << jumppoint->targetlabel() << std::endl;
+ }
+ }
+
+ return true;
+}
+
+// read ship model specifications
+bool Game::load_ships()
+{
+ using math::Vector3f;
+ using math::Color;
+
+ default_shipmodel = 0;
+
+ filesystem::IniFile shipsini;
+ shipsini.open("ships");
+ if (!shipsini.is_open()) {
+ con_error << "Could not open ini/ships.ini!" << std::endl;
+ return false;
+ }
+
+ ShipModel *shipmodel = 0;
+ std::string label;
+ bool b;
+
+ while (shipsini.getline()) {
+ if (shipsini.got_key()) {
+ if (shipsini.section().compare("ship") == 0) {
+ if (shipsini.got_key_string("label", label)) {
+ aux::to_label(label);
+ shipmodel->shipmodel_label.assign(label);
+ ShipModel::add(shipmodel);
+ continue;
+ } else if (shipsini.got_key_string("name",shipmodel->shipmodel_name)) {
+ continue;
+ } else if (shipsini.got_key_string("model", shipmodel->shipmodel_modelname)) {
+ continue;
+ } else if (shipsini.got_key_bool("default", b)) {
+ if (b) default_shipmodel = shipmodel;
+ continue;
+ } else if (shipsini.got_key_bool("jumpdrive", shipmodel->shipmodel_jumpdrive)) {
+ continue;
+ } else if (shipsini.got_key_float("acceleration", shipmodel->shipmodel_acceleration)) {
+ continue;
+ } else if (shipsini.got_key_float("maxspeed", shipmodel->shipmodel_maxspeed)) {
+ continue;
+ } else if (shipsini.got_key_float("turnspeed", shipmodel->shipmodel_turnspeed)) {
+ math::clamp(shipmodel->shipmodel_turnspeed, 0.0f, 90.0f);
+ continue;
+ } else {
+ con_warn << shipsini.name() << " unknown key '" << shipsini.key() << "' at line " << shipsini.line() << std::endl;
+ }
+ }
+ } else if (shipsini.got_section("ship")) {
+ shipmodel = new ShipModel();
+
+ if (!default_shipmodel)
+ default_shipmodel = shipmodel;
+
+ } else if (shipsini.got_section()) {
+ con_warn << shipsini.name() << " unknown section '" << shipsini.section() << "' at line " << shipsini.line() << std::endl;
+ }
+ }
+ shipsini.close();
+
+ con_debug << " " << shipsini.name() << " " << ShipModel::registry.size() << " ship models" << std::endl;
+
+ if (!default_shipmodel) {
+ con_error << "No default ship model found!\n";
+ return false;
+ }
+
+ return true;
+}
+
+void Game::frame(float seconds)
+{
+ if (!running())
+ return;
+}
+
+void Game::player_connect(core::Player *player)
+{
+ std::string args;
+ player->set_zone(default_zone);
+ func_spectate(player, args);
+}
+
+void Game::player_disconnect(core::Player *player)
+{
+ player->remove_asset(player->control());
+}
+
+} // namespace game
+
diff --git a/src/game/base/jumppoint.cc b/src/game/base/jumppoint.cc
new file mode 100644
index 0000000..bcaf8c5
--- /dev/null
+++ b/src/game/base/jumppoint.cc
@@ -0,0 +1,29 @@
+/*
+ base/jumppoint.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "base/base.h"
+#include "base/jumppoint.h"
+
+namespace base
+{
+
+JumpPoint::JumpPoint() : core::Entity(core::Entity::Static)
+{
+ entity_shape = core::Entity::Diamond;
+ entity_color.assign(0.0f, 0.8f, 0.8f, 1.0f);
+ entity_color_second.assign(0.6f, 1.0f);
+ entity_radius = 0.25f;
+
+ entity_moduletypeid = jumppoint_enttype;
+ jumppoint_target = 0;
+ entity_serverside = false;
+}
+
+JumpPoint::~JumpPoint()
+{
+}
+
+}
diff --git a/src/game/base/jumppoint.h b/src/game/base/jumppoint.h
new file mode 100644
index 0000000..4680832
--- /dev/null
+++ b/src/game/base/jumppoint.h
@@ -0,0 +1,40 @@
+/*
+ base/jumppoint.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_JUMPPOINT_H__
+#define __INCLUDED_BASE_JUMPPOINT_H__
+
+#include "core/entity.h"
+#include "math/mathlib.h"
+
+#include <string>
+
+namespace base {
+
+/// a jump point
+/**
+ * jumppoints are used to define hyperspace routes between systems
+ * when a ship actives the jump drive, a jump point will be opened
+ * between the current system and the target of the nearest jumppoint.
+ *
+ */
+class JumpPoint : public core::Entity {
+public:
+ JumpPoint();
+ ~JumpPoint();
+
+ inline std::string const & targetlabel() { return jumppoint_targetlabel; }
+ inline JumpPoint *target() { return jumppoint_target; }
+
+ std::string jumppoint_targetlabel;
+
+ JumpPoint *jumppoint_target;
+};
+
+}
+
+#endif // __INCLUDED_BASE_JUMPPOINT_H__
+
diff --git a/src/game/base/navpoint.cc b/src/game/base/navpoint.cc
new file mode 100644
index 0000000..560962c
--- /dev/null
+++ b/src/game/base/navpoint.cc
@@ -0,0 +1,27 @@
+/*
+ base/navpoint.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "base/navpoint.h"
+#include "base/base.h"
+
+namespace base
+{
+
+NavPoint::NavPoint() : core::Entity(core::Entity::Static | core::Entity::Bright)
+{
+ entity_shape = core::Entity::Diamond;
+ entity_color.assign(1.0f, 1.0f);
+ entity_color_second.assign(0.6f, 1.0f);
+ entity_radius = 0.25f;
+
+ entity_moduletypeid = navpoint_enttype;
+}
+
+NavPoint::~NavPoint()
+{
+}
+
+}
diff --git a/src/game/base/navpoint.h b/src/game/base/navpoint.h
new file mode 100644
index 0000000..7ea505d
--- /dev/null
+++ b/src/game/base/navpoint.h
@@ -0,0 +1,27 @@
+/*
+ base/navpoint.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_NAVPOINT_H__
+#define __INCLUDED_BASE_NAVPOINT_H__
+
+#include "core/entity.h"
+#include "math/mathlib.h"
+
+#include <string>
+
+namespace base {
+
+/// a navigation point
+class NavPoint : public core::Entity {
+public:
+ NavPoint();
+ ~NavPoint();
+};
+
+}
+
+#endif // __INCLUDED_BASE_NAVPOINT_H__
+
diff --git a/src/game/base/planet.cc b/src/game/base/planet.cc
new file mode 100644
index 0000000..83f3d65
--- /dev/null
+++ b/src/game/base/planet.cc
@@ -0,0 +1,27 @@
+/*
+ base/planet.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/base.h"
+#include "base/planet.h"
+
+
+namespace base {
+
+Planet::Planet() : core::EntityGlobe(core::Entity::Static | core::Entity::Solid)
+{
+ entity_color = math::Color(1,1,1,1); // white
+ entity_radius = 64; // 64 game units
+
+ entity_moduletypeid = planet_enttype;
+
+ entity_rotationspeed = 1.0f;
+}
+
+Planet::~Planet()
+{
+}
+
+} // namespace game
diff --git a/src/game/base/planet.h b/src/game/base/planet.h
new file mode 100644
index 0000000..005157d
--- /dev/null
+++ b/src/game/base/planet.h
@@ -0,0 +1,27 @@
+/*
+ base/planet.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_PLANET_H__
+#define __INCLUDED_BASE_PLANET_H__
+
+#include "core/entity.h"
+#include "math/mathlib.h"
+
+#include <string>
+
+namespace base {
+
+/// a planet
+class Planet : public core::EntityGlobe {
+public:
+ Planet();
+ ~Planet();
+};
+
+}
+
+#endif // __INCLUDED_BASE_PLANET_H__
+
diff --git a/src/game/base/racetrack.cc b/src/game/base/racetrack.cc
new file mode 100644
index 0000000..ee2ecc7
--- /dev/null
+++ b/src/game/base/racetrack.cc
@@ -0,0 +1,195 @@
+/*
+ base/racetrack.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include <string>
+#include <sstream>
+
+#include "base/racetrack.h"
+#include "core/gameserver.h"
+
+namespace base {
+
+/* ---- class CheckPoint ------------------------------------------- */
+
+CheckPoint::CheckPoint(RaceTrack *parent)
+{
+ entity_eventstate = core::Entity::NoPower;
+ parent_track = parent;
+ if (parent) {
+ entity_color = parent->color();
+ entity_color_second = parent->color_second();
+ set_zone(parent->zone());
+ parent->add_checkpoint(this);
+ } else {
+ die();
+ }
+}
+
+CheckPoint::~CheckPoint()
+{
+
+}
+
+/* ---- class RaceTrack -------------------------------------------- */
+
+RaceTrack::RaceTrack()
+{
+ track_player = 0;
+ track_racestart = 0;
+ track_checkpointtime = 0;
+
+ entity_eventstate = core::Entity::NoPower;
+}
+
+RaceTrack::~RaceTrack()
+{
+ track_checkpoints.clear();
+}
+
+void RaceTrack::add_checkpoint(CheckPoint *checkpoint)
+{
+ track_checkpoints.push_back(checkpoint);
+}
+
+void RaceTrack::reset()
+{
+ if (track_player) {
+ track_player->set_mission_target(0);
+ }
+ track_player = 0;
+ track_racestart = 0;
+ track_checkpointtime = 0;
+
+ for (CheckPoints::iterator cpit = track_checkpoints.begin(); cpit != track_checkpoints.end(); ++cpit) {
+ (*cpit)->set_eventstate(core::Entity::NoPower);
+ }
+
+ set_eventstate(core::Entity::NoPower);
+}
+
+void RaceTrack::frame(float seconds)
+{
+ if (!track_checkpoints.size())
+ return;
+
+ if (!track_player) {
+
+ // FIXME this should go through proper collision detection
+ for (core::GameServer::Players::iterator it = core::server()->players().begin(); it != core::server()->players().end(); ++it) {
+ if ((*it)->control() && (*it)->control()->zone() == zone()) {
+ if (math::distance((*it)->control()->location(), location()) <= 1) {
+ track_player = (*it);
+
+ track_racestart = core::server()->time();
+ set_eventstate(core::Entity::Normal);
+
+ for (CheckPoints::iterator cpit = track_checkpoints.begin(); cpit != track_checkpoints.end(); ++cpit) {
+ set_eventstate(core::Entity::Normal);
+ }
+
+ entity_timer = 5.0f;
+ std::string message("^B");
+ message.append(track_player->name());
+ message.append(" ^Bactivated the race! Race starts in 5...");
+ core::server()->broadcast(message);
+ track_player->set_mission_target(this);
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ // FIXME this should go into a proper general function
+ // validate current player
+ core::Player *player = 0;
+ for (core::GameServer::Players::iterator pit = core::server()->players().begin(); (!player) && (pit != core::server()->players().end()); ++pit) {
+ if ((*pit) == track_player) {
+ player = (*pit);
+ }
+ }
+
+ if (!player) {
+ reset();
+ return;
+ }
+
+ if (!player->control() || (player->control()->zone() != zone())) {
+ reset();
+ return;
+ }
+
+ if (entity_timer) {
+
+ if (math::distance(player->control()->location(), location()) > 1) {
+ std::string message("^BNo cheating!");
+ core::server()->broadcast(message);
+ reset();
+ return;
+ }
+
+ if (track_racestart + 1.0f <= core::server()->time()) {
+ entity_timer -= 1.0f;
+ entity_dirty = true;
+
+ if (entity_timer > 0) {
+ std::stringstream msgstr;
+ msgstr << "^B" << entity_timer << "...";
+ core::server()->broadcast(msgstr.str());
+ track_racestart = core::server()->time();
+ } else {
+ for (CheckPoints::iterator cpit = track_checkpoints.begin(); cpit != track_checkpoints.end(); ++cpit) {
+ (*cpit)->set_eventstate(core::Entity::NoPower);
+ }
+ std::string message("^BGo!");
+ core::server()->broadcast(message);
+
+ track_racestart = core::server()->time();
+ track_checkpointtime = core::server()->time() + 15.0f;
+ track_checkpoint = track_checkpoints.begin();
+ (*track_checkpoint)->set_eventstate(core::Entity::Normal);
+ track_player->set_mission_target((*track_checkpoint));
+ }
+ }
+
+
+ } else {
+
+ if (core::server()->time() > track_checkpointtime) {
+ std::string message("^BToo slow, race lost!");
+ core::server()->broadcast(message);
+
+ reset();
+ return;
+ }
+
+ if (math::distance(track_player->control()->location(), (*track_checkpoint)->location()) <= 1) {
+ CheckPoints::iterator next_checkpoint = track_checkpoint;
+ next_checkpoint++;
+
+ if (next_checkpoint != track_checkpoints.end()) {
+
+ std::string message("^BCheckpoint!");
+ core::server()->broadcast(message);
+ track_checkpointtime = core::server()->time() + 15.0f;
+ (*track_checkpoint)->set_eventstate(core::Entity::NoPower);
+ track_checkpoint++;
+ (*track_checkpoint)->set_eventstate(core::Entity::Normal);
+ track_player->set_mission_target((*track_checkpoint));
+
+ } else {
+
+ std::stringstream msgstr;
+ msgstr << "^BRace completed in " << core::server()->time() - track_racestart << " seconds!";
+ core::server()->broadcast(msgstr.str());
+ reset();
+ }
+ }
+ }
+}
+
+}
diff --git a/src/game/base/racetrack.h b/src/game/base/racetrack.h
new file mode 100644
index 0000000..b5b5dad
--- /dev/null
+++ b/src/game/base/racetrack.h
@@ -0,0 +1,63 @@
+/*
+ base/racetrack.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_RACETRACK_H__
+#define __INCLUDED_BASE_RACETRACK_H__
+
+#include "core/entity.h"
+#include "core/player.h"
+#include "math/mathlib.h"
+
+#include <string>
+
+namespace base {
+
+class CheckPoint;
+
+/* ---- class RaceTrack -------------------------------------------- */
+
+class RaceTrack : public core::EntityDynamic {
+
+public:
+ typedef std::list<CheckPoint *> CheckPoints ;
+
+ RaceTrack();
+ ~RaceTrack();
+
+ void add_checkpoint(CheckPoint *checkpoint);
+
+ /// reset the race track
+ void reset();
+
+ virtual void frame(float seconds);
+
+ inline core::Player *player() { return track_player; }
+
+private:
+ CheckPoints track_checkpoints;
+ core::Player *track_player;
+ float track_racestart;
+ float track_checkpointtime;
+ CheckPoints::iterator track_checkpoint;
+
+};
+
+/* ---- class CheckPoint ------------------------------------------- */
+
+class CheckPoint : public core::EntityDynamic {
+public:
+ CheckPoint(RaceTrack *parent);
+ ~CheckPoint();
+
+private:
+ RaceTrack *parent_track;
+};
+
+
+}
+
+#endif // __INCLUDED_BASE_NAVPOINT_H__
+
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
new file mode 100644
index 0000000..0fdfd3f
--- /dev/null
+++ b/src/game/base/ship.cc
@@ -0,0 +1,464 @@
+/*
+ base/ship.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include <cmath>
+#include <iostream>
+
+#include "auxiliary/functions.h"
+#include "core/gameserver.h"
+#include "core/entity.h"
+#include "base/base.h"
+#include "base/ship.h"
+#include "math/functions.h"
+
+
+
+using math::degrees360f;
+using math::degrees180f;
+
+namespace base {
+
+const float MIN_DELTA = 0.000001f;
+
+Ship::Ship(core::Player *owner, ShipModel *shipmodel) :
+ core::EntityControlable(owner, ship_enttype)
+{
+ entity_modelname = "ships/" + shipmodel->modelname();
+ entity_name = shipmodel->name() + ": <^B" + owner->name() + "^N>";
+ entity_label = shipmodel->label();
+
+ entity_moduletypeid = ship_enttype;
+
+ entity_color = owner->color();
+ entity_color_second = owner->color_second();
+
+ ship_shipmodel = shipmodel;
+ ship_jumpdrive = shipmodel->shipmodel_jumpdrive;
+
+ ship_impulsedrive_timer = 0;
+ ship_jumpdrive_timer = 0;
+
+ reset();
+}
+
+Ship::~Ship()
+{
+
+}
+
+void Ship::reset()
+{
+ current_target_direction = 0.0f;
+ current_target_pitch = 0.0f;;
+ current_target_roll = 0.0f;
+ current_target_strafe = 0.0f;
+ current_target_afterburner = 0.0f;
+}
+void Ship::impulse()
+{
+ if (entity_eventstate == core::Entity::Jump) {
+ return;
+
+ } else if ((entity_eventstate == core::Entity::Impulse) || (entity_eventstate == core::Entity::ImpulseInitiate)) {
+ entity_eventstate = core::Entity::Normal;
+
+ } else {
+
+ if (entity_eventstate == core::Entity::JumpInitiate) {
+ ship_jumpdrive_timer = 0;
+ entity_timer = 0;
+ }
+
+ entity_eventstate = core::Entity::ImpulseInitiate;
+ if (Base::instance()->g_devel->value()) {
+ entity_timer = 0;
+ } else {
+ entity_timer = 3;
+ }
+ ship_impulsedrive_timer = core::server()->time();
+ entity_dirty = true;
+ }
+
+ entity_dirty = true;
+}
+
+void Ship::jump(std::string const &args)
+{
+ // devel mode provides instant jump access to arbitrary systems
+ if (Base::instance()->g_devel->value() && (args.size())) {
+
+ core::Zone *jumptargetzone = 0;
+ std::string target;
+ std::istringstream is(args);
+ if (!(is >> target)) {
+ std::string helpstr;
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ core::Zone *zone = (*it).second;
+ if (helpstr.size())
+ helpstr.append("^N|^B");
+ helpstr.append(zone->label());
+ }
+
+ core::server()->send(owner(), "Usage: jump [^B" + helpstr + "^N]");
+ return;
+ }
+
+ aux::to_lowercase(target);
+ jumptargetzone = core::Zone::find_zone(target);
+ if (!jumptargetzone) {
+ core::server()->send(owner(), "Unknown system '" + target + '\'');
+ return;
+ }
+
+ if (jumptargetzone == zone()) {
+ core::server()->send(owner(), "Already in the " + jumptargetzone->name() + '.');
+ return;
+ }
+
+ core::server()->send(owner(), "Jumping to the " + jumptargetzone->name());
+ set_zone(jumptargetzone);
+ if (owner()->control() == (EntityControlable*) this)
+ owner()->set_zone(jumptargetzone);
+
+ ship_jumpdrive_timer = 0;
+ entity_timer = 0;
+ entity_eventstate = core::Entity::Jump;
+ entity_dirty = true;
+ return;
+
+ } else {
+ if (!jumpdrive() && !Base::instance()->g_devel->value()) {
+ core::server()->send(owner(), "This ship is not equiped with a hyperspace drive!");
+ return;
+
+ } else if (entity_eventstate == core::Entity::Jump) {
+ return;
+
+ } else if (entity_eventstate == core::Entity::JumpInitiate) {
+ core::server()->send(owner(), "Jump aborted, hyperspace drive deactivated.");
+ ship_jumpdrive_timer = 0;
+ entity_timer = 0;
+ entity_eventstate = core::Entity::Normal;
+ return;
+ }
+
+ if (!find_closest_jumppoint()) {
+ return;
+ }
+
+ entity_eventstate = core::Entity::JumpInitiate;
+ if (Base::instance()->g_devel->value()) {
+ entity_timer = 0;
+ } else {
+ entity_timer = 8;
+ }
+
+ ship_jumpdrive_timer = core::server()->time();
+ entity_dirty = true;
+ }
+}
+
+JumpPoint * Ship::find_closest_jumppoint()
+{
+ // find closest jumppoint
+ float d = -1;
+ JumpPoint *jumppoint = 0;
+ for (core::Zone::Content::iterator it = zone()->content().begin(); it != zone()->content().end(); it++) {
+ core::Entity *entity = (*it);
+ if (entity->moduletype() == jumppoint_enttype) {
+ JumpPoint *te = static_cast<JumpPoint *>(entity);
+ float d1 = math::distance(location(), te->location());
+ if ((d < 0) || (d1 < d)) {
+ d = d1;
+ jumppoint = te;
+ }
+ }
+ }
+
+ if (jumppoint && jumppoint->target()) {
+ if (Base::instance()->g_jumppointrange->value() < d) {
+ core::server()->send(owner(), "Jumppoint out of range!");
+ return 0;
+ } else {
+ core::server()->send(owner(), "Jumping to the " + jumppoint->target()->zone()->name());
+ return jumppoint;
+ }
+ } else {
+ core::server()->send(owner(), "No jumppoints found!");
+ return 0;
+ }
+
+ return 0;
+}
+
+void Ship::frame(float seconds)
+{
+ const float direction_change_speed = 2;
+ float cosangle; // cosine of an angle
+ float angle; // angle in radians
+ math::Vector3f n; // normal of a plane
+
+ float actual_maxspeed = ship_shipmodel->maxspeed();
+ float actual_turnspeed = ship_shipmodel->turnspeed();
+ float actual_acceleration = ship_shipmodel->acceleration();
+
+ entity_movement = 0;
+
+ // speed might get set to 0 on this update
+ if (entity_speed != 0.0f)
+ entity_dirty = true;
+
+ // jumpdrive
+ // target axis
+ math::Axis target_axis(entity_axis);
+
+ if (entity_eventstate == core::Entity::JumpInitiate) {
+
+ if (ship_jumpdrive_timer + 1.0f <= core::server()->time()) {
+ entity_timer -= 1.0f;
+
+ if (entity_timer <= 0) {
+ JumpPoint *jumppoint = find_closest_jumppoint();
+
+ if (jumppoint) {
+ set_zone(jumppoint->target()->zone());
+ if (owner()->control() == (EntityControlable*) this)
+ owner()->set_zone(jumppoint->target()->zone());
+ entity_eventstate = core::Entity::Jump;
+ entity_location.assign(jumppoint->target()->location() + location() - jumppoint->location());
+ } else {
+ entity_eventstate = core::Entity::Normal;
+ }
+ ship_jumpdrive_timer = 0;
+ entity_timer = 0;
+
+ entity_dirty = true;
+ return;
+ } else {
+ ship_jumpdrive_timer = core::server()->time();
+ entity_dirty = true;
+ }
+ }
+
+ // control is disabled while the jumpdrive is activated
+ target_thrust = 0;
+ target_pitch = 0;
+ target_roll = 0;
+ target_direction = 0;
+ target_afterburner = 0.0f;
+ target_thrust = 0;
+
+ } else if (entity_eventstate == core::Entity::Jump) {
+ // control is disabled while the jumpdrive is activated
+ target_thrust = 0;
+ target_pitch = 0;
+ target_roll = 0;
+ target_direction = 0;
+ target_afterburner = 0.0f;
+ target_thrust = 0;
+
+ // FIXME jump location and axis
+ math::Axis default_axis;
+ entity_axis.assign(default_axis);
+ entity_dirty = true;
+
+ // FIXME 5 second cooldown
+ entity_eventstate = core::Entity::Normal;
+
+ } else if (entity_eventstate == core::Entity::ImpulseInitiate) {
+
+ if (ship_impulsedrive_timer + 1.0f <= core::server()->time()) {
+ entity_timer -= 1.0f;
+
+ if (entity_timer <= 0) {
+ actual_maxspeed = Base::instance()->g_impulsespeed->value();
+ actual_acceleration = Base::instance()->g_impulseacceleration->value();
+ entity_eventstate = core::Entity::Impulse;
+ entity_timer = 0;
+ entity_dirty = true;
+ } else {
+ ship_impulsedrive_timer = core::server()->time();
+ entity_dirty = true;
+ }
+ }
+
+ // clamp input values
+ target_thrust = 0.0f;
+ math::clamp(target_pitch, -1.0f, 1.0f);
+ math::clamp(target_roll, -1.0f, 1.0f);
+ math::clamp(target_direction, -1.0f, 1.0f);
+ math::clamp(target_afterburner, -1.0f, 1.0f);
+ actual_turnspeed *= 0.5;
+
+ } else if (entity_eventstate == core::Entity::Impulse) {
+
+ // clamp input values
+ target_thrust = 0.0f;
+ math::clamp(target_pitch, -1.0f, 1.0f);
+ math::clamp(target_roll, -1.0f, 1.0f);
+ math::clamp(target_direction, -1.0f, 1.0f);
+ target_afterburner = 0.0f;
+ actual_maxspeed = Base::instance()->g_impulsespeed->value();
+ actual_acceleration = Base::instance()->g_impulseacceleration->value();
+ actual_turnspeed *= 0.5;
+
+ } else if (entity_eventstate == core::Entity::Normal) {
+
+ // clamp input values
+ math::clamp(target_thrust, 0.0f, 1.0f);
+ math::clamp(target_pitch, -1.0f, 1.0f);
+ math::clamp(target_roll, -1.0f, 1.0f);
+ math::clamp(target_direction, -1.0f, 1.0f);
+ math::clamp(target_afterburner, -1.0f, 1.0f);
+
+ if (speed() > actual_maxspeed * 1.15f) {
+ actual_acceleration = Base::instance()->g_impulseacceleration->value();
+ actual_turnspeed *= 0.5;
+ }
+
+ }
+
+ // update roll
+ if (current_target_roll < target_roll) {
+ current_target_roll += direction_change_speed * seconds;
+ if (current_target_roll > target_roll)
+ current_target_roll = target_roll;
+ } else if (current_target_roll > target_roll) {
+ current_target_roll -= direction_change_speed * seconds;
+ if (current_target_roll < target_roll)
+ current_target_roll = target_roll;
+ }
+ math::clamp(current_target_roll, -1.0f, 1.0f);
+
+ if (fabs(current_target_roll) > MIN_DELTA) {
+ float roll_offset = seconds * current_target_roll;
+ entity_axis.change_roll(actual_turnspeed * roll_offset);
+ } else {
+ current_target_roll = 0.0f;
+ }
+
+ // update target_axis direction
+ if (current_target_direction < target_direction) {
+ current_target_direction += direction_change_speed * seconds;
+ if (current_target_direction > target_direction) {
+ current_target_direction = target_direction;
+ }
+ } else if (current_target_direction > target_direction) {
+ current_target_direction -= direction_change_speed * seconds;
+ if (current_target_direction < target_direction) {
+ current_target_direction = target_direction;
+ }
+ }
+
+ if (fabs(current_target_direction) > MIN_DELTA ) {
+ math::clamp(current_target_direction, -1.0f, 1.0f);
+ target_axis.change_direction(actual_turnspeed * current_target_direction);
+ } else {
+ current_target_direction = 0.0f;
+ }
+
+ if (current_target_pitch < target_pitch) {
+ current_target_pitch += direction_change_speed * seconds;
+ if (current_target_pitch > target_pitch)
+ current_target_pitch = target_pitch;
+ } else if (current_target_pitch > target_pitch) {
+ current_target_pitch -= direction_change_speed * seconds;
+ if (current_target_pitch < target_pitch)
+ current_target_pitch = target_pitch;
+ }
+
+ if (fabs(current_target_pitch) > MIN_DELTA) {
+ math::clamp(current_target_pitch, -1.0f, 1.0f);
+ target_axis.change_pitch(actual_turnspeed * current_target_pitch);
+ } else {
+ current_target_pitch = 0.0f;
+ }
+
+ n.assign(math::crossproduct(entity_axis.forward(), target_axis.forward()));
+ if (!(n.length() < MIN_DELTA)) {
+ n.normalize();
+ cosangle = math::dotproduct(entity_axis.forward(), target_axis.forward());
+ angle = acos(cosangle) * seconds; // * 180.0f / M_PI;
+ if (angle > MIN_DELTA)
+ entity_axis.rotate(n, -angle);
+ }
+
+ // update afterburner
+ if (current_target_afterburner < target_afterburner) {
+ current_target_afterburner += 2.0f * seconds;
+ if (current_target_afterburner > target_afterburner)
+ current_target_afterburner = target_afterburner;
+ } else if (current_target_afterburner > target_afterburner) {
+ current_target_afterburner -= 2.0f * seconds;
+ if (current_target_afterburner < target_afterburner)
+ current_target_afterburner = target_afterburner;
+ }
+
+ // update thrust
+ if (current_target_afterburner < 0.0f) {
+ target_thrust = 0;
+ }
+
+ if (entity_thrust < target_thrust) {
+ entity_thrust += seconds * 0.5f;
+ if (entity_thrust > target_thrust)
+ entity_thrust = target_thrust;
+ } else if (entity_thrust > target_thrust) {
+ entity_thrust -= seconds * 0.5f;
+ if (entity_thrust < target_thrust)
+ entity_thrust = target_thrust;
+ }
+ math::clamp(entity_thrust, 0.0f, 1.0f);
+ float actual_thrust = entity_thrust + current_target_afterburner * 0.15f;
+
+ if ((entity_eventstate == core::Entity::ImpulseInitiate) || (entity_eventstate == core::Entity::Impulse)) {
+ actual_thrust = 1.0f;
+ }
+
+ // update speed
+ if (entity_speed < actual_thrust * actual_maxspeed) {
+ entity_speed += actual_acceleration * seconds;
+ if (entity_speed > actual_thrust * actual_maxspeed) {
+ entity_speed = actual_thrust * actual_maxspeed;
+ }
+ } else if(entity_speed > actual_thrust * actual_maxspeed) {
+ entity_speed -= actual_acceleration * seconds;
+ if (entity_speed < actual_thrust * actual_maxspeed) {
+ entity_speed = actual_thrust * actual_maxspeed;
+ }
+ }
+
+ // update strafe
+ if (current_target_strafe < target_strafe) {
+ current_target_strafe += 2.0f * seconds;
+ if (current_target_strafe > target_strafe)
+ current_target_strafe = target_strafe;
+ } else if (current_target_strafe > target_strafe) {
+ current_target_strafe -= 2.0f * seconds;
+ if (current_target_strafe < target_strafe)
+ current_target_strafe = target_strafe;
+ }
+
+ if (fabs(current_target_strafe) > MIN_DELTA) {
+ entity_location += entity_axis.left() * (current_target_strafe * Base::instance()->g_strafespeed->value());
+ }
+
+ entity_movement = target_thrust;
+ entity_movement = math::max(entity_movement, fabs(current_target_pitch));
+ entity_movement = math::max(entity_movement, fabs(current_target_direction));
+ entity_movement = math::max(entity_movement, fabs(current_target_roll));
+ entity_movement = math::max(entity_movement, fabs(current_target_afterburner));
+ entity_movement = math::max(entity_movement, fabs(current_target_strafe));
+
+ if (entity_speed) {
+ entity_location += entity_axis.forward() * entity_speed * seconds;
+ entity_dirty = true;
+ } else if (entity_movement > 0.0f) {
+ entity_dirty = true;
+ }
+}
+
+} // namespace game
diff --git a/src/game/base/ship.h b/src/game/base/ship.h
new file mode 100644
index 0000000..d3c8bbf
--- /dev/null
+++ b/src/game/base/ship.h
@@ -0,0 +1,60 @@
+/*
+ base/ship.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_SHIP_H__
+#define __INCLUDED_BASE_SHIP_H__
+
+#include "core/player.h"
+#include "core/entity.h"
+#include "base/shipmodel.h"
+#include "base/jumppoint.h"
+#include "math/vector3f.h"
+
+namespace base {
+
+/// A ship in the game, controled by a player
+class Ship : public core::EntityControlable
+{
+public:
+ Ship(core::Player *owner, ShipModel *shipmodel);
+ ~Ship();
+
+ /// update the ship state
+ virtual void frame(float seconds);
+
+ /// true if the ship is equiped with a jumpdrive
+ inline bool jumpdrive() const { return ship_jumpdrive; }
+
+ /// toggle jump drive activation
+ void jump(std::string const & args);
+
+ /// toggle impulse drive activation
+ void impulse();
+
+ /// void reset drive controls
+ void reset();
+
+private:
+ ShipModel *ship_shipmodel;
+
+ float current_target_direction;
+ float current_target_pitch;
+ float current_target_roll;
+ float current_target_strafe;
+ float current_target_afterburner;
+
+ bool ship_jumpdrive;
+ float ship_jumpdrive_timer;
+
+ float ship_impulsedrive_timer;
+
+ JumpPoint * find_closest_jumppoint();
+};
+
+}
+
+#endif // __INCLUDED_BASE_SHIP_H__
+
diff --git a/src/game/base/shipmodel.cc b/src/game/base/shipmodel.cc
new file mode 100644
index 0000000..6018414
--- /dev/null
+++ b/src/game/base/shipmodel.cc
@@ -0,0 +1,72 @@
+/*
+ base/shipmodel.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "sys/sys.h"
+#include "base/shipmodel.h"
+
+namespace base {
+
+// the ship model registry
+std::map<std::string, ShipModel *> ShipModel::registry;
+
+ShipModel::ShipModel()
+{
+ //default specifications
+ shipmodel_acceleration = 1.0f; // thruster acceleration in game untits/second^2
+ shipmodel_maxspeed = 3.0f; // maximum thruster speed in game units/second
+ shipmodel_turnspeed = 45.0f; // 45 degrees per second
+
+ shipmodel_jumpdrive = false;
+}
+
+ShipModel::~ShipModel()
+{}
+
+
+// clear the ship model registry
+void ShipModel::clear()
+{
+ for (iterator smit = registry.begin(); smit != registry.end(); smit++) {
+ delete (*smit).second;
+ }
+ registry.clear();
+}
+
+void ShipModel::list()
+{
+ for (iterator smit = registry.begin(); smit != registry.end(); smit++) {
+ con_print <<
+ " " << (*smit).second->label() <<
+ " " << (*smit).second->name() <<
+ " accel " << (*smit).second->acceleration() <<
+ " max " << (*smit).second->maxspeed() <<
+ " turn " << (*smit).second->turnspeed() << "\n";
+ }
+ con_print << registry.size() << " registered ship models\n";
+}
+
+ShipModel *ShipModel::find(const std::string label)
+{
+ std::map<std::string, ShipModel *>::iterator it = registry.find(label);
+ if (it == registry.end())
+ return 0;
+ else
+ return (*it).second;
+}
+
+// add a new ship model
+void ShipModel::add(ShipModel *shipmodel)
+{
+ ShipModel *m = find(shipmodel->label());
+ if (m) {
+ con_warn << "Duplicate ship model " << shipmodel->label() << "!\n";
+ delete m;
+ }
+
+ registry[shipmodel->label()] = shipmodel;
+}
+
+}
diff --git a/src/game/base/shipmodel.h b/src/game/base/shipmodel.h
new file mode 100644
index 0000000..d92b840
--- /dev/null
+++ b/src/game/base/shipmodel.h
@@ -0,0 +1,70 @@
+/*
+ base/shipmodel.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_SHIPMODEL_H__
+#define __INCLUDED_BASE_SHIPMODEL_H__
+
+#include <map>
+#include <string>
+
+namespace base {
+
+/// ship model specifications
+class ShipModel
+{
+public:
+ ShipModel();
+ ~ShipModel();
+
+ /// acceleration
+ inline float acceleration() const { return shipmodel_acceleration; }
+
+ /// maximum speed
+ inline float maxspeed() const { return shipmodel_maxspeed; }
+
+ /// turn speed in rotations per second
+ inline float turnspeed() const { return shipmodel_turnspeed; }
+
+ /// label of the ship model
+ inline std::string const &label() const { return shipmodel_label; }
+
+ /// name of the ship model
+ inline std::string const & name() const { return shipmodel_name; }
+
+ /// name of the model of the ship
+ inline std::string const & modelname() const { return shipmodel_modelname; }
+
+ float shipmodel_acceleration;
+ float shipmodel_maxspeed;
+ float shipmodel_turnspeed;
+ std::string shipmodel_label;
+ std::string shipmodel_name;
+ std::string shipmodel_modelname;
+
+ /// indicates of this model can be equiped with a jump drive
+ bool shipmodel_jumpdrive;
+
+ static ShipModel *find(const std::string label);
+
+ /// the ship model registry
+ static std::map<std::string, ShipModel *> registry;
+
+ typedef std::map<std::string, ShipModel *>::iterator iterator;
+
+ /// clear the ship model registry
+ static void clear();
+
+ /// list the ship model registry
+ static void list();
+
+ /// add a new ship model
+ static void add(ShipModel *shipmodel);
+};
+
+}
+
+#endif // __INCLUDED_BASE_SHIPMODEL_H__
+
diff --git a/src/game/base/star.cc b/src/game/base/star.cc
new file mode 100644
index 0000000..cacd542
--- /dev/null
+++ b/src/game/base/star.cc
@@ -0,0 +1,25 @@
+/*
+ base/star.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/base.h"
+#include "base/star.h"
+
+
+namespace base {
+
+Star::Star() : core::EntityGlobe(core::Entity::Static | core::Entity::Solid | core::Entity::Bright)
+{
+ entity_color = math::Color(1,1,1,1); // white
+ entity_radius = 96; // 96 game units
+
+ entity_moduletypeid = star_enttype;
+}
+
+Star::~Star()
+{
+}
+
+} // namespace game
diff --git a/src/game/base/star.h b/src/game/base/star.h
new file mode 100644
index 0000000..5a78fc8
--- /dev/null
+++ b/src/game/base/star.h
@@ -0,0 +1,29 @@
+/*
+ base/star.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_STAR_H__
+#define __INCLUDED_BASE_STAR_H__
+
+// project headers
+#include "core/entity.h"
+#include "math/mathlib.h"
+
+// C++ headers
+#include <string>
+
+namespace base {
+
+/// a star, that shines so bright
+class Star : public core::EntityGlobe {
+public:
+ Star();
+ ~Star();
+};
+
+}
+
+#endif // __INCLUDED_BASE_STAR_H__
+