Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/base/game.cc')
-rw-r--r--src/game/base/game.cc774
1 files changed, 774 insertions, 0 deletions
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
new file mode 100644
index 0000000..d20dd8c
--- /dev/null
+++ b/src/game/base/game.cc
@@ -0,0 +1,774 @@
+/*
+ base/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 <assert.h>
+
+#include "auxiliary/functions.h"
+#include "core/gameserver.h"
+#include "core/parser.h"
+#include "core/descriptions.h"
+#include "filesystem/filesystem.h"
+#include "filesystem/inifile.h"
+#include "base/game.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 game
+{
+
+/* -- class Base static members ----------------------------------- */
+
+// game variables
+core::Cvar *Game::g_impulsespeed = 0;
+core::Cvar *Game::g_impulseacceleration = 0;
+core::Cvar *Game::g_strafespeed = 0;
+core::Cvar *Game::g_jumppointrange = 0;
+core::Cvar *Game::g_devel = 0;
+
+core::Zone *Game::default_zone = 0;
+ShipModel *Game::default_shipmodel = 0;
+
+// list the ship model registry
+void Game::func_list_ship(std::string const &args)
+{
+ ShipModel::list();
+}
+
+// a player joins the game
+void Game::func_join(core::Player *player, std::string const &args)
+{
+ if (player->control())
+ return;
+
+ Ship *ship = new Ship(player, Game::default_shipmodel);
+ ship->set_zone(player->zone());
+ player->set_control(ship);
+
+ core::Entity *dock = ship->zone()->default_view();
+ if (dock) {
+ ship->entity_location.assign(dock->location() + (dock->axis().forward() * ((ship->radius()+ dock->radius())*2.0f)));
+ ship->entity_axis.assign(dock->axis());
+ ship->set_eventstate(core::Entity::Docked);
+ player->set_view(dock);
+ }
+
+ std::string message("^B");
+ message.append(player->name());
+ message.append("^B joins the game.");
+ core::server()->broadcast(message);
+
+ player->send("^BYou received " + aux::article(Game::default_shipmodel->name()));
+ player->sound("game/buy-ship");
+
+ player->player_dirty = true;
+}
+
+// a player joins the spectators
+void Game::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());
+ }
+
+ if (!player->zone())
+ player->set_zone(Game::default_zone);
+
+ player->set_view(0);
+}
+
+// a player buys a ship
+void Game::func_buy(core::Player *player, std::string const &args)
+{
+ if (!g_devel->value() && !player->view()) {
+ player->send("Cheats disabled.");
+ return;
+ }
+
+ // FIXME verify the base sells this ship
+
+ 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());
+ }
+
+ core::Entity *dock = player->view();
+ Ship * ship = new Ship(player, shipmodel);
+ ship->set_zone(player->zone());
+ player->set_control(ship);
+
+ if (dock) {
+ player->control()->location().assign(dock->location());
+ player->control()->set_eventstate(core::Entity::Docked);
+ ship->entity_axis.assign(dock->axis());
+ ship->entity_axis.change_direction(180.0f);
+ player->set_view(dock);
+ }
+
+ player->send("^BPurchased " + aux::article(shipmodel->name()));
+ player->sound("game/buy-ship");
+
+ } else {
+ player->send("Usage: buy [^B" + helpstr + "^N]");
+ }
+}
+
+// a player sends standard hails
+void Game::func_hail(core::Player *player, std::string const &args)
+{
+ if (player->mute()) {
+ player->send("^WYou have been muted");
+ return;
+ }
+
+ std::string target;
+ std::istringstream is(args);
+ if (!(is >> target)) {
+ player->send("Usage: hail [player]");
+ return;
+ }
+
+ core::Player *targetplayer = core::server()->find_player(target);
+ if (!targetplayer) {
+ player->send("Player " + target + "^N not found");
+ return;
+ }
+
+ player->send("^BYou hail " + targetplayer->name());
+ player->sound("com/hail");
+
+ targetplayer->send("^B" + player->name() + "^B hails you");
+ targetplayer->sound("com/hail");
+}
+
+// a player actives the hyperspace jump drive on his ship
+void Game::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->func_jump(args);
+}
+
+// a player actives the kinetic impulse drive on his ship
+void Game::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->func_impulse();
+}
+
+// a player sends a docking request
+void Game::func_dock(core::Player *player,core::Entity *entity)
+{
+ if (!player->control())
+ return;
+
+ if (player->control()->zone() != entity->zone())
+ return;
+
+ if ((entity->flags() & core::Entity::Dockable) == 0)
+ return;
+
+ if (player->control()->eventstate() == core::Entity::Docked)
+ return;
+
+ if (math::distance(entity->location(), player->control()->location()) > 2.0f * (entity->radius()+player->control()->radius())) {
+ player->send("Target out of range");
+ return;
+ }
+
+ if (entity->moduletype() == jumpgate_enttype) {
+ JumpGate *jumpgate = static_cast<JumpGate *>(entity);
+ if (jumpgate->target()) {
+ if (jumpgate->activated()) {
+ player->send("Jumpgate in use");
+ return;
+ }
+ player->set_view(jumpgate);
+ Ship * ship = static_cast<Ship *>(player->control());
+ ship->initiate_jump(jumpgate);
+ jumpgate->activate();
+ if (jumpgate->target()->moduletype() == jumpgate_enttype) {
+ static_cast<JumpGate *>(jumpgate->target())->activate();
+ }
+ } else {
+ player->send("Jumpgate inactive.");
+ }
+ } else {
+
+ player->control()->location().assign(entity->location());
+ player->control()->set_eventstate(core::Entity::Docked);
+ player->set_view(entity);
+ player->send("^BDocking at " + entity->name());
+ }
+}
+
+// launch request
+void Game::func_launch(core::Player *player, std::string const &args)
+{
+ if (!player->control())
+ return;
+
+ if (!player->view())
+ return;
+
+ if (player->control()->eventstate() != core::Entity::Docked)
+ return;
+
+ assert(player->view()->zone() == player->control()->zone());
+
+ core::Entity *dock = player->view();
+ player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * (player->control()->radius()+ dock->radius())*2.0f));
+ player->control()->entity_axis.assign(dock->axis());
+ player->control()->set_eventstate(core::Entity::Normal);
+ player->set_view(0);
+
+ player->send("^BLaunching from " + dock->name());
+}
+
+// instantaniously goto a specified entity within the zone
+void Game::func_goto(core::Player *player, const std::string &args)
+{
+ if (!args.size())
+ return;
+
+ if (!g_devel->value()) {
+ player->send("Cheats disabled");
+ return;
+ }
+
+ if (!player->control())
+ return;
+
+ core::Entity *dock = 0;
+ std::string label(args);
+ aux::to_label(label);
+
+ core::Zone *zone = player->control()->zone();
+ for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it ++) {
+ std::string str((*it)->label());
+ aux::to_label(str);
+ if (str.find(label) != std::string::npos) {
+ dock = (*it);
+ }
+ }
+
+ if (dock) {
+ player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * (player->control()->radius()+dock->radius())*2.0f));
+ player->control()->entity_axis.assign(dock->axis());
+ player->control()->entity_axis.change_direction(180.0f);
+ player->control()->set_eventstate(core::Entity::Normal);
+ player->set_view(0);
+ player->send("Going to " + dock->name());
+ } else {
+ player->send("Entity '" + args + "' not found");
+ }
+}
+
+/* -- class Base -------------------------------------------------- */
+
+Game::Game() : core::Module("base", "Project::OSiRiON", true)
+{
+ default_shipmodel = 0;
+ default_zone = 0;
+}
+
+Game::~Game()
+{
+}
+
+void Game::init()
+{
+ ShipModel::clear();
+
+ if (!load_world()) {
+ abort();
+ return;
+ }
+
+ if (!load_ships()) {
+ abort();
+ return;
+ }
+
+ // add engine functions
+ core::Func *func = 0;
+
+ func = core::Func::add("list_ship", Game::func_list_ship);
+ func->set_info("list ship statistics");
+
+ func = core::Func::add("join", Game::func_join);
+ func->set_info("join the game");
+
+ func = core::Func::add("hail", Game::func_hail);
+ func->set_info("send a standard hail");
+
+ func = core::Func::add("spectate", Game::func_spectate);
+ func->set_info("leave the game and spectate");
+
+ func = core::Func::add("buy", Game::func_buy);
+ func->set_info("buy a ship");
+
+ func = core::Func::add("jump", Game::func_jump);
+ func->set_info("[string] activate or deactivate hyperspace jump drive");
+
+ func = core::Func::add("impulse", Game::func_impulse);
+ func->set_info("activate are deactive kinetic impulse drive");
+
+ func = core::Func::add("launch", Game::func_launch);
+ func->set_info("launch to space when docked");
+
+ func = core::Func::add("goto", Game::func_goto);
+ func->set_info("[string] goto to an entity within the zone");
+
+ func = core::Func::add("@dock", Game::func_dock);
+ func->set_info("dock with target object");
+
+ // add engine variables
+ 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.01", 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");
+}
+
+void Game::shutdown()
+{
+ g_impulsespeed = 0;
+ // game functions are automaticly removed
+
+ // remove engine core functions
+ core::Func::remove("list_ship");
+
+ ShipModel::clear();
+}
+
+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;
+ }
+
+ con_print << "^BLoading world..." << std::endl;
+
+ core::Zone *zone = 0;
+ std::string label;
+
+ while (worldini.getline()) {
+
+ if (worldini.got_section()) {
+
+ if (worldini.got_section("world")) {
+ continue;
+ } else {
+ worldini.unknown_section();
+ }
+
+ } else if (worldini.got_key()) {
+
+ if (worldini.in_section("world")) {
+
+ if (worldini.got_key_string("zone", label)) {
+ aux::to_label(label);
+ zone = new core::Zone(label);
+ core::Zone::add(zone);
+ } else {
+ worldini.unkown_key();
+ }
+ }
+ }
+ }
+
+ 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::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;
+ }
+
+ con_print << "^BLoading zone " << zone->label() << "..." << std::endl;
+
+ 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_section()) {
+ 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("jumpgate")) {
+ jumppoint = new JumpGate();
+ jumppoint->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->set_flag(core::Entity::Static);
+ entity->set_zone(zone);
+ count ++;
+
+ } else {
+ zoneini.unknown_section();
+ }
+
+ } else if (zoneini.got_key()) {
+
+ if (zoneini.in_section("zone")) {
+ 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 {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("star")) {
+ if (core::Parser::got_entity_key(zoneini, star)) {
+ continue;
+ } else if (zoneini.got_key_string("texture", star->entity_texture)) {
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("navpoint")) {
+ if (core::Parser::got_entity_key(zoneini, navpoint)) {
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("jumppoint") || zoneini.in_section("jumpgate")) {
+ if (core::Parser::got_entity_key(zoneini, jumppoint)) {
+ continue;
+ } else if (zoneini.got_key_string("target", strval)) {
+ jumppoint->set_targetlabel(strval);
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("planet")) {
+ if (core::Parser::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 if (zoneini.got_key_bool("dock", b)) {
+ if (b) {
+ planet->set_flag(core::Entity::Dockable);
+ core::Descriptions::load_entity_menus(planet, "zones/" + zone->label() + "/" + planet->label());
+ } else {
+ planet->unset_flag(core::Entity::Dockable);
+ }
+ } else if (zoneini.got_key_bool("default", b)) {
+ if (b) {
+ zone->set_default_view(planet);
+ }
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("racetrack")) {
+ if (core::Parser::got_entity_key(zoneini, racetrack)) {
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("checkpoint")) {
+ if (core::Parser::got_entity_key(zoneini, checkpoint)) {
+ continue;
+ } else {
+ zoneini.unkown_key();
+ }
+
+ } else if (zoneini.in_section("entity")) {
+ if (core::Parser::got_entity_key(zoneini, entity)) {
+ continue;
+ } else if (zoneini.got_key_bool("default", b)) {
+ if (b) {
+ zone->set_default_view(entity);
+ }
+ } else if (zoneini.got_key_bool("dock", b)) {
+ if (b) {
+ entity->set_flag(core::Entity::Dockable);
+ core::Descriptions::load_entity_menus(entity, "zones/" + zone->label() + "/" + entity->label());
+ } else {
+ entity->unset_flag(core::Entity::Dockable);
+ }
+ } else {
+ zoneini.unkown_key();
+ }
+ }
+
+ }
+ }
+ 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) {
+ // validate jump points
+ JumpPoint *jumppoint = static_cast<JumpPoint *>(entity);
+ jumppoint->validate();
+ } else if (entity->entity_moduletypeid == jumpgate_enttype) {
+ // validate jump gate
+ JumpGate *jumpgate = static_cast<JumpGate *>(entity);
+ jumpgate->validate();
+ }
+ }
+
+ 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);
+ player->set_view(0); // not docked
+
+ func_spectate(player, args);
+}
+
+void Game::player_disconnect(core::Player *player)
+{
+ player->remove_asset(player->control());
+}
+
+} // namespace game
+