std::string Planet::CardinalSuffix() const { std::string retval = ""; // Planets are grouped into asteroids, and non-asteroids // Asteroids receive a localized prefix if (Type() == PT_ASTEROIDS) retval.append(UserString("NEW_ASTEROIDS_SUFFIX") + " "); TemporaryPtr<System> cur_system = GetSystem(SystemID()); if (cur_system) { if (cur_system->OrbitOfPlanet(ID()) < 0) { ErrorLogger() << "Planet " << Name() << "(" << ID() << ") " << "has no current orbit"; retval.append(RomanNumber(1)); return retval; } int num_planets_lteq = 0; // number of planets at this orbit or smaller int num_planets_total = 0; bool prior_current_planet = true; const std::vector<int>& sys_orbits = cur_system->PlanetIDsByOrbit(); for (std::vector<int>::const_iterator it = sys_orbits.begin(); it != sys_orbits.end(); ++it) { if (*it == INVALID_OBJECT_ID) continue; PlanetType other_planet_type = GetPlanet(*it)->Type(); if (other_planet_type == INVALID_PLANET_TYPE) continue; if (Type() != PT_ASTEROIDS) { if (other_planet_type != PT_ASTEROIDS) { ++num_planets_total; if (prior_current_planet) ++num_planets_lteq; } } else { if (other_planet_type == PT_ASTEROIDS) { ++num_planets_total; if (prior_current_planet) ++num_planets_lteq; } } if (*it == ID()) prior_current_planet =false; } // For asteroids: If no other asteroids in this system, suffix does not receive a number if (Type() != PT_ASTEROIDS || (Type() == PT_ASTEROIDS && num_planets_total > 1)) retval.append(RomanNumber(num_planets_lteq)); } else { ErrorLogger() << "Planet " << Name() << "(" << ID() << ") not assigned to a system"; } return retval; }
void Planet::AddBuilding(int building_id) { if (this->Contains(building_id)) { Logger().debugStream() << "Planet::AddBuilding this planet " << this->Name() << " already contained building " << building_id; return; } //Logger().debugStream() << "Planet::AddBuilding " << this->Name() << " adding building: " << building_id; if (Building* building = GetObject<Building>(building_id)) { if (System* system = GetObject<System>(this->SystemID())) { system->Insert(building); } else { Logger().errorStream() << "... planet is not located in a system?!?!"; building->MoveTo(X(), Y()); building->SetSystem(SystemID()); } building->SetPlanetID(ID()); m_buildings.insert(building_id); } else { Logger().errorStream() << "Planet::AddBuilding() : Attempted to add an id of a non-building object to a planet."; } StateChangedSignal(); }
QString ConditionalAccessDescriptor::toString() const { return QString("Conditional Access: sid(0x%1) pid(0x%2) data_size(%3)") .arg(SystemID(),0,16).arg(PID(),0,16).arg(DataSize()); }
std::string Planet::CardinalSuffix() const { std::string retval = ""; // Early return for invalid ID if (ID() == INVALID_OBJECT_ID) { WarnLogger() << "Planet " << Name() << " has invalid ID"; return retval; } auto cur_system = GetSystem(SystemID()); // Early return for no system if (!cur_system) { ErrorLogger() << "Planet " << Name() << "(" << ID() << ") not assigned to a system"; return retval; } // Early return for unknown orbit if (cur_system->OrbitOfPlanet(ID()) < 0) { WarnLogger() << "Planet " << Name() << "(" << ID() << ") " << "has no current orbit"; retval.append(RomanNumber(1)); return retval; } int num_planets_lteq = 0; // number of planets at this orbit or smaller int num_planets_total = 0; bool prior_current_planet = true; for (int sys_orbit : cur_system->PlanetIDsByOrbit()) { if (sys_orbit == INVALID_OBJECT_ID) continue; // all other planets are in further orbits if (sys_orbit == ID()) { prior_current_planet = false; ++num_planets_total; ++num_planets_lteq; continue; } PlanetType other_planet_type = GetPlanet(sys_orbit)->Type(); if (other_planet_type == INVALID_PLANET_TYPE) continue; // only increment suffix for non-asteroid planets if (Type() != PT_ASTEROIDS) { if (other_planet_type != PT_ASTEROIDS) { ++num_planets_total; if (prior_current_planet) ++num_planets_lteq; } } else { // unless the planet being named is an asteroid // then only increment suffix for asteroid planets if (other_planet_type == PT_ASTEROIDS) { ++num_planets_total; if (prior_current_planet) ++num_planets_lteq; } } } // Planets are grouped into asteroids, and non-asteroids if (Type() != PT_ASTEROIDS) { retval.append(RomanNumber(num_planets_lteq)); } else { // Asteroids receive a localized prefix retval.append(UserString("NEW_ASTEROIDS_SUFFIX")); // If no other asteroids in this system, do not append an ordinal if (num_planets_total > 1) retval.append(" " + RomanNumber(num_planets_lteq)); } return retval; }
void Fleet::CalculateRoute() const { m_travel_distance = 0.0; m_travel_route.clear(); //Logger().debugStream() << "Fleet::CalculateRoute"; if (m_moving_to == INVALID_OBJECT_ID) return; if (m_prev_system != INVALID_OBJECT_ID && SystemID() == m_prev_system) { // if we haven't actually left yet, we have to move from whichever system we are at now if (!GetSystem(m_moving_to)) return; // destination system doesn't exist or doesn't exist in known universe, so can't move to it. leave route empty. std::pair<std::list<int>, double> path; try { path = GetUniverse().ShortestPath(m_prev_system, m_moving_to, this->Owner()); } catch (...) { Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" << " fleet's previous: " << m_prev_system << " or moving to: " << m_moving_to; } m_travel_route = path.first; m_travel_distance = path.second; return; } int dest_system_id = m_moving_to; // Geoff: commenting out the early exit code of the owner of a fleet doesn't // have visibility of the destination system, since this was preventing the // human client's attempts to find routes for enemy fleets, for which the // player's client doesn't know which systems are visible, and since // visibility of a system on the current turn isn't necessary to plot // route to it now that empire's can remember systems they've seen on // previous turns. //if (universe.GetObjectVisibilityByEmpire(dest_system_id, this->Owner()) <= VIS_NO_VISIBILITY) { // // destination system isn't visible to this fleet's owner, so the fleet can't move to it // // // check if system to which fleet is moving is visible to the fleet's owner. this should always be true, but just in case... // if (universe.GetObjectVisibilityByEmpire(m_next_system, this->Owner()) <= VIS_NO_VISIBILITY) // return; // next system also isn't visible; leave route empty. // // // safety check: ensure supposedly visible object actually exists in known universe. // if (!GetSystem(m_next_system)) { // Logger().errorStream() << "Fleet::CalculateRoute found system with id " << m_next_system << " should be visible to this fleet's owner, but the system doesn't exist in the known universe!"; // return; // abort if object doesn't exist in known universe... can't path to it if it's not there, even if it's considered visible for some reason... // } // // // next system is visible, so move to that instead of ordered destination (m_moving_to) // dest_system_id = m_next_system; //} // if we're between systems, the shortest route may be through either one if (this->CanChangeDirectionEnRoute()) { std::pair<std::list<int>, double> path1; try { path1 = GetUniverse().ShortestPath(m_next_system, dest_system_id, this->Owner()); } catch (...) { Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" << " fleet's next: " << m_next_system << " or destination: " << dest_system_id; } const std::list<int>& sys_list1 = path1.first; if (sys_list1.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; return; } const UniverseObject* obj = GetUniverseObject(sys_list1.front()); if (!obj) { Logger().errorStream() << "Fleet::CalculateRoute couldn't get path start object with id " << path1.first.front(); return; } double dist_x = obj->X() - this->X(); double dist_y = obj->Y() - this->Y(); double dist1 = std::sqrt(dist_x*dist_x + dist_y*dist_y); std::pair<std::list<int>, double> path2; try { path2 = GetUniverse().ShortestPath(m_prev_system, dest_system_id, this->Owner()); } catch (...) { Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" << " fleet's previous: " << m_prev_system << " or destination: " << dest_system_id; } const std::list<int>& sys_list2 = path2.first; if (sys_list2.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; return; } obj = GetUniverseObject(sys_list2.front()); if (!obj) { Logger().errorStream() << "Fleet::CalculateRoute couldn't get path start object with id " << path2.first.front(); return; } dist_x = obj->X() - this->X(); dist_y = obj->Y() - this->Y(); double dist2 = std::sqrt(dist_x*dist_x + dist_y*dist_y); // pick whichever path is quicker if (dist1 + path1.second < dist2 + path2.second) { m_travel_route = path1.first; m_travel_distance = dist1 + path1.second; } else { m_travel_route = path2.first; m_travel_distance = dist2 + path2.second; } } else { std::pair<std::list<int>, double> route; try { route = GetUniverse().ShortestPath(m_next_system, dest_system_id, this->Owner()); } catch (...) { Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" << " fleet's next: " << m_next_system << " or destination: " << dest_system_id; } const std::list<int>& sys_list = route.first; if (sys_list.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; return; } const UniverseObject* obj = GetUniverseObject(sys_list.front()); if (!obj) { Logger().errorStream() << "Fleet::CalculateRoute couldn't get path start object with id " << route.first.front(); return; } double dist_x = obj->X() - this->X(); double dist_y = obj->Y() - this->Y(); double dist = std::sqrt(dist_x*dist_x + dist_y*dist_y); m_travel_route = route.first; m_travel_distance = dist + route.second; } }
void Fleet::MovementPhase() { //Logger().debugStream() << "Fleet::MovementPhase this: " << this->Name() << " id: " << this->ID(); m_arrived_this_turn = false; m_arrival_starlane = INVALID_OBJECT_ID; int prev_prev_system = m_prev_system; Empire* empire = Empires().Lookup(this->Owner()); // if owner of fleet can resupply ships at the location of this fleet, then // resupply all ships in this fleet if (empire && empire->FleetOrResourceSupplyableAtSystem(this->SystemID())) for (Fleet::const_iterator ship_it = this->begin(); ship_it != this->end(); ++ship_it) if (Ship* ship = GetShip(*ship_it)) ship->Resupply(); System* current_system = GetSystem(SystemID()); System* const initial_system = current_system; std::list<MovePathNode> move_path = this->MovePath(); std::list<MovePathNode>::const_iterator it = move_path.begin(); std::list<MovePathNode>::const_iterator next_it = it; if (next_it != move_path.end()) ++next_it; // is the ship stuck in a system for a whole turn? if (current_system) { // in a system. if there is no system after the current one in the // path, or the current and next nodes have the same system id, that // is an actual system, then won't be moving this turn. if ((next_it == move_path.end()) || (it->object_id != INVALID_OBJECT_ID && it->object_id == next_it->object_id) ) { // fuel regeneration for ships in stationary fleet if (this->FinalDestinationID() == INVALID_OBJECT_ID || this->FinalDestinationID() == this->SystemID()) { for (Fleet::const_iterator ship_it = this->begin(); ship_it != this->end(); ++ship_it) { if (Ship* ship = GetShip(*ship_it)) if (Meter* fuel_meter = ship->UniverseObject::GetMeter(METER_FUEL)) { fuel_meter->AddToCurrent(0.1001); fuel_meter->BackPropegate(); } } } return; } } // if fleet not moving, nothing more to do. if (move_path.empty() || move_path.size() == 1) { //Logger().debugStream() << "Fleet::MovementPhase: Fleet move path is empty or has only one entry. doing nothing"; return; } //Logger().debugStream() << "Fleet::MovementPhase move path:"; //for (std::list<MovePathNode>::const_iterator it = move_path.begin(); it != move_path.end(); ++it) // Logger().debugStream() << "... (" << it->x << ", " << it->y << ") at object id: " << it->object_id << " eta: " << it->eta << (it->turn_end ? " (end of turn)" : " (during turn)"); // move fleet in sequence to MovePathNodes it can reach this turn double fuel_consumed = 0.0; for (it = move_path.begin(); it != move_path.end(); ++it) { next_it = it; ++next_it; System* system = GetSystem(it->object_id); //Logger().debugStream() << "... node " << (system ? system->Name() : "no system"); // is this system the last node reached this turn? either it's an end of turn node, // or there are no more nodes after this one on path bool node_is_next_stop = (it->turn_end || next_it == move_path.end()); if (system) { // node is a system. explore system for all owners of this fleet if (empire) empire->AddExploredSystem(it->object_id); prev_prev_system = m_prev_system; m_prev_system = system->ID(); // passing a system, so update previous system of this fleet bool resupply_here = empire ? empire->FleetOrResourceSupplyableAtSystem(system->ID()) : false; // if this system can provide supplies, reset consumed fuel and refuel ships if (resupply_here) { //Logger().debugStream() << " ... node has fuel supply. consumed fuel for movement reset to 0 and fleet resupplied"; fuel_consumed = 0.0; for (Fleet::const_iterator ship_it = this->begin(); ship_it != this->end(); ++ship_it) { Ship* ship = GetShip(*ship_it); assert(ship); ship->Resupply(); } } if (node_is_next_stop) { // is system the last node reached this turn? system->Insert(this); // fleet ends turn at this node. insert fleet into system current_system = system; //Logger().debugStream() << "... ... inserted fleet into system"; break; } else { // fleet will continue past this system this turn. //Logger().debugStream() << "... ... moved fleet to system (not inserted)"; if (!resupply_here) { fuel_consumed += 1.0; //Logger().debugStream() << "... ... consuming 1 unit of fuel to continue moving. total fuel consumed now: " << fuel_consumed; } else { //Logger().debugStream() << "... ... not consuming fuel to depart resupply system"; } } } else { // node is not a system. if (node_is_next_stop) { // node is not a system, but is it the last node reached this turn? MoveTo(it->x, it->y); // fleet ends turn at this node. move fleet here //Logger().debugStream() << "... ... moved fleet to position"; break; } } } //Logger().debugStream() << "Fleet::MovementPhase rest of move path:"; //for (std::list<MovePathNode>::const_iterator it2 = it; it2 != move_path.end(); ++it2) // Logger().debugStream() << "... (" << it2->x << ", " << it2->y << ") at object id: " << it2->object_id << " eta: " << it2->eta << (it2->turn_end ? " (end of turn)" : " (during turn)"); // update next system if (m_moving_to != SystemID() && next_it != move_path.end() && it != move_path.end()) { // there is another system later on the path to aim for. find it for (; next_it != move_path.end(); ++next_it) { if (GetSystem(next_it->object_id)) { //Logger().debugStream() << "___ setting m_next_system to " << next_it->object_id; m_next_system = next_it->object_id; break; } } } else { // no more systems on path m_arrived_this_turn = current_system != initial_system; m_arrival_starlane = prev_prev_system; m_moving_to = m_next_system = m_prev_system = INVALID_OBJECT_ID; } // consume fuel from ships in fleet if (fuel_consumed > 0.0) { for (const_iterator ship_it = begin(); ship_it != end(); ++ship_it) if (Ship* ship = GetShip(*ship_it)) if (Meter* meter = ship->UniverseObject::GetMeter(METER_FUEL)) { meter->AddToCurrent(-fuel_consumed); meter->BackPropegate(); } } }
void Fleet::SetRoute(const std::list<int>& route) { if (route.empty()) throw std::invalid_argument("Fleet::SetRoute() : Attempted to set an empty route."); if (UnknownRoute()) throw std::invalid_argument("Fleet::SetRoute() : Attempted to set an unknown route."); if (m_prev_system != SystemID() && m_prev_system == route.front() && !CanChangeDirectionEnRoute()) throw std::invalid_argument("Fleet::SetRoute() : Illegally attempted to change a fleet's direction while it was in transit."); m_travel_route = route; // calculate length of line segments between systems on route, and sum up to determine length of route between // systems on route. (Might later add distance from fleet to first system on route to this to get the total // route length, or this may itself be the total route length if the fleet is at the first system on the route). m_travel_distance = 0.0; for (std::list<int>::const_iterator it = m_travel_route.begin(); it != m_travel_route.end(); ++it) { std::list<int>::const_iterator next_it = it; ++next_it; if (next_it == m_travel_route.end()) break; // current system is the last on the route, so don't need to add any additional distance. const System* cur_sys = GetSystem(*it); if (!cur_sys) { Logger().errorStream() << "Fleet::SetRoute() couldn't get system with id " << *it; return; } const System* next_sys = GetSystem(*next_it); if (!next_sys) { Logger().errorStream() << "Fleet::SetRoute() couldn't get system with id " << *next_it; return; } double dist_x = next_sys->X() - cur_sys->X(); double dist_y = next_sys->Y() - cur_sys->Y(); m_travel_distance += std::sqrt(dist_x*dist_x + dist_y*dist_y); } // if resetting to no movement while in a system if (SystemID() != INVALID_OBJECT_ID && SystemID() == m_travel_route.back()) { m_moving_to = INVALID_OBJECT_ID; m_next_system = INVALID_OBJECT_ID; m_prev_system = INVALID_OBJECT_ID; } else { // if we're already moving, add in the distance from where we are to the first system in the route if (SystemID() != route.front()) { const System* starting_system = GetSystem(route.front()); if (!starting_system) { Logger().errorStream() << "Fleet::SetRoute couldn't get system with id " << route.front(); return; } double dist_x = starting_system->X() - this->X(); double dist_y = starting_system->Y() - this->Y(); m_travel_distance += std::sqrt(dist_x*dist_x + dist_y*dist_y); } m_moving_to = m_travel_route.back(); if (m_prev_system != SystemID() && m_prev_system == m_travel_route.front()) { m_prev_system = m_next_system; // if already in transit and turning around, swap prev and next } else if (SystemID() == route.front()) { m_prev_system = SystemID(); } std::list<int>::const_iterator it = m_travel_route.begin(); m_next_system = m_prev_system == SystemID() ? (*++it) : (*it); } StateChangedSignal(); }
std::list<MovePathNode> Fleet::MovePath(const std::list<int>& route) const { std::list<MovePathNode> retval; if (route.empty()) return retval; // nowhere to go => empty path // if (route.size() == 1) do nothing special. this fleet is probably on the starlane leading to // its final destination. normal looping to read destination should work fine if (route.size() == 2 && route.front() == route.back()) return retval; // nowhere to go => empty path if (this->Speed() < FLEET_MOVEMENT_EPSILON) { retval.push_back(MovePathNode(this->X(), this->Y(), true, ETA_NEVER, this->SystemID(), INVALID_OBJECT_ID, INVALID_OBJECT_ID)); return retval; // can't move => path is just this system with explanatory ETA } double fuel = Fuel(); double max_fuel = MaxFuel(); //Logger().debugStream() << "Fleet " << this->Name() << " movePath fuel: " << fuel << " sys id: " << this->SystemID(); // determine all systems where fleet(s) can be resupplied if fuel runs out int owner = this->Owner(); const Empire* empire = Empires().Lookup(owner); std::set<int> fleet_supplied_systems; std::set<int> unobstructed_systems; if (empire) { fleet_supplied_systems = empire->FleetSupplyableSystemIDs(); unobstructed_systems = empire->SupplyUnobstructedSystems(); } // determine if, given fuel available and supplyable systems, fleet will ever be able to move if (fuel < 1.0 && this->SystemID() != INVALID_OBJECT_ID && fleet_supplied_systems.find(this->SystemID()) == fleet_supplied_systems.end()) { MovePathNode node(this->X(), this->Y(), true, ETA_OUT_OF_RANGE, this->SystemID(), INVALID_OBJECT_ID, INVALID_OBJECT_ID); retval.push_back(node); return retval; // can't move => path is just this system with explanatory ETA } // get iterator pointing to System* on route that is the first after where this fleet is currently. // if this fleet is in a system, the iterator will point to the system after the current in the route // if this fleet is not in a system, the iterator will point to the first system in the route std::list<int>::const_iterator route_it = route.begin(); if (*route_it == SystemID()) ++route_it; // first system in route is current system of this fleet. skip to the next system if (route_it == route.end()) return retval; // current system of this fleet is the *only* system in the route. path is empty. // get current, previous and next systems of fleet const System* cur_system = GetSystem(this->SystemID()); // may be 0 const System* prev_system = GetSystem(this->PreviousSystemID());// may be 0 if this fleet is not moving or ordered to move const System* next_system = GetSystem(*route_it); // can't use this->NextSystemID() because this fleet may not be moving and may not have a next system. this might occur when a fleet is in a system, not ordered to move or ordered to move to a system, but a projected fleet move line is being calculated to a different system if (!next_system) { Logger().errorStream() << "Fleet::MovePath couldn't get next system with id " << *route_it << " for this fleet " << this->Name(); return retval; } //Logger().debugStream() << "initial cur system: " << (cur_system ? cur_system->Name() : "(none)") << // " prev system: " << (prev_system ? prev_system->Name() : "(none)") << // " next system: " << (next_system ? next_system->Name() : "(none)"); // place initial position MovePathNode MovePathNode initial_pos(this->X(), this->Y(), false /* not an end of turn node */, 0 /* turns taken to reach position of node */, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(initial_pos); const int TOO_LONG = 100; // limit on turns to simulate. 99 turns max keeps ETA to two digits, making UI work better int turns_taken = 1; double turn_dist_remaining = m_speed; // additional distance that can be travelled in current turn of fleet movement being simulated double cur_x = this->X(); double cur_y = this->Y(); double next_x = next_system->X(); double next_y = next_system->Y(); // simulate fleet movement given known speed, starting position, fuel limit and systems on route // need to populate retval with MovePathNodes that indicate the correct position, whether this // fleet will end a turn at the node, the turns it will take to reach the node, and (when applicable) // the current (if at a system), previous and next system IDs at which the fleet will be. the // previous and next system ids are needed to know what starlane a given node is located on, if any. // nodes at systems don't need previous system ids to be valid, but should have next system ids // valid so that when rendering starlanes using the returned move path, lines departing a system // can be drawn on the correct side of the system icon while (turns_taken < TOO_LONG) { // each loop iteration moves the current position to the next location of interest along the move // path, and then adds a node at that position. //Logger().debugStream() << " starting iteration"; //if (cur_system) // Logger().debugStream() << " at system " << cur_system->Name() << " with id " << cur_system->ID(); //else // Logger().debugStream() << " at (" << cur_x << ", " << cur_y << ")"; // check if fuel limits movement or current system refuels passing fleet if (cur_system) { // check if current system has fuel supply available if (fleet_supplied_systems.find(cur_system->ID()) != fleet_supplied_systems.end()) { // current system has fuel supply. replenish fleet's supply and don't restrict movement fuel = max_fuel; //Logger().debugStream() << " ... at system with fuel supply. replenishing and continuing movement"; } else { // current system has no fuel supply. require fuel to proceed if (fuel >= 1.0) { //Logger().debugStream() << " ... at system without fuel supply. consuming unit of fuel to proceed"; fuel -= 1.0; } else { //Logger().debugStream() << " ... at system without fuel supply. have insufficient fuel to continue moving"; turns_taken = ETA_OUT_OF_RANGE; break; } } } // find distance to next system along path from current position double dist_to_next_system = std::sqrt((next_x - cur_x)*(next_x - cur_x) + (next_y - cur_y)*(next_y - cur_y)); //Logger().debugStream() << " ... dist to next system: " << dist_to_next_system; // move ship as far as it can go this turn, or to next system, whichever is closer, and deduct // distance travelled from distance travellable this turn if (turn_dist_remaining >= FLEET_MOVEMENT_EPSILON) { double dist_travelled_this_step = std::min(turn_dist_remaining, dist_to_next_system); //Logger().debugStream() << " ... fleet moving " << dist_travelled_this_step << " this iteration. dist to next system: " << dist_to_next_system << " and turn_dist_remaining: " << turn_dist_remaining; double x_dist = next_x - cur_x; double y_dist = next_y - cur_y; // dist_to_next_system = std::sqrt(x_dist * x_dist + y_dist * y_dist); // should already equal this distance, so don't need to recalculate double unit_vec_x = x_dist / dist_to_next_system; double unit_vec_y = y_dist / dist_to_next_system; cur_x += unit_vec_x*dist_travelled_this_step; cur_y += unit_vec_y*dist_travelled_this_step; turn_dist_remaining -= dist_travelled_this_step; dist_to_next_system -= dist_travelled_this_step; // if moved away any distance from a system, are no longer in that system if (cur_system && dist_travelled_this_step >= FLEET_MOVEMENT_EPSILON) { prev_system = cur_system; cur_system = 0; } } bool end_turn_at_cur_position = false; // check if fleet can move any further this turn if (turn_dist_remaining < FLEET_MOVEMENT_EPSILON) { //Logger().debugStream() << " ... fleet can't move further this turn."; turn_dist_remaining = 0.0; // to prevent any possible precision-related errors end_turn_at_cur_position = true; } // check if current position is close enough to next system on route to qualify as at that system. if (dist_to_next_system < FLEET_MOVEMENT_EPSILON) { // close enough to be consider to be at next system. // set current position to be exactly at next system to avoid rounding issues cur_system = next_system; cur_x = cur_system->X(); // update positions to ensure no round-off-errors cur_y = cur_system->Y(); //Logger().debugStream() << " ... arrived at system: " << cur_system->Name(); // attempt to get next system on route, to update next system. if new current // system is the end of the route, abort. ++route_it; if (route_it == route.end()) break; // update next system on route and distance to it from current position next_system = GetEmpireKnownSystem(*route_it, owner); if (!next_system) { Logger().errorStream() << "Fleet::MovePath couldn't get system with id " << *route_it; break; } next_x = next_system->X(); next_y = next_system->Y(); } // if new position is an obstructed system, must end turn here if (cur_system && unobstructed_systems.find(cur_system->ID()) == unobstructed_systems.end()) { turn_dist_remaining = 0.0; end_turn_at_cur_position = true; } // if turn done and turns taken is enough, abort simulation if (end_turn_at_cur_position && (turns_taken + 1 >= TOO_LONG)) { // exit loop before placing current node to simplify post-loop processing: now all cases require a post-loop node to be added ++turns_taken; break; } // add MovePathNode for current position (end of turn position and/or system location) MovePathNode cur_pos(cur_x, cur_y, end_turn_at_cur_position, turns_taken, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(cur_pos); // if the turn ended at this position, increment the turns taken and // reset the distance remaining to be travelled during the current (now // next) turn for the next loop iteration if (end_turn_at_cur_position) { //Logger().debugStream() << " ... end of simulated turn " << turns_taken; ++turns_taken; turn_dist_remaining = m_speed; } } // done looping. may have exited due to reaching end of path, lack of fuel, or turns taken getting too big if (turns_taken == TOO_LONG) turns_taken = ETA_NEVER; MovePathNode final_pos(cur_x, cur_y, true, turns_taken, (cur_system ? cur_system->ID() : INVALID_OBJECT_ID), (prev_system ? prev_system->ID() : INVALID_OBJECT_ID), (next_system ? next_system->ID() : INVALID_OBJECT_ID)); retval.push_back(final_pos); return retval; }