/* 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 #include #include #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/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 { /* -- class Base static members ----------------------------------- */ // game variables core::Cvar *Base::g_impulsespeed = 0; core::Cvar *Base::g_impulseacceleration = 0; core::Cvar *Base::g_strafespeed = 0; core::Cvar *Base::g_jumppointrange = 0; core::Cvar *Base::g_devel = 0; core::Zone *Base::default_zone = 0; ShipModel *Base::default_shipmodel = 0; // list the ship model registry void Base::func_list_ship(std::string const &args) { ShipModel::list(); } // a player joins the game void Base::func_join(core::Player *player, std::string const &args) { if (player->control()) return; Ship *ship = new Ship(player, Base::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); } player->sound("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 Base::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(Base::default_zone); player->set_view(0); } // a player buys a ship void Base::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()); } 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); } core::server()->broadcast("^B" + player->name() + " ^Bpurchased " + aux::article(shipmodel->name())); player->sound("game/buy-ship"); } else { player->send("Usage: buy [^B" + helpstr + "^N]"); } } // a player sends standard hails void Base::func_hail(core::Player *player, std::string const &args) { if (player->mute()) { player->send("^BYou 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("^BPlayer " + target + "^B not found."); return; } player->send("^BYou hail " + targetplayer->name() + "^B."); player->sound("com/hail"); targetplayer->send("^B" + player->name() + "^B hails you!"); targetplayer->send("com/hail"); } // a player actives the hyperspace jump drive on his ship void Base::func_jump(core::Player *player, std::string const &args) { if (!player->control()) return; if (!player->control()->moduletype() == ship_enttype) return; Ship * ship = static_cast(player->control()); ship->jump(args); } // a player actives the kinetic impulse drive on his ship void Base::func_impulse(core::Player *player, std::string const &args) { if (!player->control()) return; if (!player->control()->moduletype() == ship_enttype) return; Ship * ship = static_cast(player->control()); ship->impulse(); } // a player sends a docking request void Base::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("^B" + entity->name() + " is out of range!"); return; } player->control()->location().assign(entity->location()); player->control()->set_eventstate(core::Entity::Docked); player->set_view(entity); player->send("^BDocking at " + entity->name() + "^B..."); } // launch request void Base::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); } // instantaniously goto a specified entity within the zone void Base::func_goto(core::Player *player, const std::string &args) { if (!args.size()) return; if (!g_devel->value()) return; if (!player->control()) return; 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 ++) { core::Entity *dock = (*it); std::string str(dock->label()); aux::to_label(str); if (str.find(label) != std::string::npos) { 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); return; } } } /* -- class Base -------------------------------------------------- */ Base::Base() : core::Module("base", "Project::OSiRiON", true) { default_shipmodel = 0; default_zone = 0; } Base::~Base() { } void Base::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", Base::func_list_ship); func->set_info("list ship statistics"); func = core::Func::add("join", Base::func_join); func->set_info("join the game"); func = core::Func::add("hail", Base::func_hail); func->set_info("send a standard hail"); func = core::Func::add("spectate", Base::func_spectate); func->set_info("leave the game and spectate"); func = core::Func::add("buy", Base::func_buy); func->set_info("buy a ship"); func = core::Func::add("jump", Base::func_jump); func->set_info("[string] activate or deactivate hyperspace jump drive"); func = core::Func::add("impulse", Base::func_impulse); func->set_info("activate are deactive kinetic impulse drive"); func = core::Func::add("launch", Base::func_launch); func->set_info("launch to space when docked"); func = core::Func::add("goto", Base::func_goto); func->set_info("[string] goto to an entity within the zone"); func = core::Func::add("@dock", Base::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 Base::shutdown() { g_impulsespeed = 0; // game functions are automaticly removed // remove engine core functions core::Func::remove("list_ship"); ShipModel::clear(); } 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; } 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 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; } 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("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")) { if (core::Parser::got_entity_key(zoneini, jumppoint)) { continue; } else if (zoneini.got_key_string("target", jumppoint->jumppoint_targetlabel)) { 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); 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 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(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(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); player->set_view(0); // not docked func_spectate(player, args); } void Base::player_disconnect(core::Player *player) { player->remove_asset(player->control()); } } // namespace game