// Do the randomization to make a ship enter or be in the given system. void Fleet::Enter(const System &system, Ship &ship) { if(!system.Links().size()) { Place(system, ship); return; } const System *source = system.Links()[Random::Int(system.Links().size())]; Angle angle = Angle::Random(); Point pos = angle.Unit() * Random::Real() * 1000.; ship.Place(pos, angle.Unit(), angle); ship.SetSystem(source); ship.SetTargetSystem(&system); }
void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Planet *planet) const { if(!total || !government) return; // Pick a random variant based on the weights. unsigned index = 0; for(int choice = Random::Int(total); choice >= variants[index].weight; ++index) choice -= variants[index].weight; if(variants[index].ships.empty()) return; bool isEnemy = system.GetGovernment()->IsEnemy(government); bool hasJump = variants[index].ships.front()->Attributes().Get("jump drive"); const vector<const System *> &linkVector = hasJump ? system.Neighbors() : system.Links(); int links = linkVector.size(); // Count the inhabited planets in this system. int planets = 0; if(!isEnemy && !personality.IsSurveillance()) for(const StellarObject &object : system.Objects()) if(object.GetPlanet() && object.GetPlanet()->HasSpaceport()) ++planets; if(!(links + planets)) return; int choice = Random::Int(links + planets); const System *source = &system; const System *target = &system; Point position; unsigned radius = 0; if(planet) { for(const StellarObject &object : system.Objects()) if(object.GetPlanet() == planet) { position = object.Position(); radius = max(0, static_cast<int>(object.Radius())); break; } } else if(choice >= links) { choice -= links; planets = 0; for(const StellarObject &object : system.Objects()) if(object.GetPlanet() && object.GetPlanet()->HasSpaceport()) { if(planets++ != choice) continue; position = object.Position(); planet = object.GetPlanet(); radius = max(0, static_cast<int>(object.Radius())); break; } if(links) target = linkVector[Random::Int(links)]; } else { radius = 1000; source = linkVector[choice]; } vector<shared_ptr<Ship>> placed; for(const Ship *ship : variants[index].ships) { if(ship->CanBeCarried()) { shared_ptr<Ship> fighter(new Ship(*ship)); fighter->SetGovernment(government); fighter->SetName((fighterNames ? fighterNames : names)->Get()); fighter->SetPersonality(personality); for(const shared_ptr<Ship> &parent : placed) if(parent->AddFighter(fighter)) break; continue; } Angle angle = Angle::Random(360.); Point pos = position + angle.Unit() * (Random::Int(radius + 1)); ships.push_front(shared_ptr<Ship>(new Ship(*ship))); ships.front()->SetSystem(source); ships.front()->SetPlanet(planet); if(source == &system) ships.front()->Place(pos, angle.Unit(), angle); else { Point offset = system.Position() - source->Position(); angle = TO_DEG * atan2(offset.X(), -offset.Y()); ships.front()->Place(pos, Point(), angle); } ships.front()->SetTargetSystem(target); ships.front()->SetGovernment(government); ships.front()->SetName(names->Get()); ships.front()->SetPersonality(personality); if(!placed.empty()) ships.front()->SetParent(placed.front()); placed.push_back(ships.front()); SetCargo(&*ships.front()); } }
void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Planet *planet) const { if(!total || !government || variants.empty()) return; // Pick a fleet variant to instantiate. const Variant &variant = ChooseVariant(); if(variant.ships.empty()) return; // Where this fleet can come from depends on whether it is friendly to any // planets in this system and whether it has jump drives. vector<const System *> linkVector; // Find out what the "best" jump method the fleet has is. Assume that if the // others don't have that jump method, they are being carried as fighters. // That is, content creators should avoid creating fleets with a mix of jump // drives and hyperdrives. int jumpType = 0; for(const Ship *ship : variant.ships) jumpType = max(jumpType, ship->Attributes().Get("jump drive") ? 200 : ship->Attributes().Get("hyperdrive") ? 100 : 0); if(jumpType) { // Don't try to make a fleet "enter" from another system if none of the // ships have jump drives. bool isWelcomeHere = !system.GetGovernment()->IsEnemy(government); for(const System *neighbor : (jumpType == 200 ? system.Neighbors() : system.Links())) { // If this ship is not "welcome" in the current system, prefer to have // it enter from a system that is friendly to it. (This is for realism, // so attack fleets don't come from what ought to be a safe direction.) if(isWelcomeHere || neighbor->GetGovernment()->IsEnemy(government)) linkVector.push_back(neighbor); else linkVector.insert(linkVector.end(), 4, neighbor); } } // Find all the inhabited planets this fleet could take off from. vector<const Planet *> planetVector; if(!personality.IsSurveillance()) for(const StellarObject &object : system.Objects()) if(object.GetPlanet() && object.GetPlanet()->HasSpaceport() && !object.GetPlanet()->GetGovernment()->IsEnemy(government)) planetVector.push_back(object.GetPlanet()); // If there is nowhere for this fleet to come from, don't create it. size_t options = linkVector.size() + planetVector.size(); if(!options) return; // Choose a random planet or star system to come from. size_t choice = Random::Int(options); // Figure out what system the ship is starting in, where it is going, and // what position it should start from in the system. const System *source = &system; const System *target = &system; Point position; double radius = 0.; // If a planet is chosen, also pick a system to travel to after taking off. if(choice >= linkVector.size()) { planet = planetVector[choice - linkVector.size()]; if(!linkVector.empty()) target = linkVector[Random::Int(linkVector.size())]; } // Find the stellar object for the given planet, and place the ships there. if(planet) { for(const StellarObject &object : system.Objects()) if(object.GetPlanet() == planet) { position = object.Position(); radius = object.Radius(); break; } } else if(choice < linkVector.size()) { // We are entering this system via hyperspace, not taking off from a planet. radius = 1000.; source = linkVector[choice]; } // Place all the ships in the chosen fleet variant. shared_ptr<Ship> flagship; vector<shared_ptr<Ship>> placed = Instantiate(variant); for(shared_ptr<Ship> &ship : placed) { // If this is a fighter and someone can carry it, no need to position it. if(PlaceFighter(ship, placed)) continue; Angle angle = Angle::Random(360.); Point pos = position + angle.Unit() * (Random::Real() * radius); ships.push_front(ship); ship->SetSystem(source); ship->SetPlanet(planet); if(source == &system) ship->Place(pos, angle.Unit(), angle); else { // Place the ship stationary and pointed in the right direction. angle = Angle(system.Position() - source->Position()); ship->Place(pos, Point(), angle); } if(target != source) ship->SetTargetSystem(target); if(flagship) ship->SetParent(flagship); else flagship = ship; SetCargo(&*ship); } }