/* 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 #include #include "base/game.h" #include "base/racetrack.h" #include "base/ship.h" #include "core/gameserver.h" namespace game { /* ---- class CheckPoint ------------------------------------------- */ CheckPoint::CheckPoint(RaceTrack *parent) { set_state(core::Entity::NoPower); parent_track = parent; if (parent) { get_color().assign(parent->color()); get_color_second().assign(parent->color_second()); set_zone(parent->zone()); parent->add_checkpoint(this); } else { die(); } } CheckPoint::~CheckPoint() { } /* ---- class RaceTrack -------------------------------------------- */ RaceTrack::RaceTrack() : EntityDynamic() { track_player = 0; track_racestart = 0; track_checkpointtime = 0; track_record = 0; entity_moduletypeid = race_enttype; set_state(core::Entity::NoPower); set_flag(core::Entity::Dockable); } RaceTrack::~RaceTrack() { track_checkpoints.clear(); } void RaceTrack::add_checkpoint(CheckPoint *checkpoint) { track_checkpoints.push_back(checkpoint); } void RaceTrack::reset_race() { 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_state(core::Entity::NoPower); } set_state(core::Entity::NoPower); } void RaceTrack::func_dock(core::Entity *entity) { if (entity->moduletype() != ship_enttype) return; Ship * ship = static_cast(entity); if (math::distance(location(), ship->location()) > radius()) { ship->owner()->send("Target out of range"); return; } if (track_player) { ship->owner()->send("Race in use"); return; } track_player = ship->owner(); track_racestart = core::server()->time(); set_state(core::Entity::Normal); for (CheckPoints::iterator cpit = track_checkpoints.begin(); cpit != track_checkpoints.end(); ++cpit) { set_state(core::Entity::Normal); } entity_timer = 5.0f; std::string message("^B" + track_player->name() + " ^Bactivated the race! Race starts in 5..."); core::server()->broadcast(zone(), message); track_player->set_mission_target(this); return; } void RaceTrack::frame(const unsigned long elapsed) { if (!track_checkpoints.size()) return; if (!track_player) 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_race(); return; } if (!player->control() || (player->control()->zone() != zone())) { reset_race(); return; } if (entity_timer) { if (math::distance(location(), player->control()->location()) > radius()) { std::string message("^BNo cheating!"); core::server()->broadcast(zone(), message); reset_race(); return; } if (track_racestart + 1.0f <= core::server()->time()) { entity_timer -= 1.0f; set_dirty(); if (entity_timer > 0) { std::stringstream msgstr; msgstr << "^B" << entity_timer << "..."; core::server()->broadcast(zone(), msgstr.str()); track_racestart = core::server()->time(); } else { for (CheckPoints::iterator cpit = track_checkpoints.begin(); cpit != track_checkpoints.end(); ++cpit) { (*cpit)->set_state(core::Entity::NoPower); } std::string message("^BGo!"); core::server()->broadcast(zone(), message); track_racestart = core::server()->time(); track_checkpointtime = core::server()->time() + 15.0f; track_checkpoint = track_checkpoints.begin(); (*track_checkpoint)->set_state(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(zone(), message); reset_race(); return; } if (math::distance(track_player->control()->location(), (*track_checkpoint)->location()) < radius()) { CheckPoints::iterator next_checkpoint = track_checkpoint; next_checkpoint++; if (next_checkpoint != track_checkpoints.end()) { std::string message("^BCheckpoint!"); core::server()->broadcast(zone(), message); track_checkpointtime = core::server()->time() + 15.0f; (*track_checkpoint)->set_state(core::Entity::NoPower); track_checkpoint++; (*track_checkpoint)->set_state(core::Entity::Normal); track_player->set_mission_target((*track_checkpoint)); } else { float player_time = core::server()->time() - track_racestart; const bool new_record = ((track_record > 0.0f) && (player_time > 0.0f) && (player_time < track_record)); std::stringstream msgstr; msgstr << "^B" << player->name() << " ^Bcompleted the race in " << player_time << " seconds"; if (new_record) { msgstr << ", a new record!"; } else { msgstr << "."; } core::server()->broadcast(zone(), msgstr.str()); // prize money unsigned long the_prize = (unsigned long) floorf(10000.0f / (core::server()->time() - track_racestart)); if (track_record && new_record) { the_prize += 1000.0f * (track_record - player_time); } player->add_credits(the_prize); msgstr.clear(); msgstr.str(""); msgstr << "You receive " << the_prize << " credits."; player->send(msgstr.str()); player->sound("game/buy"); if (new_record) track_record = player_time; reset_race(); } } } } }