void FleetMoveOrder::ExecuteImpl() const { ValidateEmpireID(); TemporaryPtr<Fleet> fleet = GetFleet(FleetID()); if (!fleet) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered fleet with id " << FleetID() << " to move, but no such fleet exists"; return; } TemporaryPtr<const System> destination_system = GetEmpireKnownSystem(DestinationSystemID(), EmpireID()); if (!destination_system) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered fleet to move to system with id " << DestinationSystemID() << " but no such system is known to that empire"; return; } // reject empty routes if (m_route.empty()) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered fleet to move on empty route"; return; } // verify that empire specified in order owns specified fleet if (!fleet->OwnedBy(EmpireID()) ) { ErrorLogger() << "Empire with id " << EmpireID() << " order to move but does not own fleet with id " << FleetID(); return; } // verify fleet route first system int fleet_sys_id = fleet->SystemID(); if (!m_append || fleet->TravelRoute().empty()) { if (fleet_sys_id != INVALID_OBJECT_ID) { // fleet is in a system. Its move path should also start from that system. if (fleet_sys_id != m_start_system) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered a fleet to move from a system with id " << m_start_system << " that it is not at. Fleet is located at system with id " << fleet_sys_id; return; } } else { // fleet is not in a system. Its move path should start from the next system it is moving to. int next_system = fleet->NextSystemID(); if (next_system != m_start_system) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered a fleet to move starting from a system with id " << m_start_system << ", but the fleet's next destination is system with id " << next_system; return; } } } else { // We should append and there is something to append to int last_system = fleet->TravelRoute().back(); if (last_system != m_start_system) { ErrorLogger() << "Empire with id " << EmpireID() << " ordered a fleet to continue from system with id " << m_start_system << ", but the fleet's current route won't lead there, it leads to system " << last_system; return; } } // convert list of ids to list of System std::list<int> route_list; if(m_append && !fleet->TravelRoute().empty()){ route_list = fleet->TravelRoute(); route_list.erase(--route_list.end());// Remove the last one since it is the first one of the other } std::copy(m_route.begin(), m_route.end(), std::back_inserter(route_list)); // validate route. Only allow travel between systems connected in series by starlanes known to this fleet's owner. // check destination validity: disallow movement that's out of range std::pair<int, int> eta = fleet->ETA(fleet->MovePath(route_list)); if (eta.first == Fleet::ETA_NEVER || eta.first == Fleet::ETA_OUT_OF_RANGE) { DebugLogger() << "FleetMoveOrder::ExecuteImpl rejected out of range move order"; return; } std::string waypoints; for (std::list<int>::iterator it = route_list.begin(); it != route_list.end(); ++it) { waypoints += std::string(" ") + boost::lexical_cast<std::string>(*it); } DebugLogger() << "FleetMoveOrder::ExecuteImpl Setting route of fleet " << fleet->ID() << " to " << waypoints; fleet->SetRoute(route_list); }
bool ShipDesign::ProductionLocation(int empire_id, int location_id) const { TemporaryPtr<const UniverseObject> location = GetUniverseObject(location_id); if (!location) return false; // currently ships can only be built at planets, and by species that are // not planetbound TemporaryPtr<const Planet> planet = boost::dynamic_pointer_cast<const Planet>(location); if (!planet) return false; const std::string& species_name = planet->SpeciesName(); if (species_name.empty()) return false; const Species* species = GetSpecies(species_name); if (!species) return false; if (!species->CanProduceShips()) return false; // also, species that can't colonize can't produce colony ships if (this->CanColonize() && !species->CanColonize()) return false; Empire* empire = GetEmpire(empire_id); if (!empire) { DebugLogger() << "ShipDesign::ProductionLocation: Unable to get pointer to empire " << empire_id; return false; } // get a source object, which is owned by the empire with the passed-in // empire id. this is used in conditions to reference which empire is // doing the producing. Ideally this will be the capital, but any object // owned by the empire will work. TemporaryPtr<const UniverseObject> source = SourceForEmpire(empire_id); // if this empire doesn't own ANYTHING, then how is it producing anyway? if (!source) return false; // apply hull location conditions to potential location const HullType* hull = GetHull(); if (!hull) { ErrorLogger() << "ShipDesign::ProductionLocation ShipDesign couldn't get its own hull with name " << m_hull; return false; } if (!hull->Location()->Eval(ScriptingContext(source), location)) return false; // apply external and internal parts' location conditions to potential location for (std::vector<std::string>::const_iterator part_it = m_parts.begin(); part_it != m_parts.end(); ++part_it) { std::string part_name = *part_it; if (part_name.empty()) continue; // empty slots don't limit build location const PartType* part = GetPartType(part_name); if (!part) { ErrorLogger() << "ShipDesign::ProductionLocation ShipDesign couldn't get part with name " << part_name; return false; } if (!part->Location()->Eval(ScriptingContext(source), location)) return false; } // location matched all hull and part conditions, so is a valid build location return true; }
void NewFleetOrder::ExecuteImpl() const { ValidateEmpireID(); if (m_system_id == INVALID_OBJECT_ID) { ErrorLogger() << "Empire attempted to create a new fleet outside a system"; return; } TemporaryPtr<System> system = GetSystem(m_system_id); if (!system) { ErrorLogger() << "Empire attempted to create a new fleet in a nonexistant system"; return; } if (m_fleet_names.empty()) return; if (m_fleet_names.size() != m_fleet_ids.size() || m_fleet_names.size() != m_ship_id_groups.size() || m_fleet_names.size() != m_aggressives.size()) { ErrorLogger() << "NewFleetOrder has inconsistent data container sizes..."; return; } GetUniverse().InhibitUniverseObjectSignals(true); std::vector<TemporaryPtr<Fleet> > created_fleets; created_fleets.reserve(m_fleet_names.size()); // create fleet for each group of ships for (int i = 0; i < static_cast<int>(m_fleet_names.size()); ++i) { const std::string& fleet_name = m_fleet_names[i]; int fleet_id = m_fleet_ids[i]; const std::vector<int>& ship_ids = m_ship_id_groups[i]; bool aggressive = m_aggressives[i]; if (ship_ids.empty()) continue; // nothing to do... // validate specified ships std::vector<TemporaryPtr<Ship> > validated_ships; std::vector<int> validated_ships_ids; for (unsigned int i = 0; i < ship_ids.size(); ++i) { // verify that empire is not trying to take ships from somebody else's fleet TemporaryPtr<Ship> ship = GetShip(ship_ids[i]); if (!ship) { ErrorLogger() << "Empire attempted to create a new fleet with an invalid ship"; continue; } if (!ship->OwnedBy(EmpireID())) { ErrorLogger() << "Empire attempted to create a new fleet with ships from another's fleet."; continue; } if (ship->SystemID() != m_system_id) { ErrorLogger() << "Empire attempted to make a new fleet from ship in the wrong system"; continue; } validated_ships.push_back(ship); validated_ships_ids.push_back(ship->ID()); } if (validated_ships.empty()) continue; // create fleet TemporaryPtr<Fleet> fleet = GetUniverse().CreateFleet(fleet_name, system->X(), system->Y(), EmpireID(), fleet_id); fleet->GetMeter(METER_STEALTH)->SetCurrent(Meter::LARGE_VALUE); fleet->SetAggressive(aggressive); // an ID is provided to ensure consistancy between server and client universes GetUniverse().SetEmpireObjectVisibility(EmpireID(), fleet->ID(), VIS_FULL_VISIBILITY); system->Insert(fleet); // new fleet will get same m_arrival_starlane as fleet of the first ship in the list. TemporaryPtr<Ship> firstShip = validated_ships[0]; TemporaryPtr<Fleet> firstFleet = GetFleet(firstShip->FleetID()); if (firstFleet) fleet->SetArrivalStarlane(firstFleet->ArrivalStarlane()); // remove ships from old fleet(s) and add to new for (std::vector<TemporaryPtr<Ship> >::iterator ship_it = validated_ships.begin(); ship_it != validated_ships.end(); ++ship_it) { TemporaryPtr<Ship> ship = *ship_it; if (TemporaryPtr<Fleet> old_fleet = GetFleet(ship->FleetID())) old_fleet->RemoveShip(ship->ID()); ship->SetFleetID(fleet->ID()); } fleet->AddShips(validated_ships_ids); created_fleets.push_back(fleet); } GetUniverse().InhibitUniverseObjectSignals(false); system->FleetsInsertedSignal(created_fleets); system->StateChangedSignal(); }
boost::shared_ptr<GG::Texture> FleetSizeIcon(TemporaryPtr<const Fleet> fleet, FleetButton::SizeType size_type) { if (!fleet) return FleetSizeIcon(1u, size_type); return FleetSizeIcon(fleet->NumShips(), size_type); }
void CombatShip::UpdateMissionQueue() { assert(!m_mission_queue.empty()); const float DEFAULT_MISSION_WEIGHT = 12.0; const float MAX_MISSION_WEIGHT = 48.0; const float AT_DESTINATION = std::max(3.0f, speed()); const float AT_DEST_SQUARED = AT_DESTINATION * AT_DESTINATION; bool print_needed = false; if (m_instrument && m_last_mission != m_mission_queue.back().m_type) { std::cout << "empire=" << m_empire_id << "\n" << " prev mission=" << SHIP_MISSION_STRINGS[m_last_mission] << "\n" << " new mission =" << SHIP_MISSION_STRINGS[m_mission_queue.back().m_type] << "\n"; print_needed = true; m_last_mission = m_mission_queue.back().m_type; } m_last_queue_update_turn = m_turn; m_mission_weight = 0.0; m_mission_destination = OpenSteer::Vec3(); switch (m_mission_queue.back().m_type) { case ShipMission::NONE: { assert(m_mission_queue.size() == 1u); m_mission_queue.clear(); m_mission_queue.push_front(ShipMission(ShipMission::ATTACK_SHIPS_NEAREST_FIRST)); if (print_needed) std::cout << " [STARTING DEFAULT MISSION]\n"; break; } case ShipMission::MOVE_TO: { if (AT_DEST_SQUARED < (position() - m_mission_queue.back().m_destination).lengthSquared()) { m_mission_weight = MAX_MISSION_WEIGHT; m_mission_destination = m_mission_queue.back().m_destination; } else { if (print_needed) std::cout << " [ARRIVED]\n"; RemoveMission(); } break; } case ShipMission::ATTACK_THIS_STANDOFF: case ShipMission::ATTACK_THIS: { if (CombatObjectPtr target = m_mission_queue.back().m_target.lock()) { m_mission_weight = DEFAULT_MISSION_WEIGHT; OpenSteer::Vec3 target_position = target->position(); if (target->IsFighter()) { assert(boost::dynamic_pointer_cast<CombatFighter>(target)); CombatFighterPtr f = boost::static_pointer_cast<CombatFighter>(target); target_position = f->Formation()->Centroid(); } OpenSteer::Vec3 from_target_vec = position() - target_position; float from_target_length = from_target_vec.length(); from_target_vec /= from_target_length; const float WEAPON_RANGE_FACTOR = 0.9f; float distance = std::min<float>(MaxWeaponRange() * WEAPON_RANGE_FACTOR, from_target_length); if (m_mission_queue.back().m_type == ShipMission::ATTACK_THIS_STANDOFF) distance = MinNonPDWeaponRange() * WEAPON_RANGE_FACTOR; m_mission_destination = target_position + distance * from_target_vec; } else { if (print_needed) std::cout << " [ATTACK TARGET GONE]\n"; RemoveMission(); } break; } case ShipMission::DEFEND_THIS: { if (CombatObjectPtr target = m_mission_queue.back().m_target.lock()) { m_mission_weight = DEFAULT_MISSION_WEIGHT; if (m_is_PD_ship) { PathingEngine::ConstAttackerRange attackers = m_pathing_engine->Attackers(target); CombatShipPtr ship; for (PathingEngine::Attackees::const_iterator it = attackers.first; it != attackers.second; ++it) { CombatObjectPtr attacker = it->second.lock(); if (attacker && attacker->IsShip()) { assert(boost::dynamic_pointer_cast<CombatShip>(attacker)); CombatShipPtr temp = boost::static_pointer_cast<CombatShip>(attacker); if (!ship || ship->m_raw_LR_strength < temp->m_raw_LR_strength) ship = temp; } } if (ship) { m_mission_weight = MAX_MISSION_WEIGHT; OpenSteer::Vec3 target_position = target->position(); OpenSteer::Vec3 attacker_position = ship->position(); OpenSteer::Vec3 target_to_attacker = (attacker_position - target_position).normalize(); double min_PD_range = GetShip()->Design()->PDWeapons().begin()->first; m_mission_destination = target_position + target_to_attacker * min_PD_range / 2.0; } else { // No attacker found; just get close to the target to keep // it blanketted with PD. OpenSteer::Vec3 target_position = target->position(); OpenSteer::Vec3 target_to_here = (position() - target->position()).normalize(); double min_PD_range = GetShip()->Design()->PDWeapons().begin()->first; m_mission_destination = target_position + target_to_here * min_PD_range / 3.0; } } else { if (m_mission_subtarget.expired()) { m_mission_subtarget = WeakestAttacker(target); if (CombatObjectPtr subtarget = m_mission_subtarget.lock()) m_mission_destination = subtarget->position(); else m_mission_destination = target->position(); } } } else { if (print_needed) std::cout << " [DEFEND TARGET GONE]\n"; RemoveMission(); } break; } case ShipMission::PATROL_TO: { // TODO: Consider making the engagement range dynamically adjustable by the user. const float PATROL_ENGAGEMENT_RANGE = 50.0; if (AT_DEST_SQUARED < (position() - m_mission_queue.back().m_destination).lengthSquared()) { m_mission_weight = DEFAULT_MISSION_WEIGHT; bool found_target = false; if (CombatObjectPtr object = m_pathing_engine->NearestHostileNonFighterInRange(position(), m_empire_id, PATROL_ENGAGEMENT_RANGE)) { m_mission_destination = object->position(); PushMission(ShipMission(ShipMission::ATTACK_THIS, object)); found_target = true; if (print_needed) std::cout << " [ENGAGING HOSTILE SHIP]\n"; } if (!found_target) m_mission_destination = m_mission_queue.back().m_destination; } else { if (print_needed) std::cout << " [ARRIVED]\n"; RemoveMission(); } break; } case ShipMission::ATTACK_SHIPS_WEAKEST_FIRST_STANDOFF: case ShipMission::ATTACK_SHIPS_WEAKEST_FIRST: { if (CombatObjectPtr object = WeakestHostileShip()) { m_mission_weight = DEFAULT_MISSION_WEIGHT; m_mission_destination = object->position(); PushMission( ShipMission( m_mission_queue.back().m_type == ShipMission::ATTACK_SHIPS_WEAKEST_FIRST ? ShipMission::ATTACK_THIS : ShipMission::ATTACK_THIS_STANDOFF, object)); if (print_needed) std::cout << " [ENGAGING HOSTILE SHIP]\n"; } else { if (print_needed) std::cout << " [NO TARGETS]\n"; RemoveMission(); } m_mission_weight = DEFAULT_MISSION_WEIGHT; break; } case ShipMission::ATTACK_SHIPS_NEAREST_FIRST_STANDOFF: case ShipMission::ATTACK_SHIPS_NEAREST_FIRST: { if (CombatObjectPtr object = m_pathing_engine->NearestHostileShip(position(), m_empire_id)) { m_mission_weight = DEFAULT_MISSION_WEIGHT; m_mission_destination = object->position(); PushMission( ShipMission( m_mission_queue.back().m_type == ShipMission::ATTACK_SHIPS_NEAREST_FIRST ? ShipMission::ATTACK_THIS : ShipMission::ATTACK_THIS_STANDOFF, object)); if (print_needed) std::cout << " [ENGAGING HOSTILE SHIP]\n"; } else { if (print_needed) std::cout << " [NO TARGETS]\n"; RemoveMission(); } break; } case ShipMission::ENTER_STARLANE: { TemporaryPtr<System> system = GetSystem(GetShip()->SystemID()); assert(system); const std::map<int, bool>& lanes = system->StarlanesWormholes(); for (std::map<int, bool>::const_iterator it = lanes.begin(); it != lanes.end(); ++it) { if (PointInStarlaneEllipse(position().x, position().y, system->ID(), it->first)) { m_enter_starlane_start_turn = m_turn; break; } assert(!"Illegal ENTER_STARLANE ShipMission was issued -- ship is not within " "minimum distance of any starlane entrance."); } } } if (print_needed) std::cout << " position =" << position() << "\n" << " destination=" << m_mission_destination << "\n" << " mission_weight=" << m_mission_weight << "\n" << std::endl; }
boost::shared_ptr<GG::Texture> FleetHeadIcon(const std::vector< TemporaryPtr<const Fleet> >& fleets, FleetButton::SizeType size_type) { if (size_type == FleetButton::FLEET_BUTTON_NONE || size_type == FleetButton::FLEET_BUTTON_TINY) return boost::shared_ptr<GG::Texture>(); // get file name prefix for appropriate size of icon std::string size_prefix = FleetIconSizePrefix(size_type); if (size_prefix.empty()) return boost::shared_ptr<GG::Texture>(); // the set of fleets is treated like a fleet that contains all the ships bool hasColonyShips = false; bool hasOutpostShips = false; bool hasTroopShips = false; bool hasMonsters = false; bool hasArmedShips = false; for (std::vector< TemporaryPtr<const Fleet> >::const_iterator fleet_it = fleets.begin(); fleet_it != fleets.end(); ++fleet_it) { const TemporaryPtr<const Fleet> fleet = *fleet_it; if (!fleet) continue; hasColonyShips = hasColonyShips || fleet->HasColonyShips(); hasOutpostShips = hasOutpostShips || fleet->HasOutpostShips(); hasTroopShips = hasTroopShips || fleet->HasTroopShips(); hasMonsters = hasMonsters || fleet->HasMonsters(); hasArmedShips = hasArmedShips || fleet->HasArmedShips(); } // get file name main part depending on type of fleet // symbol type prioritized by the ship type arbitrarily deemed "most important" std::string main_filename = "head-scout.png"; if (hasArmedShips) { main_filename = "head-warship.png"; if (hasTroopShips) main_filename = "head-lander.png"; else if (hasMonsters) main_filename = "head-monster.png"; } else { if (hasTroopShips) main_filename = "head-lander.png"; else if (hasColonyShips) main_filename = "head-colony.png"; else if (hasOutpostShips) main_filename = "head-outpost.png"; else if (hasMonsters) main_filename = "head-monster-harmless.png"; } // reset to generic icon in cases where the above is too imprecise if (hasArmedShips) { if (hasColonyShips) main_filename = "head-scout.png"; else if (hasOutpostShips) main_filename = "head-scout.png"; else if (hasMonsters && main_filename != "head-monster.png") main_filename = "head-scout.png"; } else { if (hasColonyShips && main_filename != "head-colony.png") main_filename = "head-scout.png"; else if (hasOutpostShips && main_filename != "head-outpost.png") main_filename = "head-scout.png"; else if (hasMonsters && main_filename != "head-monster-harmless.png") main_filename = "head-scout.png"; } return ClientUI::GetTexture(ClientUI::ArtDir() / "icons" / "fleet" / (size_prefix + main_filename), false); }
void FleetButton::Init(const std::vector<int>& fleet_IDs, SizeType size_type) { if (!scanline_shader && GetOptionsDB().Get<bool>("UI.system-fog-of-war")) { boost::filesystem::path shader_path = GetRootDataDir() / "default" / "shaders" / "scanlines.frag"; std::string shader_text; ReadFile(shader_path, shader_text); scanline_shader = boost::shared_ptr<ShaderProgram>( ShaderProgram::shaderProgramFactory("", shader_text)); } // get fleets std::vector<TemporaryPtr<const Fleet> > fleets; for (std::vector<int>::const_iterator it = fleet_IDs.begin(); it != fleet_IDs.end(); ++it) { TemporaryPtr<const Fleet> fleet = GetFleet(*it); if (!fleet) { Logger().errorStream() << "FleetButton::FleetButton couldn't get fleet with id " << *it; continue; } m_fleets.push_back(*it); fleets.push_back(fleet); } // determine owner(s) of fleet(s). Only care whether or not there is more than one owner, as owner // is used to determine colouration int owner_id = ALL_EMPIRES; int multiple_owners = false; if (fleets.empty()) { // leave as ALL_EMPIRES } else if (fleets.size() == 1) { owner_id = (*fleets.begin())->Owner(); } else { owner_id = (*fleets.begin())->Owner(); // use ALL_EMPIRES if there are multiple owners (including no owner and an owner) for (std::vector<TemporaryPtr<const Fleet> >::const_iterator it = fleets.begin(); it != fleets.end(); ++it) { TemporaryPtr<const Fleet> fleet = *it; if (fleet->Owner() != owner_id) { owner_id = ALL_EMPIRES; multiple_owners = true; break; } } } // get fleet colour if (multiple_owners) { SetColor(GG::CLR_WHITE); } else if (owner_id == ALL_EMPIRES) { // all ships owned by now empire bool monsters = true; // find if any ship in fleets in button is not a monster for (std::vector<TemporaryPtr<const Fleet> >::const_iterator it = fleets.begin(); it != fleets.end(); ++it) { TemporaryPtr<const Fleet> fleet = *it; for (std::set<int>::const_iterator ship_it = fleet->ShipIDs().begin(); ship_it != fleet->ShipIDs().end(); ++ship_it) { if (TemporaryPtr<const Ship> ship = GetShip(*ship_it)) { if (!ship->IsMonster()) { monsters = false; break; } } } } if (monsters) SetColor(GG::CLR_RED); else SetColor(GG::CLR_WHITE); } else { // single empire owner if (const Empire* empire = Empires().Lookup(owner_id)) SetColor(empire->Color()); else SetColor(GG::CLR_GRAY); // should never be necessary... but just in case } // select icon(s) for fleet(s) int num_ships = 0; for (std::vector<TemporaryPtr<const Fleet> >::const_iterator it = fleets.begin(); it != fleets.end(); ++it) { TemporaryPtr<const Fleet> fleet = *it; if (fleet) num_ships += fleet->NumShips(); } m_size_icon = FleetSizeIcon(num_ships, size_type); m_head_icon = FleetHeadIcon(fleets, size_type); // resize to fit icon by first determining necessary size, and then resizing GG::X texture_width(0); GG::Y texture_height(0); if (m_head_icon) { texture_width = m_head_icon->DefaultWidth(); texture_height = m_head_icon->DefaultHeight(); } if (m_size_icon) { texture_width = std::max(texture_width, m_size_icon->DefaultWidth()); texture_height = std::max(texture_height, m_size_icon->DefaultHeight()); } // determine if fleet icon should be rotated. this should be done if the fleet is moving along // a starlane, which is the case if the fleet is not in a system and has a valid next system GG::Pt direction_vector(GG::X(0), GG::Y(1)); // default, unrotated button orientation TemporaryPtr<const Fleet> first_fleet; if (!m_fleets.empty()) first_fleet = *fleets.begin(); if (first_fleet && first_fleet->SystemID() == INVALID_OBJECT_ID) { int next_sys_id = first_fleet->NextSystemID(); if (TemporaryPtr<const UniverseObject> obj = GetUniverseObject(next_sys_id)) { // fleet is not in a system and has a valid next destination, so can orient it in that direction // fleet icons might not appear on the screen in the exact place corresponding to their // actual universe position, but if they're moving along a starlane, this code will assume // their apparent position will only be different from their true position in a direction // parallel with the starlane, so the direction from their true position to their destination // position can be used to get a direction vector to orient the icon double dest_x = obj->X(), dest_y = obj->Y(); double cur_x = first_fleet->X(), cur_y = first_fleet->Y(); const MapWnd* map_wnd = ClientUI::GetClientUI()->GetMapWnd(); GG::Pt dest = map_wnd->ScreenCoordsFromUniversePosition(dest_x, dest_y); GG::Pt cur = map_wnd->ScreenCoordsFromUniversePosition(cur_x, cur_y); direction_vector = dest - cur; } } // check for unrotated texture if (Value(direction_vector.x) == 0) { // not rotated. can do simple texture blits m_vertex_components.clear(); } else { // texture is rotated, so need some extra math // get rotated corner vetex x and y components (x1, y1, x2, y2, x3, y3, x4, y4) for texture of appropriate size m_vertex_components = VectorAlignedQuadVertices(direction_vector, Value(texture_height), Value(texture_width)); } // size icon according to texture size (average two dimensions) int diameter = static_cast<int>((Value(texture_width) + Value(texture_height)) / 2.0); Resize(GG::Pt(GG::X(diameter), GG::Y(diameter))); // get selection indicator texture m_selection_texture = ClientUI::GetTexture(ClientUI::ArtDir() / "icons" / "fleet" / "fleet_selection.png", true); }
bool Field::InField(TemporaryPtr<const UniverseObject> obj) const { return obj && InField(obj->X(), obj->Y()); }
int IssueInvadeOrder(int ship_id, int planet_id) { int empire_id = AIClientApp::GetApp()->EmpireID(); // make sure ship_id is a ship... TemporaryPtr<const Ship> ship = GetShip(ship_id); if (!ship) { ErrorLogger() << "IssueInvadeOrder : passed an invalid ship_id"; return 0; } // get fleet of ship TemporaryPtr<const Fleet> fleet = GetFleet(ship->FleetID()); if (!fleet) { ErrorLogger() << "IssueInvadeOrder : ship with passed ship_id has invalid fleet_id"; return 0; } // make sure player owns ship and its fleet if (!fleet->OwnedBy(empire_id)) { ErrorLogger() << "IssueInvadeOrder : empire does not own fleet of passed ship"; return 0; } if (!ship->OwnedBy(empire_id)) { ErrorLogger() << "IssueInvadeOrder : empire does not own passed ship"; return 0; } // verify that planet exists and is occupied by another empire TemporaryPtr<const Planet> planet = GetPlanet(planet_id); if (!planet) { ErrorLogger() << "IssueInvadeOrder : no planet with passed planet_id"; return 0; } bool owned_by_invader = planet->OwnedBy(empire_id); bool unowned = planet->Unowned(); bool populated = planet->CurrentMeterValue(METER_POPULATION) > 0.; bool visible = GetUniverse().GetObjectVisibilityByEmpire(planet_id, empire_id) >= VIS_PARTIAL_VISIBILITY; bool vulnerable = planet->CurrentMeterValue(METER_SHIELD) <= 0.; float shields = planet->CurrentMeterValue(METER_SHIELD); std::string this_species = planet->SpeciesName(); //bool being_invaded = planet->IsAboutToBeInvaded(); bool invadable = !owned_by_invader && vulnerable && (populated || !unowned) && visible ;// && !being_invaded; a 'being_invaded' check prevents AI from invading with multiple ships at once, which is important if (!invadable) { ErrorLogger() << "IssueInvadeOrder : planet with passed planet_id " << planet_id << " and species " << this_species << " is not invadable due to one or more of: owned by invader empire, " << "not visible to invader empire, has shields above zero, or is already being invaded."; if (!unowned) ErrorLogger() << "IssueInvadeOrder : planet (id " << planet_id << ") is not unowned"; if (!visible) ErrorLogger() << "IssueInvadeOrder : planet (id " << planet_id << ") is not visible"; if (!vulnerable) ErrorLogger() << "IssueInvadeOrder : planet (id " << planet_id << ") is not vulnerable, shields at "<<shields; return 0; } // verify that planet is in same system as the fleet if (planet->SystemID() != fleet->SystemID()) { ErrorLogger() << "IssueInvadeOrder : fleet and planet are not in the same system"; return 0; } if (ship->SystemID() == INVALID_OBJECT_ID) { ErrorLogger() << "IssueInvadeOrder : ship is not in a system"; return 0; } AIClientApp::GetApp()->Orders().IssueOrder(OrderPtr(new InvadeOrder(empire_id, ship_id, planet_id))); return 1; }
int IssueColonizeOrder(int ship_id, int planet_id) { int empire_id = AIClientApp::GetApp()->EmpireID(); // make sure ship_id is a ship... TemporaryPtr<const Ship> ship = GetShip(ship_id); if (!ship) { ErrorLogger() << "IssueColonizeOrder : passed an invalid ship_id"; return 0; } // get fleet of ship TemporaryPtr<const Fleet> fleet = GetFleet(ship->FleetID()); if (!fleet) { ErrorLogger() << "IssueColonizeOrder : ship with passed ship_id has invalid fleet_id"; return 0; } // make sure player owns ship and its fleet if (!fleet->OwnedBy(empire_id)) { ErrorLogger() << "IssueColonizeOrder : empire does not own fleet of passed ship"; return 0; } if (!ship->OwnedBy(empire_id)) { ErrorLogger() << "IssueColonizeOrder : empire does not own passed ship"; return 0; } // verify that planet exists and is un-occupied. TemporaryPtr<const Planet> planet = GetPlanet(planet_id); if (!planet) { ErrorLogger() << "IssueColonizeOrder : no planet with passed planet_id"; return 0; } if ((!planet->Unowned()) && !( planet->OwnedBy(empire_id) && planet->CurrentMeterValue(METER_POPULATION)==0)) { ErrorLogger() << "IssueColonizeOrder : planet with passed planet_id "<<planet_id<<" is already owned, or colonized by own empire"; return 0; } // verify that planet is in same system as the fleet if (planet->SystemID() != fleet->SystemID()) { ErrorLogger() << "IssueColonizeOrder : fleet and planet are not in the same system"; return 0; } if (ship->SystemID() == INVALID_OBJECT_ID) { ErrorLogger() << "IssueColonizeOrder : ship is not in a system"; return 0; } AIClientApp::GetApp()->Orders().IssueOrder(OrderPtr(new ColonizeOrder(empire_id, ship_id, planet_id))); return 1; }