/* 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 #include #include #include "auxiliary/functions.h" #include "core/gameserver.h" #include "core/parser.h" #include "core/range.h" #include "core/descriptions.h" #include "filesystem/filesystem.h" #include "filesystem/inifile.h" #include "base/game.h" #include "base/cargo.h" #include "base/faction.h" #include "base/navpoint.h" #include "base/jumppoint.h" #include "base/planet.h" #include "base/station.h" #include "base/racetrack.h" #include "base/ship.h" #include "base/star.h" #include "base/template.h" #include "math/mathlib.h" #include "sys/sys.h" namespace game { /* -- class Default ----------- ----------------------------------- */ // default player settings core::Zone *Default::zone = 0; core::Entity *Default::view = 0; ShipModel *Default::shipmodel = 0; long Default::credits = 0; void Default::clear() { zone = 0; view = 0; shipmodel = 0; credits = 0; } /* -- class Game static members ----------------------------------- */ // game variables core::Cvar *Game::g_impulsespeed = 0; core::Cvar *Game::g_jumppointrange = 0; core::Cvar *Game::g_devel = 0; core::Cvar *Game::g_damping = 0; core::Cvar *Game::g_deplete = 0; core::Module *factory() { return new Game(); } // a player joins the game void Game::func_join(core::Player *player, std::string const &args) { if (player->control()) return; player->set_credits(Default::credits); Ship *ship = new Ship(player, Default::shipmodel); ship->set_zone(player->zone()); player->set_control(ship); core::Entity *dock = ship->zone()->default_view(); if (dock) { ship->get_location().assign(dock->location() + (dock->axis().forward() *((ship->radius() + dock->radius())*2.0f))); ship->get_axis().assign(dock->axis()); ship->set_state(core::Entity::Docked); ship->reset(); 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(Default::shipmodel->name())); player->sound("game/buy-ship"); player->set_dirty(); } // 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(Default::zone); player->set_view(0); } // 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(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(player->control()); ship->func_impulse(); } // a player sends a docking request void Game::func_target_dock(core::Player *player, core::Entity *entity) { if (!player->control()) return; if (player->control() == entity) return; if (player->control()->zone() != entity->zone()) return; if ((entity->flags() & core::Entity::Dockable) == 0) return; if (player->control()->moduletype() != ship_enttype) return; if (!(entity->flags() & core::Entity::Dockable)) { return; } Ship * ship = static_cast(player->control()); // check distance float range = entity->radius() + ship->radius(); if (entity->moduletype() == planet_enttype) { range += planet_safe_distance; } core::Player *owner = (entity->type() == core::Entity::Controlable ? static_cast(entity)->owner() : 0 ); if (math::distance(entity->location(), ship->location()) > range) { if (owner) { player->send("^W" + owner->name() + "^W's " + entity->name() + " out of range"); } else { player->send("^W" + entity->name() + " out of range"); } return; } if ((player->control()->state() == core::Entity::Impulse) || (player->control()->state() == core::Entity::ImpulseInitiate)) { player->send("^WCan not dock at impulse speed"); return; } if (player->control()->state() != core::Entity::Normal) return; if (entity->moduletype() == jumpgate_enttype) { // jumpgates have their own docking function JumpGate *jumpgate = static_cast(entity); jumpgate->func_dock(ship); return; } else { ship->get_location().assign(entity->location()); ship->set_state(core::Entity::Docked); ship->reset(); if (player->control() == ship) { player->set_view(entity); if (owner) { player->send("^BDocking at " + owner->name() + "^B's " + entity->name()); } else { player->send("^BDocking at " + entity->name()); } } } } // a player sends a standard hail void Game::func_target_hail(core::Player *player, core::Entity *entity) { // TODO spam protection if (!entity) return; if (!player->control()) return; if (player->control()->zone() != entity->zone()) return; if (player->mute()) { player->send("^WYou have been muted"); return; } core::Player *target = (entity->type() == core::Entity::Controlable ? static_cast(entity)->owner() : 0 ); if (!target) return; if (math::distance(player->control()->location(), entity->location()) > core::range::fxdistance) { player->send("^WTarget " + target->name() + " ^Wout of range"); } player->send("^BYou hail " + target->name()); player->sound("com/hail"); target->send("^B" + player->name() + "^B hails you"); target->sound("com/hail"); } // a player sends a trade request void Game::func_target_trade(core::Player *player, core::Entity *entity) { if (!entity) return; if (!player->control()) return; core::Player *target = (entity->type() == core::Entity::Controlable ? static_cast(entity)->owner() : 0 ); if ((!target) || (target == player)) return; if (entity != target->control()) return; if (target->control()->state() != core::Entity::Normal) return; if (player->control()->state() != core::Entity::Normal) return; player->send("^WTrade requests are not implemented at this time"); } // cheats void Game::func_give(core::Player *player, const std::string &args) { if (!Game::g_devel->value()) { player->send("Cheats disabled"); return; } std::istringstream is(args); std::string str; is >> str; aux::to_label(str); if (str.compare("ship") == 0) { std::string labelstr; if (!player->control()) { player->send("^WYou need to join the game first!"); return; } ShipModel *shipmodel = 0; if (!(is >> labelstr)) { player->send("Usage: give ship [string]"); } else { shipmodel = ShipModel::find(labelstr); } if (!shipmodel) { // enable rcon buffering sys::ConsoleInterface::instance()->set_rcon(true); ShipModel::list(); // disable rcon buffering sys::ConsoleInterface::instance()->set_rcon(false); while (sys::ConsoleInterface::instance()->rconbuf().size()) { player->send((*sys::ConsoleInterface::instance()->rconbuf().begin())); sys::ConsoleInterface::instance()->rconbuf().pop_front(); } player->send("Unkown ship type '" + labelstr + "'"); return; } // check if there's enough space available to transfer inventory if (shipmodel->maxcargo() < player->control()->inventory()->capacity_used()) { player->send("^WNot enough cargo space to transfer inventory!"); return; } Ship * ship = new Ship(player, shipmodel); core::Entity *view = player->view(); if (view && (view == player->control())) { view = ship; } // transfer inventory for (core::Inventory::Items::iterator it = player->control()->inventory()->items().begin(); it != player->control()->inventory()->items().end(); it++) { ship->inventory()->add(new core::Item(*(*it))); } ship->inventory()->set_dirty(); // FIME move this into a method in the Ship class ship->set_zone(player->control()->zone()); ship->get_location().assign(player->control()->location()); ship->set_state(player->control()->state()); ship->get_axis().assign(player->control()->axis()); ship->set_thrust(player->control()->thrust()); ship->reset(); //target_thrust is protected //ship->target_thrust = player->control()->target_thrust()); player->remove_asset(player->control()); player->set_control(ship); player->set_view(view); player->sound("game/buy-ship"); } else if (str.compare("credits") == 0) { long credits; if (!(is >> credits)) { player->send("Usage: give credits [int]"); return; } if (player->credits() + credits > 0 ) { player->set_credits(player->credits() + credits); } else { player->set_credits(0); } player->set_dirty(); player->sound("game/buy"); } else if (str.compare("cargo") == 0) { std::string labelstr; if (!player->control()) { player->send("^WNeed a ship to load cargo!"); } Cargo *cargo = 0; if (!(is >> labelstr)) { player->send("Usage: give cargo [string] [int]"); } else { cargo = Cargo::find(labelstr); } if (!cargo) { // enable rcon buffering sys::ConsoleInterface::instance()->set_rcon(true); Cargo::list(); // disable rcon buffering sys::ConsoleInterface::instance()->set_rcon(false); while (sys::ConsoleInterface::instance()->rconbuf().size()) { player->send((*sys::ConsoleInterface::instance()->rconbuf().begin())); sys::ConsoleInterface::instance()->rconbuf().pop_front(); } player->send("Unkown cargo type '" + labelstr + "'"); return; } else { int amount = 0; if (!(is >> amount)) { amount = -1; } else { if (!amount) return; } const int max = (int)floorf(player->control()->inventory()->capacity_available() / cargo->volume()); if (amount < 0 ) { amount = max; } if ((amount == 0) || (amount > max)) { player->send("^WNot enough cargo space available!"); return; } core::Item *item = player->control()->inventory()->find(cargo); if (!item) { item = new core::Item(cargo); player->control()->inventory()->add(item); } else { assert(item->info() == cargo); } item->inc_amount(amount); player->control()->inventory()->set_dirty(); player->sound("game/buy"); } } else { player->send("Usage: give cargo [string] [int]"); player->send(" give credits [int]"); player->send(" give ship [string]"); return; } } void Game::func_specs(core::Player *player, const std::string &args) { if (!Game::g_devel->value()) { player->send("Cheats disabled"); return; } if (!player->control()) { player->send("^WYou need to join the game first!"); return; } if (player->control()->moduletype() != ship_enttype) return; Ship * ship = static_cast(player->control()); std::istringstream is(args); std::string str; if (!(is >> str)) { // enable rcon buffering sys::ConsoleInterface::instance()->set_rcon(true); con_print << "Current ship specifications for " + ship->name() << std::endl; con_print << "cargo = " << ship->inventory()->capacity() << std::endl; con_print << "mass = " << ship->shipmodel()->mass() << std::endl; con_print << "thrust = " << ship->thrust_force() << std::endl; con_print << "impulse = " << ship->impulse_force() << std::endl; con_print << "strafe = " << ship->strafe_force() << std::endl; con_print << "turn = " << ship->turn_force() << std::endl; con_print << "roll = " << ship->roll_force() << std::endl; // disable rcon buffering sys::ConsoleInterface::instance()->set_rcon(false); while (sys::ConsoleInterface::instance()->rconbuf().size()) { player->send((*sys::ConsoleInterface::instance()->rconbuf().begin())); sys::ConsoleInterface::instance()->rconbuf().pop_front(); } } else { float value; if (!(is >> value)) return; aux::to_label(str); std::stringstream msgstr; if (str.compare("thrust") == 0) { ship->set_thrust_force(value); msgstr << "Ship thrust force set to " << value; } else if (str.compare("impulse") == 0) { ship->set_impulse_force(value); msgstr << "Ship impulse force set to " << value; } else if (str.compare("strafe") == 0) { ship->set_strafe_force(value) ; msgstr << "Ship strafe force set to " << value; } else if (str.compare("turn") == 0) { ship->set_turn_force(value); msgstr << "Ship turn force set to " << value; } else if (str.compare("roll") == 0) { ship->set_roll_force(value); msgstr << "Ship roll force set to " << value; } else { msgstr << "^WUnknown ship specification '" << str << "'"; } player->send(msgstr.str()); } } // sell request from a player void Game::func_sell(core::Player *player, const std::string &args) { if (!player->control()) { player->send("^WYou need to join the game first!"); return; } std::istringstream is(args); std::string typestr; std::string labelstr; if (!(is >> typestr)) { player->send("Usage: sell [string] [string] [int] sell an item: specify type, label and amount"); return; } else { aux::to_label(typestr); } if (!(is >> labelstr)) { player->send("Usage: sell [string] [string] [int] sell an item: specify type, label and amount"); return; } else { aux::to_label(labelstr); } int amount = 0; if (!(is >> amount)) amount = 0; if (typestr.compare("cargo") == 0) { Cargo *cargo = Cargo::find(labelstr); if (cargo) { cargo->sell(player->control(), player->view(), amount); } else { player->send("Unkown cargo type '" + labelstr + "'"); } } else { player->send("Unkown item type '" + typestr + "'"); } return; } // buy request from a player void Game::func_buy(core::Player *player, const std::string &args) { if (!player->control()) { player->send("^WYou need to join the game first!"); return; } std::istringstream is(args); std::string typestr; std::string labelstr; if (!(is >> typestr)) { player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); return; } else { aux::to_label(typestr); } if (!(is >> labelstr)) { player->send("Usage: buy [string] [string] [int] buy an item: specify type, label and amount"); return; } else { aux::to_label(labelstr); } int amount = 0; if (!(is >> amount)) amount = 0; if (typestr.compare("ship") == 0) { ShipModel *shipmodel = ShipModel::find(labelstr); if (shipmodel) { shipmodel->buy(player->control(), player->view()); } else { player->send("Unkown ship type '" + labelstr + "'"); } } else if (typestr.compare("cargo") == 0) { Cargo *cargo = Cargo::find(labelstr); if (cargo) { cargo->buy(player->control(), player->view(), amount); } else { player->send("Unkown cargo type '" + labelstr + "'"); } } else { player->send("Unkown item type '" + typestr + "'"); } return; } // eject cargo request void Game::func_eject(core::Player *player, const std::string &args) { if (!player->control()) { player->send("^WYou need to join the game first!"); return; } std::istringstream is(args); std::string typestr; std::string labelstr; if (!(is >> typestr)) { player->send("Usage: eject [string] [string] [int] eject an item: specify type, label and amount"); return; } else { aux::to_label(typestr); } if (!(is >> labelstr)) { player->send("Usage: eject [string] [string] [int] eject an item: specify type, label and amount"); return; } else { aux::to_label(labelstr); } int amount = 0; if (!(is >> amount)) amount = 0; if (typestr.compare("cargo") == 0) { Cargo *cargo = Cargo::find(labelstr); if (cargo) { cargo->eject(player->control(), amount); } else { player->send("Unkown cargo type '" + labelstr + "'"); } } else { player->send("Unkown item type '" + typestr + "'"); } } // beam in nearby cargo pods void Game::func_beam(core::Player *player, const std::string &args) { const float beam_range_squared = 5.0f * 5.0f; if (!player->control()) return; if (player->control()->state() != core::Entity::Normal) return; core::Zone *zone = player->control()->zone(); core::Inventory *inventory = player->control()->inventory(); // entity iterator for (core::Zone::Content::iterator eit = zone->content().begin(); eit != zone->content().end(); eit++) { // if the entity is a cargo pod and within beaming range if (((*eit)->moduletype() == cargopod_enttype) && (math::distancesquared(player->control()->location(), (*eit)->location()) <= beam_range_squared)) { core::Inventory *loot = (*eit)->inventory(); if (!inventory || !loot) continue; // item iterator int loot_left = 0; for (core::Inventory::Items::iterator iit = loot->items().begin(); iit != loot->items().end(); iit++) { core::Item *item = (*iit); int negotiated_amount = item->amount(); assert(item->info()); if (inventory->capacity_available() < negotiated_amount * item->info()->volume()) { negotiated_amount = (int) floorf( inventory->capacity_available() / item->info()->volume()); } if (negotiated_amount > 0) { core::Item *iteminv = inventory->find(item->info()); if (!iteminv) { iteminv = new core::Item(item->info()); inventory->add(iteminv); } item->dec_amount(negotiated_amount); iteminv->inc_amount(negotiated_amount); // this will recalculate inventory capacity inventory->set_dirty(); loot->set_dirty(); std::stringstream msgstr; msgstr << "^BBeamed in " << negotiated_amount << " " << aux::plural("unit", negotiated_amount) << " of " << item->info()->name(); player->send(msgstr.str()); player->sound("game/beam"); } loot_left += item->amount(); } // if there's no loot left, the cargo pod will be destroyed if (!loot_left) { (*eit)->die(); } } } } // launch request void Game::func_launch(core::Player *player, std::string const &args) { if (!player->control()) { player->send("^WYou need to join the game first!"); return; } if (!player->view()) return; if (player->control()->state() != core::Entity::Docked) return; assert(player->view()->zone() == player->control()->zone()); core::Entity *dock = player->view(); if (dock->moduletype() == ship_enttype) { switch(static_cast(dock)->state()) { case core::Entity::Normal: case core::Entity::Docked: break; case core::Entity::NoPower: player->send("^BCan not launch while carrier has no power!"); return; break; case core::Entity::ImpulseInitiate: case core::Entity::Impulse: player->send("^BCan not launch while carrier is using impulse engines!"); return; break; case core::Entity::JumpInitiate: case core::Entity::Jump: player->send("^BCan not launch while carrier is jumping through hyperspace!"); return; break; default: player->send("^BCan not launch from carrier!"); return; break; } } assert(player->control()->moduletype() == ship_enttype); Ship *ship = static_cast(player->control()); if (dock->type() == core::Entity::Globe) ship->get_location().assign(dock->location() + (dock->axis().forward() * (planet_safe_distance + ship->radius() + dock->radius()))); else ship->get_location().assign(dock->location() + (dock->axis().forward() * (ship->radius() + dock->radius()))); ship->get_axis().assign(dock->axis()); ship->set_state(core::Entity::Normal); ship->reset(); player->set_view(0); player->send("^BLaunching from " + dock->name()); } // respawn void Game::func_respawn(core::Player *player, std::string const &args) { if (!player->control()) { func_join(player, args); return; } if (!(player->view() == player->control())) return; if (player->control()->state() != core::Entity::Destroyed) return; Ship *ship = static_cast(player->control()); core::Entity *dock = player->control()->zone()->default_view(); if (dock) { ship->get_location().assign(dock->location()); ship->get_axis().assign(dock->axis()); ship->set_state(core::Entity::Docked); player->set_view(dock); player->send("^BRespawning at " + dock->name()); } else { ship->get_location().clear(); ship->get_axis().clear(); ship->set_state(core::Entity::Jump); player->set_view(0); player->send("^BRespawning"); } ship->set_zone(Default::zone); } // 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 = player->control()->zone()->search_entity(args); Ship *ship = static_cast(player->control()); if (dock) { if (dock->type() == core::Entity::Globe) ship->get_location().assign(dock->location() + (dock->axis().forward() *(planet_safe_distance + ship->radius() + dock->radius()))); else ship->get_location().assign(dock->location() + (dock->axis().forward() *(ship->radius() + dock->radius()))); ship->get_axis().assign(dock->axis()); ship->get_axis().change_direction(180.0f); ship->set_state(core::Entity::Normal); ship->reset(); player->set_view(0); player->send("Going to " + dock->name()); } else { player->send("Entity '" + args + "' not found"); } } /* -- class Game -------------------------------------------------- */ Game::Game() : core::Module("Project::OSiRiON", true) { // clear defaults Default::clear(); // read factions.ini if (!Faction::init()) { abort(); return; } // read templates.ini if (!Template::init()) { abort(); return; } // read cargo.ini if (!Cargo::init()) { abort(); return; } // read ships.ini if (!ShipModel::init()) { abort(); return; } // read world.ini and the zones it refers to if (!load_world()) { abort(); return; } // read game.ini if (!load_settings()) { abort(); return; } // add engine functions core::Func *func = 0; func = core::Func::add("join", Game::func_join); func->set_info("join the game"); 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("[string] [string] [int] buy an item: specify type, label and amount"); func = core::Func::add("sell", Game::func_sell); func->set_info("[string] [string] [int] sell an item: specify type, label and amount"); func = core::Func::add("eject", Game::func_eject); func->set_info("[string] [string] [int] eject an item from inventory: specify type, label and amount"); func = core::Func::add("beam", Game::func_beam); func->set_info("beam nearby cargo pods in"); func = core::Func::add("give", Game::func_give); func->set_info("cheat functions"); func = core::Func::add("specs", Game::func_specs); func->set_info("change ship specifications"); 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("respawn", Game::func_respawn); func->set_info("respawn when your ship has been destroyed"); 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_target_dock); func->set_info("send a docking request to target"); func = core::Func::add("@hail", Game::func_target_hail); func->set_info("send a standard hail to target"); func = core::Func::add("@trade", Game::func_target_trade); func->set_info("send a trade request to target"); // add engine variables g_impulsespeed = core::Cvar::get("g_impulsespeed", "1500", core::Cvar::Game | core::Cvar::Archive); g_impulsespeed->set_info("[float] speed of the impulse drive"); 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::Game | core::Cvar::Archive); g_devel->set_info("[bool] enable or disable developer mode"); g_damping = core::Cvar::get("g_damping", "0.1", core::Cvar::Game | core::Cvar::Archive); g_damping->set_info("[float] physics damping factor (0-1)"); g_deplete = core::Cvar::get("g_deplete", "60", core::Cvar::Game | core::Cvar::Archive); g_deplete->set_info("[int] number of seconds to deplete 1 unit of cargo from inventories"); } Game::~Game() { g_impulsespeed = 0; g_jumppointrange = 0; g_devel = 0; g_damping = 0; g_deplete = 0; // clear defaults Default::clear(); // clear Factions Faction::clear(); } bool Game::load_world() { std::string inifilename("ini/world"); filesystem::IniFile inifile; inifile.open(inifilename); if (!inifile.is_open()) { con_error << "Could not open " << inifile.name() << std::endl; return false; } con_print << "^BLoading world..." << std::endl; Faction *faction = 0; core::Zone *zone = 0; std::string label; math::Color color; while (inifile.getline()) { if (inifile.got_section()) { zone = 0; faction = 0; if (inifile.got_section("world")) { continue; } else { inifile.unknown_section(); } } else if (inifile.got_key()) { if (inifile.in_section("world")) { if (inifile.got_key_string("zone", label)) { aux::to_label(label); zone = new core::Zone(label); core::Zone::add(zone); } else { inifile.unkown_key(); } } } } inifile.close(); if (!core::Zone::registry().size()) { con_error << "No zones found!" << std::endl; return false; } con_debug << " " << inifile.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; } } return true; } bool Game::load_zone(core::Zone *zone) { using math::Vector3f; using math::Color; std::string inifilename("ini/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; core::Entity *entity = 0; core::Inventory *inventory = 0; core::Item *item = 0; Station *station = 0; Planet *planet = 0; Star *star = 0; NavPoint *navpoint = 0; JumpPoint *jumppoint = 0; RaceTrack *racetrack = 0; CheckPoint *checkpoint = 0; bool b; long l; std::string strval; while (zoneini.getline()) { if (zoneini.got_section()) { if (zoneini.got_section("zone")) { continue; } else if (zoneini.got_section("star")) { star = new Star(); entity = star; star->set_zone(zone); count ++; } else if (zoneini.got_section("navpoint")) { navpoint = new NavPoint(); entity = navpoint; navpoint->set_zone(zone); count ++; } else if (zoneini.got_section("jumpgate")) { jumppoint = new JumpGate(); entity = jumppoint; jumppoint->set_zone(zone); count ++; } else if (zoneini.got_section("jumppoint")) { jumppoint = new JumpPoint(); entity = jumppoint; jumppoint->set_zone(zone); count ++; } else if (zoneini.got_section("racetrack")) { racetrack = new RaceTrack(); entity = racetrack; racetrack->set_zone(zone); } else if (zoneini.got_section("checkpoint")) { checkpoint = new CheckPoint(racetrack); entity = checkpoint; if (!racetrack) { zoneini.unknown_error("checkpoint without racetrack"); } } else if (zoneini.got_section("planet")) { planet = new Planet(); entity = planet; planet->set_zone(zone); count ++; } else if (zoneini.got_section("station")) { station = new Station(); entity = station; station->set_zone(zone); count ++; } else if (zoneini.got_section("entity")) { entity = new core::Entity(); entity->set_zone(zone); count ++; } else if (zoneini.got_section("cargo")) { // new cargo trading definition for the current base item = 0; inventory = 0; if (!entity) { zoneini.unknown_error("cargo definition without entity"); } else if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype)) { zoneini.unknown_error("cargo definition for invalid entity type"); } else { inventory = entity->inventory(); if (!inventory) { inventory = new core::Inventory(); entity->set_inventory(inventory); } } } else if (zoneini.got_section("ship")) { // new ship trading definition for the current base item = 0; inventory = 0; if (!entity) { zoneini.unknown_error("ship definition without entity"); } else if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype)) { zoneini.unknown_error("ship definition for invalid entity type"); } else { inventory = entity->inventory(); if (!inventory) { inventory = new core::Inventory(); entity->set_inventory(inventory); } } } 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 { 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", strval)) { jumppoint->set_targetlabel(strval); continue; } else { zoneini.unkown_key(); } } else if (zoneini.in_section("jumpgate")) { if (core::Parser::got_entity_key(zoneini, jumppoint)) { continue; } else if (zoneini.got_key_label("faction", strval)) { Faction *faction = Faction::find(strval); if (!faction) { zoneini.unknown_error("unkown faction '" + strval + "'"); } else { faction->apply(jumppoint); } } else if (zoneini.got_key_label("template", strval)) { Template *entitytemplate = Template::find(strval); if (!entitytemplate) { zoneini.unknown_error("unkown template '" + strval + "'"); } else { entitytemplate->apply(jumppoint); } } 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); } else { planet->unset_flag(core::Entity::Dockable); } } else if (zoneini.got_key_bool("default", b)) { if (b) { zone->set_default_view(planet); } continue; } else if (zoneini.got_key_label("faction", strval)) { Faction *faction = Faction::find(strval); if (!faction) { zoneini.unknown_error("unkown faction '" + strval + "'"); } else { faction->apply(planet); } } else { zoneini.unkown_key(); } } else if (zoneini.in_section("station")) { if (core::Parser::got_entity_key(zoneini, station)) { continue; } else if (zoneini.got_key_bool("default", b)) { if (b) { zone->set_default_view(station); } } else if (zoneini.got_key_label("faction", strval)) { Faction *faction = Faction::find(strval); if (!faction) { zoneini.unknown_error("unkown faction '" + strval + "'"); } else { faction->apply(station); } } else if (zoneini.got_key_label("template", strval)) { Template *entitytemplate = Template::find(strval); if (!entitytemplate) { zoneini.unknown_error("unkown template '" + strval + "'"); } else { entitytemplate->apply(station); } } 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_label("faction", strval)) { Faction *faction = Faction::find(strval); if (!faction) { zoneini.unknown_error("unkown faction '" + strval + "'"); } else { entity->set_color(faction->color()); entity->set_color_second(faction->color_second()); } } else if (zoneini.got_key_label("template", strval)) { Template *entitytemplate = Template::find(strval); if (!entitytemplate) { zoneini.unknown_error("unkown template '" + strval + "'"); } else { entitytemplate->apply(entity); } } else { zoneini.unkown_key(); } } else if (zoneini.in_section("cargo")) { // cargo definition for a station or planet if (!entity || !inventory) { continue; } if (zoneini.got_key_label("label", strval)) { Cargo *cargo = Cargo::find(strval); if (cargo) { item = inventory->find(cargo); if (!item) { item = new core::Item(cargo); item->set_amount(-1); item->set_price(cargo->price()); inventory->add(item); } } else { zoneini.unknown_error("unkown cargo type '" + strval + "'"); } } else if (zoneini.got_key_long("price", l)) { if (item) { item->set_price(l); } } else if (zoneini.got_key_long("amount", l)) { if (item) { item->set_amount(l); } } else { zoneini.unkown_key(); } } else if (zoneini.in_section("ship")) { // ship definition for a station or planet if (!entity || !inventory) { continue; } if (zoneini.got_key_label("label", strval)) { ShipModel *shipmodel= ShipModel::find(strval); if (shipmodel) { item = inventory->find(shipmodel); if (!item) { item = new core::Item(shipmodel); item->set_amount(-1); item->set_price(shipmodel->price()); inventory->add(item); } } else { zoneini.unknown_error("unkown ship type '" + strval + "'"); } } else if (zoneini.got_key_long("price", l)) { if (item) { item->set_price(l); } } 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_print << "^BValidating zone " << zone->label() << "..." << 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(entity); jumppoint->validate(); } else if (entity->entity_moduletypeid == jumpgate_enttype) { // validate jump gate JumpGate *jumpgate = static_cast(entity); jumpgate->validate(); } else { if (entity->flag_is_set(core::Entity::Dockable)) { generate_entity_menus(entity); } } // initialize physics on planets and entities with a model if ((entity->entity_moduletypeid == planet_enttype) || (entity->model())) { entity->reset(); } } return true; } bool Game::generate_entity_menus(core::Entity *entity) { using core::MenuDescription; using core::ButtonDescription; if ((entity->moduletype() != planet_enttype) && (entity->moduletype() != station_enttype)) { //con_warn << "Can not generate menus for entity '" << entity->label() << "'" << std::endl; // not dockable return false; } MenuDescription *menu_dealer = 0; ButtonDescription *button = 0; // dockable entity // add main menu MenuDescription *menu_main = new MenuDescription(); menu_main->set_label("main"); menu_main->set_text("Launch area"); entity->add_menu(menu_main); // add launch button button = new ButtonDescription(); button->set_text("Launch"); button->set_command("launch", ButtonDescription::CommandGame); button->set_alignment(ButtonDescription::Center); menu_main->add_button(button); // add trade menus if (entity->inventory()) { entity->set_flag(core::Entity::KeepAlive); size_t nbcargo = 0; size_t nbships = 0; for (core::Inventory::Items::const_iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); it++) { core::Item *item = (*it); if (item->info()->type() == Cargo::infotype()) { nbcargo++; } else if (item->info()->type() == ShipModel::infotype()) { if (!menu_dealer) { menu_dealer = new MenuDescription(); menu_dealer->set_label("ships"); menu_dealer->set_text("Ships"); } button = new ButtonDescription(); button->set_text("buy " + item->info()->name()); std::ostringstream str(""); str << "buy " << item->info()->id(); button->set_command(str.str() , ButtonDescription::CommandMenu); button->set_info(item->info()); button->set_alignment(ButtonDescription::Left); menu_dealer->add_button(button); nbships++; } } if (nbcargo > 0) { con_debug << " " << entity->label() << " " << nbcargo << " cargo " << aux::plural("type", nbcargo) << std::endl; button = new ButtonDescription(); button->set_text("Trade"); button->set_command("trade cargo", ButtonDescription::CommandMenu); button->set_alignment(ButtonDescription::Center); menu_main->add_button(button); } if (nbships > 0) { con_debug << " " << entity->label() << " " << nbships << " ship " << aux::plural("type", nbships) << std::endl; button = new ButtonDescription(); button->set_text("Return"); button->set_command("main", ButtonDescription::CommandMenu); button->set_alignment(ButtonDescription::Center); menu_dealer->add_button(button); entity->add_menu(menu_dealer); button = new ButtonDescription(); button->set_text("Ships"); button->set_command("ships", ButtonDescription::CommandMenu); button->set_alignment(ButtonDescription::Center); menu_main->add_button(button); } } return true; } // load game defaults settings bool Game::load_settings() { filesystem::IniFile inifile; inifile.open("ini/game"); if (!inifile.is_open()) { con_error << "Could not open " << inifile.name() << "!" << std::endl; return false; } long l; std::string str; while (inifile.getline()) { if (inifile.got_section()) { if (inifile.got_section("player")) { continue; } else if (inifile.got_section("cargo")) { continue; } else { inifile.unknown_section(); } } else if (inifile.got_key()) { if (inifile.in_section("player")) { if (inifile.got_key_long("credits", l)) { Default::credits = l; } else if (inifile.got_key_string("zone", str)) { aux::to_label(str); Default::zone = core::Zone::find(str); } else if (inifile.got_key_string("ship", str)) { aux::to_label(str); Default::shipmodel = ShipModel::find(str); } else { inifile.unkown_key(); } } } } inifile.close(); if (!Default::zone) { con_error << "No default zone found!\n"; return false; } if (!Default::zone->default_view()) { con_error << "Zone '" << Default::zone->label() << "' has no default view!\n"; return false; } Default::view = Default::zone->default_view(); 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