Example #1
0
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());
	}
}
Example #2
0
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);
	}
}