예제 #1
0
void HiringPanel::Draw()
{
	if(!player.Flagship())
		return;
	const Ship &flagship = *player.Flagship();
	
	// Draw a line in the same place as the trading and bank panels.
	FillShader::Fill(Point(-60., 95.), Point(480., 1.), *GameData::Colors().Get("medium"));
	
	const Interface *interface = GameData::Interfaces().Get("hiring");
	Information info;
	
	int flagshipBunks = flagship.Attributes().Get("bunks");
	int flagshipRequired = flagship.RequiredCrew();
	int flagshipExtra = flagship.Crew() - flagshipRequired;
	int flagshipUnused = flagshipBunks - flagship.Crew();
	info.SetString("flagship bunks", to_string(static_cast<int>(flagshipBunks)));
	info.SetString("flagship required", to_string(static_cast<int>(flagshipRequired)));
	info.SetString("flagship extra", to_string(static_cast<int>(flagshipExtra)));
	info.SetString("flagship unused", to_string(static_cast<int>(flagshipUnused)));
	
	// Sum up the statistics for all your ships.
	int fleetBunks = 0;
	int fleetRequired = 0;
	for(const shared_ptr<Ship> &ship : player.Ships())
		if(!ship->IsParked())
		{
			fleetBunks += static_cast<int>(ship->Attributes().Get("bunks"));
			fleetRequired += ship->RequiredCrew();
		}
	int passengers = player.Cargo().Passengers();
	int fleetUnused = fleetBunks - fleetRequired - flagshipExtra;
	info.SetString("fleet bunks", to_string(static_cast<int>(fleetBunks)));
	info.SetString("fleet required", to_string(static_cast<int>(fleetRequired)));
	info.SetString("fleet unused", to_string(static_cast<int>(fleetUnused)));
	info.SetString("passengers", to_string(static_cast<int>(passengers)));
	
	static const int DAILY_SALARY = 100;
	int salary = DAILY_SALARY * (fleetRequired - 1);
	int extraSalary = DAILY_SALARY * flagshipExtra;
	info.SetString("salary required", to_string(static_cast<int>(salary)));
	info.SetString("salary extra", to_string(static_cast<int>(extraSalary)));
	
	int modifier = Modifier();
	if(modifier > 1)
		info.SetString("modifier", "x " + to_string(modifier));
	
	maxFire = max(flagshipExtra, 0);
	maxHire = max(min(flagshipUnused, fleetUnused - passengers), 0);
	
	if(maxHire)
		info.SetCondition("can hire");
	if(maxFire)
		info.SetCondition("can fire");
	
	interface->Draw(info, this);
}
void MissionPanel::Draw() const
{
	MapPanel::Draw();
	
	Color routeColor(.2, .1, 0., 0.);
	const System *system = selectedSystem;
	while(distance.Distance(system) > 0)
	{
		const System *next = distance.Route(system);
		
		Point from = Zoom() * (next->Position() + center);
		Point to = Zoom() * (system->Position() + center);
		Point unit = (from - to).Unit() * 7.;
		from -= unit;
		to += unit;
		
		LineShader::Draw(from, to, 5., routeColor);
		
		system = next;
	}
	
	DrawKey();
	DrawSelectedSystem();
	Point pos = DrawPanel(
		Screen::TopLeft() + Point(0., -availableScroll),
		"Missions available here:",
		available.size());
	DrawList(available, pos);
	
	pos = DrawPanel(
		Screen::TopRight() + Point(-SIDE_WIDTH, -acceptedScroll),
		"Your current missions:",
		AcceptedVisible());
	DrawList(accepted, pos);
	
	DrawMissionInfo();
	
	const Set<Color> &colors = GameData::Colors();
	const Color &availableColor = *colors.Get("available back");
	const Color &unavailableColor = *colors.Get("unavailable back");
	const Color &currentColor = *colors.Get("active back");
	const Color &blockedColor = *colors.Get("blocked back");
	if(availableIt != available.end() && availableIt->Destination())
		DrawMissionSystem(*availableIt, CanAccept() ? availableColor : unavailableColor);
	if(acceptedIt != accepted.end() && acceptedIt->Destination())
		DrawMissionSystem(*acceptedIt, IsSatisfied(*acceptedIt) ? currentColor : blockedColor);
	
	// Draw the buttons to switch to other map modes.
	Information info;
	info.SetCondition("is missions");
	if(ZoomIsMax())
		info.SetCondition("max zoom");
	if(ZoomIsMin())
		info.SetCondition("min zoom");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info);
}
예제 #3
0
void MapSalesPanel::DrawButtons() const
{
	Information info;
	info.SetCondition(isOutfitters ? "is outfitters" : "is shipyards");
	if(ZoomIsMax())
		info.SetCondition("max zoom");
	if(ZoomIsMin())
		info.SetCondition("min zoom");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info);
}
예제 #4
0
void InfoPanel::Draw() const
{
	DrawBackdrop();
	
	Information interfaceInfo;
	if(showShip)
	{
		interfaceInfo.SetCondition("ship tab");
		if(canEdit && (shipIt != player.Ships().end())
					&& ((shipIt->get() != player.Flagship() && !(*shipIt)->IsDisabled()) || (*shipIt)->IsParked()))
			interfaceInfo.SetCondition((*shipIt)->IsParked() ? "show unpark" : "show park");
		else if(!canEdit)
			interfaceInfo.SetCondition(CanDump() ? "enable dump" : "show dump");
		if(player.Ships().size() > 1)
			interfaceInfo.SetCondition("four buttons");
		else
			interfaceInfo.SetCondition("two buttons");
	}
	else
	{
		interfaceInfo.SetCondition("player tab");
		if(canEdit && player.Ships().size() > 1)
		{
			bool allParked = true;
			bool hasOtherShips = false;
			const Ship *flagship = player.Flagship();
			for(const auto &it : player.Ships())
				if(!it->IsDisabled() && it.get() != flagship)
				{
					allParked &= it->IsParked();
					hasOtherShips = true;
				}
			if(hasOtherShips)
				interfaceInfo.SetCondition(allParked ? "show unpark all" : "show park all");
			
			if(!allSelected.empty())
			{
				allParked = true;
				for(int i : allSelected)
				{
					const Ship &ship = *player.Ships()[i];
					if(!ship.IsDisabled() && &ship != flagship)
						allParked &= ship.IsParked();
				}
				interfaceInfo.SetCondition(allParked ? "show unpark" : "show park");
			}
		}
		interfaceInfo.SetCondition("two buttons");
	}
	const Interface *interface = GameData::Interfaces().Get("info panel");
	interface->Draw(interfaceInfo);
	
	zones.clear();
	commodityZones.clear();
	if(showShip)
		DrawShip();
	else
		DrawInfo();
}
예제 #5
0
void MissionPanel::DrawMissionInfo() const
{
	Information info;
	
	// The "accept / abort" button text and activation depends on what mission,
	// if any, is selected, and whether missions are available.
	if(CanAccept())
		info.SetCondition("can accept");
	else if(acceptedIt != accepted.end())
		info.SetCondition("can abort");
	else if(available.size())
		info.SetCondition("cannot accept");
	else
		info.SetCondition("cannot abort");
	
	int cargoFree = -player.Cargo().Used();
	int bunksFree = -player.Cargo().Passengers();
	for(const shared_ptr<Ship> &ship : player.Ships())
		if(ship->GetSystem() == player.GetSystem() && !ship->IsDisabled() && !ship->IsParked())
		{
			cargoFree += ship->Attributes().Get("cargo space") - ship->Cargo().Used();
			int crew = (ship.get() == player.Flagship()) ? ship->Crew() : ship->RequiredCrew();
			bunksFree += ship->Attributes().Get("bunks") - crew - ship->Cargo().Passengers();
		}
	info.SetString("cargo free", to_string(cargoFree) + " tons");
	info.SetString("bunks free", to_string(bunksFree) + " bunks");
	
	info.SetString("today", player.GetDate().ToString());
	
	const Interface *interface = GameData::Interfaces().Get("mission");
	interface->Draw(info);
	
	// If a mission is selected, draw its descriptive text.
	if(availableIt != available.end())
		wrap.Wrap(availableIt->Description());
	else if(acceptedIt != accepted.end())
		wrap.Wrap(acceptedIt->Description());
	else
		return;
	wrap.Draw(Point(-190., Screen::Bottom() - 213.), *GameData::Colors().Get("bright"));
}
예제 #6
0
void ShipInfoPanel::Draw()
{
	// Dim everything behind this panel.
	DrawBackdrop();
	
	// Fill in the information for how this interface should be drawn.
	Information interfaceInfo;
	interfaceInfo.SetCondition("ship tab");
	if(canEdit && (shipIt != player.Ships().end())
			&& (shipIt->get() != player.Flagship() || (*shipIt)->IsParked()))
	{
		if(!(*shipIt)->IsDisabled())
			interfaceInfo.SetCondition("can park");
		interfaceInfo.SetCondition((*shipIt)->IsParked() ? "show unpark" : "show park");
		interfaceInfo.SetCondition("show disown");
	}
	else if(!canEdit)
	{
		interfaceInfo.SetCondition("show dump");
		if(CanDump())
			interfaceInfo.SetCondition("enable dump");
	}
	if(player.Ships().size() > 1)
		interfaceInfo.SetCondition("five buttons");
	else
		interfaceInfo.SetCondition("three buttons");
	if(player.HasLogs())
		interfaceInfo.SetCondition("enable logbook");
	
	// Draw the interface.
	const Interface *interface = GameData::Interfaces().Get("info panel");
	interface->Draw(interfaceInfo, this);
	
	// Draw all the different information sections.
	zones.clear();
	commodityZones.clear();
	plunderZones.clear();
	Rectangle cargoBounds = interface->GetBox("cargo");
	DrawShipStats(interface->GetBox("stats"));
	DrawOutfits(interface->GetBox("outfits"), cargoBounds);
	DrawWeapons(interface->GetBox("weapons"));
	DrawCargo(cargoBounds);
	
	// If the player hovers their mouse over a ship attribute, show its tooltip.
	info.DrawTooltips();
}
예제 #7
0
void PlanetPanel::Draw()
{
	if(player.IsDead())
		return;
	
	const Ship *flagship = player.Flagship();
	
	Information info;
	info.SetSprite("land", planet.Landscape());
	bool hasAccess = planet.CanUseServices();
	bool hasShip = false;
	for(const auto &it : player.Ships())
		if(it->GetSystem() == player.GetSystem() && !it->IsDisabled())
		{
			hasShip = true;
			break;
		}
	if(flagship && flagship->CanBeFlagship())
		info.SetCondition("has ship");
	if(planet.IsInhabited() && hasAccess)
		info.SetCondition("has bank");
	if(flagship && planet.IsInhabited() && hasAccess)
		info.SetCondition("is inhabited");
	if(flagship && planet.HasSpaceport() && hasAccess)
		info.SetCondition("has spaceport");
	if(planet.HasShipyard() && hasAccess)
		info.SetCondition("has shipyard");
	if(hasShip && planet.HasOutfitter() && hasAccess)
		info.SetCondition("has outfitter");
	
	ui.Draw(info, this);
	
	if(!selectedPanel)
		text.Draw(Point(-300., 80.), *GameData::Colors().Get("bright"));
}
예제 #8
0
void HailPanel::Draw() const
{
	DrawBackdrop();
	
	Information interfaceInfo;
	interfaceInfo.SetString("header", header);
	if(ship)
	{
		bool isEnemy = ship->GetGovernment()->IsEnemy();
		if(isEnemy)
		{
			interfaceInfo.SetCondition("can bribe");
			interfaceInfo.SetCondition("cannot assist");
		}
		else
			interfaceInfo.SetCondition("can assist");
	}
	else
	{
		if(!planet->CanLand())
			interfaceInfo.SetCondition("can bribe");
		else
			interfaceInfo.SetCondition("cannot bribe");
		
		interfaceInfo.SetCondition("can dominate");
	}
	
	const Interface *interface = GameData::Interfaces().Get("hail panel");
	interface->Draw(interfaceInfo);
	
	// Draw the sprite, rotated, scaled, and swizzled as necessary.
	int swizzle = ship ? ship->GetGovernment()->GetSwizzle() : 0;
	uint32_t tex = sprite->Texture();
	
	float pos[2] = {-170.f, -10.f};
	
	double zoom = min(1., 200. / max(sprite->Width(), sprite->Height()));
	Point uw = unit * (sprite->Width() * zoom);
	Point uh = unit * (sprite->Height() * zoom);
	float tr[4] = {
		static_cast<float>(-uw.Y()), static_cast<float>(uw.X()),
		static_cast<float>(-uh.X()), static_cast<float>(-uh.Y())};
	
	SpriteShader::Bind();
	SpriteShader::Add(tex, tex, pos, tr, swizzle);
	SpriteShader::Unbind();
	
	// Draw the current message.
	WrappedText wrap;
	wrap.SetAlignment(WrappedText::JUSTIFIED);
	wrap.SetWrapWidth(330);
	wrap.SetFont(FontSet::Get(14));
	wrap.Wrap(message);
	wrap.Draw(Point(-50., -50.), *GameData::Colors().Get("medium"));
}
예제 #9
0
void InfoPanel::Draw() const
{
	DrawBackdrop();
	
	Information interfaceInfo;
	if(showShip)
	{
		interfaceInfo.SetCondition("ship tab");
		if(canEdit && shipIt != player.Ships().begin())
			interfaceInfo.SetCondition((*shipIt)->IsParked() ? "show unpark" : "show park");
		if(player.Ships().size() > 1)
			interfaceInfo.SetCondition("four buttons");
		else
			interfaceInfo.SetCondition("two buttons");
	}
	else
	{
		interfaceInfo.SetCondition("player tab");
		if(canEdit && player.Ships().size() > 1)
		{
			bool allParked = true;
			bool hasOtherShips = false;
			auto it = player.Ships().begin() + 1;
			for( ; it != player.Ships().end(); ++it)
				if(!(*it)->IsDisabled())
				{
					allParked &= (*it)->IsParked();
					hasOtherShips = true;
				}
			
			if(hasOtherShips)
				interfaceInfo.SetCondition(allParked ? "show unpark all" : "show park all");
		}
		interfaceInfo.SetCondition("two buttons");
	}
	const Interface *interface = GameData::Interfaces().Get("info panel");
	interface->Draw(interfaceInfo);
	
	zones.clear();
	if(showShip)
		DrawShip();
	else
		DrawInfo();
}
예제 #10
0
void MapShipyardPanel::Draw() const
{
	MapPanel::Draw();
	
	DrawPanel();
	DrawItems();
	
	Information info;
	info.SetCondition("is shipyards");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info);
	
	if(selected)
	{
		ShipInfoDisplay infoDisplay(*selected);
		
		Color back(.125, 1.);
		Point size(infoDisplay.PanelWidth(), infoDisplay.AttributesHeight());
		Point topLeft(Screen::Right() - size.X(), Screen::Top());
		FillShader::Fill(topLeft + .5 * size, size, back);
		
		const Sprite *left = SpriteSet::Get("ui/left edge");
		const Sprite *bottom = SpriteSet::Get("ui/bottom edge");
		Point leftPos = topLeft + Point(
			-.5 * left->Width(),
			size.Y() - .5 * left->Height());
		SpriteShader::Draw(left, leftPos);
		// The top left corner of the bottom sprite should be 10 x units right
		// of the bottom left corner of the left edge sprite.
		Point bottomPos = leftPos + Point(
			10. + .5 * (bottom->Width() - left->Width()),
			.5 * (left->Height() + bottom->Height()));
		SpriteShader::Draw(bottom, bottomPos);
		
		infoDisplay.DrawAttributes(topLeft);
	}
}
예제 #11
0
void BankPanel::Draw() const
{
	Table table;
	table.AddColumn(TYPE_X, Table::LEFT);
	table.AddColumn(PRINCIPAL_X, Table::LEFT);
	table.AddColumn(INTEREST_X, Table::LEFT);
	table.AddColumn(TERM_X, Table::LEFT);
	table.AddColumn(PAYMENT_X, Table::LEFT);
	table.AddColumn(170, Table::RIGHT);
	table.SetHighlight(-300, 180);
	table.DrawAt(Point(0., FIRST_Y));
	
	Color back = *GameData::Colors().Get("faint");
	Color unselected = *GameData::Colors().Get("medium");
	Color selected = *GameData::Colors().Get("bright");
	table.DrawUnderline(unselected);
	table.SetColor(selected);
	for(int i = 0; i < 6; ++i)
		table.Draw(HEADING[i]);
	table.DrawGap(5);
	
	// Figure out the total payments and principal (other than salaries). This
	// is in case there are more mortgages than can be displayed.
	int otherPrincipal = 0;
	int otherPayment = 0;
	for(const Mortgage &mortgage : player.Accounts().Mortgages())
	{
		otherPrincipal += mortgage.Principal();
		otherPayment += mortgage.Payment();
	}
	int totalPayment = otherPayment;
	
	// Check if salaries need to be drawn.
	int salaries = player.Salaries();
	
	int row = 0;
	for(const Mortgage &mortgage : player.Accounts().Mortgages())
	{
		if(row == selectedRow)
		{
			table.DrawHighlight(back);
			table.SetColor(selected);
		}
		else
			table.SetColor(unselected);
		
		// There is room for seven rows if including salaries, or 8 if not.
		if(row == (6 + !salaries) && otherPrincipal != mortgage.Principal())
		{
			table.Draw("Other", unselected);
			table.Draw(otherPrincipal);
			table.Advance(2);
			table.Draw(otherPayment);
		}
		else
		{
			table.Draw(mortgage.Type());
			table.Draw(mortgage.Principal());
			table.Draw(mortgage.Interest());
			table.Draw(mortgage.Term());
			table.Draw(mortgage.Payment());
			
			otherPrincipal -= mortgage.Principal();
			otherPayment -= mortgage.Payment();
		}
		table.Draw("[pay extra]");
		++row;
		
		// Draw no more than 8 rows, counting the salaries row if any.
		if(row == 7 + !salaries)
			break;
	}
	table.SetColor(unselected);
	// Draw the salaries, if necessary.
	if(salaries)
	{
		totalPayment += salaries;
		
		table.Draw("Crew Salaries", unselected);
		table.Advance(3);
		table.Draw(salaries);
		table.Advance();
	}
	
	table.Advance(3);
	table.Draw("total:", selected);
	table.Draw(totalPayment, unselected);
	table.Advance();
	
	table.DrawAt(Point(0., FIRST_Y + 210.));
	string credit = "Your credit score is " + to_string(player.Accounts().CreditScore()) + ".";
	table.Draw(credit);
	table.Advance(5);
	
	string amount;
	if(!qualify)
		amount = "You do not qualify for further loans at this time.";
	else
		amount = "You qualify for a new loan of up to " + Format::Number(qualify) + " credits.";
	bool isSelected = qualify && (selectedRow > (6 + !salaries)
		|| static_cast<unsigned>(selectedRow) >= player.Accounts().Mortgages().size());
	if(isSelected)
		table.DrawHighlight(back);
	table.Draw(amount, unselected);
	if(qualify)
	{
		table.Advance(4);
		table.Draw("[apply]", selected);
	}
	
	const Interface *interface = GameData::Interfaces().Get("bank");
	Information info;
	for(const Mortgage &mortgage : player.Accounts().Mortgages())
		if(mortgage.Principal() <= player.Accounts().Credits())
			info.SetCondition("can pay");
	interface->Draw(info);
}
예제 #12
0
// Draw the panel.
void BoardingPanel::Draw() const
{
	// Draw a translucent black scrim over everything beneath this panel.
	DrawBackdrop();
	
	// Draw the list of plunder.
	Color opaque(.1, 1.);
	Color back = *GameData::Colors().Get("faint");
	Color dim = *GameData::Colors().Get("dim");
	Color medium = *GameData::Colors().Get("medium");
	Color bright = *GameData::Colors().Get("bright");
	FillShader::Fill(Point(-155., -60.), Point(360., 250.), opaque);
	
	int index = (scroll - 10) / 20;
	int y = -170 - scroll + 20 * index;
	int endY = 60;
	
	const Font &font = FontSet::Get(14);
	// Y offset to center the text in a 20-pixel high row.
	double fontOff = .5 * (20 - font.Height());
	int freeSpace = you->Cargo().Free();
	for( ; y < endY && static_cast<unsigned>(index) < plunder.size(); y += 20, ++index)
	{
		const Plunder &item = plunder[index];
		
		// Check if this is the selected row.
		bool isSelected = (index == selected);
		if(isSelected)
			FillShader::Fill(Point(-155., y + 10.), Point(360., 20.), back);
		
		// Color the item based on whether you have space for it.
		const Color &color = item.CanTake(freeSpace) ? isSelected ? bright : medium : dim;
		Point pos(-320., y + fontOff);
		font.Draw(item.Name(), pos, color);
		
		Point valuePos(pos.X() + 260. - font.Width(item.Value()), pos.Y());
		font.Draw(item.Value(), valuePos, color);
		
		Point sizePos(pos.X() + 330. - font.Width(item.Size()), pos.Y());
		font.Draw(item.Size(), sizePos, color);
	}
	
	// Set which buttons are active.
	Information info;
	if(CanExit())
		info.SetCondition("can exit");
	if(CanTake())
		info.SetCondition("can take");
	if(CanCapture())
		info.SetCondition("can capture");
	if(CanAttack() && (you->Crew() > 1 || !victim->RequiredCrew()))
		info.SetCondition("can attack");
	if(CanAttack())
		info.SetCondition("can defend");
	
	// This should always be true, but double check.
	int crew = 0;
	if(you)
	{
		crew = you->Crew();
		info.SetString("cargo space", to_string(freeSpace));
		info.SetString("your crew", to_string(crew));
		info.SetString("your attack",
			Round(attackOdds.AttackerPower(crew)));
		info.SetString("your defense",
			Round(defenseOdds.DefenderPower(crew)));
	}
	if(victim->IsCapturable())
	{
		int vCrew = victim->Crew();
		info.SetString("enemy crew", to_string(vCrew));
		info.SetString("enemy attack",
			Round(defenseOdds.AttackerPower(vCrew)));
		info.SetString("enemy defense",
			Round(attackOdds.DefenderPower(vCrew)));
	
		info.SetString("attack odds",
			Round(100. * attackOdds.Odds(crew, vCrew)) + "%");
		info.SetString("attack casualties",
			Round(attackOdds.AttackerCasualties(crew, vCrew)));
		info.SetString("defense odds",
			Round(100. * (1. - defenseOdds.Odds(vCrew, crew))) + "%");
		info.SetString("defense casualties",
			Round(defenseOdds.DefenderCasualties(vCrew, crew)));
	}
	
	const Interface *interface = GameData::Interfaces().Get("boarding");
	interface->Draw(info);
	
	// Draw the status messages from hand to hand combat.
	Point messagePos(50., 55.);
	for(const string &message : messages)
	{
		font.Draw(message, messagePos, bright);
		messagePos.Y() += 20.;
	}
}
예제 #13
0
void TradingPanel::Draw()
{
	Color back = *GameData::Colors().Get("faint");
	int selectedRow = player.MapColoring();
	if(selectedRow >= 0 && selectedRow < COMMODITY_COUNT)
		FillShader::Fill(Point(-60., FIRST_Y + 20 * selectedRow + 33), Point(480., 20.), back);
	
	const Font &font = FontSet::Get(14);
	Color unselected = *GameData::Colors().Get("medium");
	Color selected = *GameData::Colors().Get("bright");
	
	int y = FIRST_Y;
	FillShader::Fill(Point(-60., y + 15.), Point(480., 1.), unselected);
	
	font.Draw("Commodity", Point(NAME_X, y), selected);
	font.Draw("Price", Point(PRICE_X, y), selected);
	
	string mod = "x " + to_string(Modifier());
	font.Draw(mod, Point(BUY_X, y), unselected);
	font.Draw(mod, Point(SELL_X, y), unselected);
	
	font.Draw("In Hold", Point(HOLD_X, y), selected);
	
	y += 5;
	int lastY = y + 20 * COMMODITY_COUNT + 25;
	font.Draw("free:", Point(SELL_X + 5, lastY), selected);
	font.Draw(to_string(player.Cargo().Free()), Point(HOLD_X, lastY), selected);
	
	int outfits = player.Cargo().OutfitsSize();
	int missionCargo = player.Cargo().MissionCargoSize();
	sellOutfits = false;
	if(player.Cargo().HasOutfits() || missionCargo)
	{
		bool hasOutfits = false;
		bool hasHarvested = false;
		for(const auto &it : player.Cargo().Outfits())
			if(it.second)
			{
				bool isHarvested = (it.first->Get("installable") < 0.);
				(isHarvested ? hasHarvested : hasOutfits) = true;
			}
		sellOutfits = (hasOutfits && !hasHarvested);
		
		string str = to_string(outfits + missionCargo);
		if(hasHarvested && missionCargo)
			str += " tons of mission cargo and other items.";
		else if(hasOutfits && missionCargo)
			str += " tons of outfits and mission cargo.";
		else if(hasOutfits && hasHarvested)
			str += " tons of outfits and harvested materials.";
		else if(hasOutfits)
			str += " tons of outfits.";
		else if(hasHarvested)
			str += " tons of harvested materials.";
		else
			str += " tons of mission cargo.";
		font.Draw(str, Point(NAME_X, lastY), unselected);
	}
	
	int i = 0;
	bool canSell = false;
	for(const Trade::Commodity &commodity : GameData::Commodities())
	{
		y += 20;
		int price = system.Trade(commodity.name);
		
		const Color &color = (i++ == selectedRow ? selected : unselected);
		font.Draw(commodity.name, Point(NAME_X, y), color);
		
		if(price)
		{
			font.Draw(to_string(price), Point(PRICE_X, y), color);
		
			int basis = player.GetBasis(commodity.name);
			if(basis && basis != price)
			{
				string profit = "(profit: " + to_string(price - basis) + ")";
				font.Draw(profit, Point(LEVEL_X, y), color);
			}
			else
			{
				int level = (price - commodity.low);
				if(level < 0)
					level = 0;
				else if(level >= (commodity.high - commodity.low))
					level = 4;
				else
					level = (5 * level) / (commodity.high - commodity.low);
				font.Draw(TRADE_LEVEL[level], Point(LEVEL_X, y), color);
			}
		
			font.Draw("[buy]", Point(BUY_X, y), color);
			font.Draw("[sell]", Point(SELL_X, y), color);
		}
		
		int hold = player.Cargo().Get(commodity.name);
		if(hold)
		{
			sellOutfits = false;
			canSell |= (price != 0);
			font.Draw(to_string(hold), Point(HOLD_X, y), selected);
		}
	}
	
	const Interface *interface = GameData::Interfaces().Get("trade");
	Information info;
	if(sellOutfits)
		info.SetCondition("can sell outfits");
	else if(player.Cargo().HasOutfits() || canSell)
		info.SetCondition("can sell");
	if(player.Cargo().Free() > 0)
		info.SetCondition("can buy");
	interface->Draw(info, this);
}
예제 #14
0
void LoadPanel::Draw() const
{
	glClear(GL_COLOR_BUFFER_BIT);
	GameData::Background().Draw(Point(), Point());
	
	Information info;
	if(loadedInfo.IsLoaded())
	{
		info.SetString("pilot", loadedInfo.Name());
		if(loadedInfo.ShipSprite())
		{
			info.SetSprite("ship sprite", loadedInfo.ShipSprite());
			info.SetString("ship", loadedInfo.ShipName());
		}
		if(!loadedInfo.GetSystem().empty())
			info.SetString("system", loadedInfo.GetSystem());
		if(!loadedInfo.GetPlanet().empty())
			info.SetString("planet", loadedInfo.GetPlanet());
		info.SetString("credits", loadedInfo.Credits());
		info.SetString("date", loadedInfo.GetDate());
	}
	else
		info.SetString("pilot", "No Pilot Loaded");
	
	if(!selectedPilot.empty())
		info.SetCondition("pilot selected");
	if(selectedFile.find('~') != string::npos)
		info.SetCondition("snapshot selected");
	if(loadedInfo.IsLoaded())
		info.SetCondition("pilot loaded");
	
	const Interface *menu = GameData::Interfaces().Get("load menu");
	menu->Draw(info);
	
	const Font &font = FontSet::Get(14);
	
	// The list has space for 14 entries. Alpha should be 100% for Y = -157 to
	// 103, and fade to 0 at 10 pixels beyond that.
	Point point(-470., -157. - sideScroll);
	for(const auto &it : files)
	{
		double alpha = min(1., max(0., min(.1 * (113. - point.Y()), .1 * (point.Y() - -167.))));
		if(it.first == selectedPilot)
			FillShader::Fill(point + Point(110., 7.), Point(230., 20.), Color(.1 * alpha, 0.));
		font.Draw(it.first, point, Color(.5 * alpha, 0.));
		point += Point(0., 20.);
	}
	
	if(!selectedPilot.empty() && files.find(selectedPilot) != files.end())
	{
		point = Point(-110., -157. - centerScroll);
		for(const string &file : files.find(selectedPilot)->second)
		{
			double alpha = min(1., max(0., min(.1 * (113. - point.Y()), .1 * (point.Y() - -167.))));
			if(file == selectedFile)
				FillShader::Fill(point + Point(110., 7.), Point(230., 20.), Color(.1 * alpha, 0.));
			size_t pos = file.find('~') + 1;
			string name = file.substr(pos, file.size() - 4 - pos);
			font.Draw(name, point, Color(.5 * alpha, 0.));
			point += Point(0., 20.);
		}
	}
}
예제 #15
0
void MenuPanel::Draw() const
{
	glClear(GL_COLOR_BUFFER_BIT);
	GameData::Background().Draw(Point(), Point());
	
	Information info;
	if(player.IsLoaded() && !player.IsDead())
	{
		info.SetCondition("pilot loaded");
		info.SetString("pilot", player.FirstName() + " " + player.LastName());
		if(player.Flagship())
		{
			const Ship &flagship = *player.Flagship();
			info.SetSprite("ship sprite", flagship.GetSprite());
			info.SetString("ship", flagship.Name());
		}
		if(player.GetSystem())
			info.SetString("system", player.GetSystem()->Name());
		if(player.GetPlanet())
			info.SetString("planet", player.GetPlanet()->Name());
		info.SetString("credits", Format::Number(player.Accounts().Credits()));
		info.SetString("date", player.GetDate().ToString());
	}
	else if(player.IsLoaded())
	{
		info.SetCondition("no pilot loaded");
		info.SetString("pilot", player.FirstName() + " " + player.LastName());
		info.SetString("ship", "You have died.");
	}
	else
	{
		info.SetCondition("no pilot loaded");
		info.SetString("pilot", "No Pilot Loaded");
	}
	
	const Interface *menu = GameData::Interfaces().Get("main menu");
	menu->Draw(info);
	
	if(progress == 60)
		alpha -= .02f;
	if(alpha > 0.f)
	{
		Angle da(6.);
		Angle a(0.);
		for(int i = 0; i < progress; ++i)
		{
			Color color(.5 * alpha, 0.f);
			PointerShader::Draw(Point(), a.Unit(), 8., 20., 140. * alpha, color);
			a += da;
		}
	}
	
	const Font &font = FontSet::Get(14);
	int y = 120 - scroll / scrollSpeed;
	for(const string &line : credits)
	{
		float fade = 1.f;
		if(y < -145)
			fade = max(0.f, (y + 165) / 20.f);
		else if(y > 95)
			fade = max(0.f, (115 - y) / 20.f);
		if(fade)
		{
			Color color(((line.empty() || line[0] == ' ') ? .2 : .4) * fade, 0.);
			font.Draw(line, Point(-470., y), color);
		}
		y += 20;
	}
}
예제 #16
0
void LoadPanel::Draw()
{
	glClear(GL_COLOR_BUFFER_BIT);
	GameData::Background().Draw(Point(), Point());
	const Font &font = FontSet::Get(14);
	
	Information info;
	if(loadedInfo.IsLoaded())
	{
		info.SetString("pilot", font.TruncateMiddle(loadedInfo.Name(), 165));
		if(loadedInfo.ShipSprite())
		{
			info.SetSprite("ship sprite", loadedInfo.ShipSprite());
			info.SetString("ship", font.TruncateMiddle(loadedInfo.ShipName(), 165));
		}
		if(!loadedInfo.GetSystem().empty())
			info.SetString("system", loadedInfo.GetSystem());
		if(!loadedInfo.GetPlanet().empty())
			info.SetString("planet", loadedInfo.GetPlanet());
		info.SetString("credits", loadedInfo.Credits());
		info.SetString("date", loadedInfo.GetDate());
	}
	else
		info.SetString("pilot", "No Pilot Loaded");
	
	if(!selectedPilot.empty())
		info.SetCondition("pilot selected");
	if(!player.IsDead() && player.IsLoaded() && !selectedPilot.empty())
		info.SetCondition("pilot alive");
	if(selectedFile.find('~') != string::npos)
		info.SetCondition("snapshot selected");
	if(loadedInfo.IsLoaded())
		info.SetCondition("pilot loaded");
	
	GameData::Interfaces().Get("menu background")->Draw(info, this);
	GameData::Interfaces().Get("load menu")->Draw(info, this);
	GameData::Interfaces().Get("menu player info")->Draw(info, this);
	
	// The list has space for 14 entries. Alpha should be 100% for Y = -157 to
	// 103, and fade to 0 at 10 pixels beyond that.
	Point point(-470., -157. - sideScroll);
	for(const auto &it : files)
	{
		Rectangle zone(point + Point(110., 7.), Point(230., 20.));
		bool isHighlighted = (it.first == selectedPilot || (hasHover && zone.Contains(hoverPoint)));
		
		double alpha = min(1., max(0., min(.1 * (113. - point.Y()), .1 * (point.Y() - -167.))));
		if(it.first == selectedPilot)
			FillShader::Fill(zone.Center(), zone.Dimensions(), Color(.1 * alpha, 0.));
		string name = font.Truncate(it.first, 220);
		font.Draw(name, point, Color((isHighlighted ? .7 : .5) * alpha, 0.));
		point += Point(0., 20.);
	}
	
	// The hover count "decays" over time if not hovering over a saved game.
	if(hoverCount)
		--hoverCount;
	string hoverText;
	
	if(!selectedPilot.empty() && files.count(selectedPilot))
	{
		point = Point(-110., -157. - centerScroll);
		for(const auto &it : files.find(selectedPilot)->second)
		{
			const string &file = it.first;
			Rectangle zone(point + Point(110., 7.), Point(230., 20.));
			double alpha = min(1., max(0., min(.1 * (113. - point.Y()), .1 * (point.Y() - -167.))));
			bool isHovering = (alpha && hasHover && zone.Contains(hoverPoint));
			bool isHighlighted = (file == selectedFile || isHovering);
			if(isHovering)
			{
				hoverCount = min(HOVER_TIME, hoverCount + 2);
				if(hoverCount == HOVER_TIME)
					hoverText = TimestampString(it.second);
			}
			
			if(file == selectedFile)
				FillShader::Fill(zone.Center(), zone.Dimensions(), Color(.1 * alpha, 0.));
			size_t pos = file.find('~') + 1;
			string name = font.Truncate(file.substr(pos, file.size() - 4 - pos), 220);
			font.Draw(name, point, Color((isHighlighted ? .7 : .5) * alpha, 0.));
			point += Point(0., 20.);
		}
	}
	if(!hoverText.empty())
	{
		Point boxSize(font.Width(hoverText) + 20., 30.);
		
		FillShader::Fill(hoverPoint + .5 * boxSize, boxSize, *GameData::Colors().Get("tooltip background"));
		font.Draw(hoverText, hoverPoint + Point(10., 10.), *GameData::Colors().Get("medium"));
	}
}
예제 #17
0
void MapOutfitterPanel::Draw() const
{
	MapPanel::Draw();
	
	DrawPanel();
	DrawItems();
	
	Information info;
	info.SetCondition("is outfitters");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info);
	

	if(selected and !compare)
	{
		OutfitInfoDisplay infoDisplay(*selected);
		
		Color back(.125, 1.);
		Point size(infoDisplay.PanelWidth(), infoDisplay.AttributesHeight());
		Point topLeft(Screen::Right() - size.X(), Screen::Top());
		FillShader::Fill(topLeft + .5 * size, size, back);
		
		const Sprite *left = SpriteSet::Get("ui/left edge");
		const Sprite *bottom = SpriteSet::Get("ui/bottom edge");
		Point leftPos = topLeft + Point(
			-.5 * left->Width(),
			size.Y() - .5 * left->Height());
		SpriteShader::Draw(left, leftPos);
		// The top left corner of the bottom sprite should be 10 x units right
		// of the bottom left corner of the left edge sprite.
		Point bottomPos = leftPos + Point(
			10. + .5 * (bottom->Width() - left->Width()),
			.5 * (left->Height() + bottom->Height()));
		SpriteShader::Draw(bottom, bottomPos);
		infoDisplay.DrawAttributes(topLeft + Point(0., 10.), false);
	}
	else if (selected)
	{
		OutfitInfoDisplay infoDisplay(*selected, *compare);
		
		Color back(.125, 1.);
		Point size(infoDisplay.PanelWidth(), infoDisplay.AttributesHeight());
		Point topLeft(Screen::Right() - size.X(), Screen::Top());
		
		Point fillCenter(topLeft + 0.5 * size);
		fillCenter = fillCenter + Point(-0.5 * size. X(), 0.);
		
		FillShader::Fill(fillCenter, Point(2 * size.X(), size.Y()), back);
		
		const Sprite *left = SpriteSet::Get("ui/left edge");
		const Sprite *bottom = SpriteSet::Get("ui/bottom edge");
		const Sprite *bottom2 = SpriteSet::Get("ui/bottom edge");

		Point leftPos = topLeft + Point(
										-.5 * left->Width(),
										size.Y() - .5 * left->Height());
		SpriteShader::Draw(left, leftPos + Point(-size.X(), 0));
		
		// The top left corner of the bottom sprite should be 10 x units right
		// of the bottom left corner of the left edge sprite.
		Point bottomPos = leftPos + Point(
										  10. + .5 * (bottom->Width() - left->Width()),
										  .5 * (left->Height() + bottom->Height()));
		SpriteShader::Draw(bottom, bottomPos);
		
		
		SpriteShader::Draw(bottom2, bottomPos + Point(-size.X(), 0));
		infoDisplay.DrawAttributes(topLeft + Point(0., 10.), true);
	}
}
예제 #18
0
void MapShipyardPanel::Draw() const
{
	MapPanel::Draw();
	
	DrawKey();
	DrawPanel();
	DrawItems();
	
	Information info;
	info.SetCondition("is shipyards");
	if(ZoomIsMax())
		info.SetCondition("max zoom");
	if(ZoomIsMin())
		info.SetCondition("min zoom");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info);
	
	if(selected)
	{
		ShipInfoDisplay infoDisplay(*selected);
		ShipInfoDisplay compareDisplay;
		if(compare)
			compareDisplay.Update(*compare);
		int infoHeight = max(infoDisplay.AttributesHeight(), 120);
		int compareHeight = compare ? max(compareDisplay.AttributesHeight(), 120) : 0;
		
		Color back(.125, 1.);
		Point size(infoDisplay.PanelWidth(), infoHeight + compareHeight);
		Point topLeft(Screen::Right() - size.X(), Screen::Top());
		FillShader::Fill(topLeft + .5 * size, size, back);
		
		const Sprite *left = SpriteSet::Get("ui/left edge");
		const Sprite *bottom = SpriteSet::Get("ui/bottom edge");
		const Sprite *box = SpriteSet::Get("ui/thumb box");
		Point leftPos = topLeft + Point(
			-.5 * left->Width(),
			size.Y() - .5 * left->Height());
		SpriteShader::Draw(left, leftPos);
		// The top left corner of the bottom sprite should be 10 x units right
		// of the bottom left corner of the left edge sprite.
		Point bottomPos = leftPos + Point(
			10. + .5 * (bottom->Width() - left->Width()),
			.5 * (left->Height() + bottom->Height()));
		SpriteShader::Draw(bottom, bottomPos);
		
		Point iconOffset(-.5 * ICON_HEIGHT, .5 * ICON_HEIGHT);
		const Sprite *sprite = selected->GetSprite().GetSprite();
		int swizzle = GameData::PlayerGovernment()->GetSwizzle();
		if(sprite)
		{
			double scale = min(.5, ICON_HEIGHT / sprite->Height());
			SpriteShader::Draw(box, topLeft + iconOffset + Point(-15., 5.));
			SpriteShader::Draw(sprite, topLeft + iconOffset + Point(0., 5.), scale, swizzle);
		}
		infoDisplay.DrawAttributes(topLeft);
		
		if(compare)
		{
			topLeft.Y() += infoHeight;
			
			sprite = compare->GetSprite().GetSprite();
			if(sprite)
			{
				double scale = min(.5, ICON_HEIGHT / sprite->Height());
				SpriteShader::Draw(box, topLeft + iconOffset + Point(-15., 5.));
				SpriteShader::Draw(sprite, topLeft + iconOffset + Point(0., 5.), scale, swizzle);
			}
			
			Color line(.5);
			size.Y() = 1.;
			FillShader::Fill(topLeft + .5 * size - Point(0., 1.), size, line);
			compareDisplay.DrawAttributes(topLeft + Point(0., 10.));
		}
	}
}
예제 #19
0
void BoardingPanel::Draw() const
{
	DrawBackdrop();
	
	// Draw the list of plunder.
	Color opaque(.1, 1.);
	Color back = *GameData::Colors().Get("faint");
	Color dim = *GameData::Colors().Get("dim");
	Color medium = *GameData::Colors().Get("medium");
	Color bright = *GameData::Colors().Get("bright");
	FillShader::Fill(Point(-155., -60.), Point(360., 250.), opaque);
	
	int index = (scroll - 10) / 20;
	int y = -170 - scroll + 20 * index;
	int endY = 60;
	
	const Font &font = FontSet::Get(14);
	double fontOff = .5 * (20 - font.Height());
	int freeSpace = you->Cargo().Free();
	for( ; y < endY && static_cast<unsigned>(index) < plunder.size(); y += 20, ++index)
	{
		const Plunder &item = plunder[index];
		
		bool isSelected = (index == selected);
		if(isSelected)
			FillShader::Fill(Point(-155., y + 10.), Point(360., 20.), back);
		
		const Color &color = item.CanTake(freeSpace) ? isSelected ? bright : medium : dim;
		Point pos(-320., y + fontOff);
		font.Draw(item.Name(), pos, color);
		
		Point valuePos(pos.X() + 260. - font.Width(item.Value()), pos.Y());
		font.Draw(item.Value(), valuePos, color);
		
		Point sizePos(pos.X() + 330. - font.Width(item.Size()), pos.Y());
		font.Draw(item.Size(), sizePos, color);
	}
	
	Information info;
	if(CanExit())
		info.SetCondition("can exit");
	if(CanTake())
		info.SetCondition("can take");
	if(CanCapture())
		info.SetCondition("can capture");
	if(CanAttack() && you->Crew() > 1)
		info.SetCondition("can attack");
	if(CanAttack())
		info.SetCondition("can defend");
	
	// This should always be true, but double check.
	int crew = 0;
	if(you)
	{
		const Ship &ship = *you;
		crew = ship.Crew();
		info.SetString("cargo space", to_string(freeSpace));
		info.SetString("your crew", to_string(crew));
		info.SetString("your attack",
			Round(attackOdds.AttackerPower(crew)));
		info.SetString("your defense",
			Round(defenseOdds.DefenderPower(crew)));
	}
	int vCrew = victim->Crew();
	info.SetString("enemy crew", to_string(vCrew));
	info.SetString("enemy attack",
		Round(defenseOdds.AttackerPower(vCrew)));
	info.SetString("enemy defense",
		Round(attackOdds.DefenderPower(vCrew)));
	
	info.SetString("attack odds",
		Round(100. * attackOdds.Odds(crew, vCrew)) + "%");
	info.SetString("attack casualties",
		Round(attackOdds.AttackerCasualties(crew, vCrew)));
	info.SetString("defense odds",
		Round(100. * (1. - defenseOdds.Odds(vCrew, crew))) + "%");
	info.SetString("defense casualties",
		Round(defenseOdds.DefenderCasualties(vCrew, crew)));
	
	const Interface *interface = GameData::Interfaces().Get("boarding");
	interface->Draw(info);
	
	Point messagePos(50., 55.);
	for(const string &message : messages)
	{
		font.Draw(message, messagePos, bright);
		messagePos.Y() += 20.;
	}
}
예제 #20
0
void MapDetailPanel::DrawInfo() const
{
	Color dimColor(.1, 0.);
	Color closeColor(.6, .6);
	Color farColor(.3, .3);
	
	Point uiPoint(Screen::Left() + 100., Screen::Top() + 45.);
	
	// System sprite goes from 0 to 90.
	const Sprite *systemSprite = SpriteSet::Get("ui/map system");
	SpriteShader::Draw(systemSprite, uiPoint);
	
	const Font &font = FontSet::Get(14);
	string systemName = player.KnowsName(selectedSystem) ?
		selectedSystem->Name() : "Unexplored System";
	font.Draw(systemName, uiPoint + Point(-90., -7.), closeColor);
	
	governmentY = uiPoint.Y() + 10.;
	string gov = player.HasVisited(selectedSystem) ?
		selectedSystem->GetGovernment()->GetName() : "Unknown Government";
	font.Draw(gov, uiPoint + Point(-90., 13.), (commodity == SHOW_GOVERNMENT) ? closeColor : farColor);
	if(commodity == SHOW_GOVERNMENT)
		PointerShader::Draw(uiPoint + Point(-90., 20.), Point(1., 0.),
			10., 10., 0., closeColor);
	
	uiPoint.Y() += 115.;
	
	planetY.clear();
	if(player.HasVisited(selectedSystem))
	{
		set<const Planet *> shown;
		const Sprite *planetSprite = SpriteSet::Get("ui/map planet");
		for(const StellarObject &object : selectedSystem->Objects())
			if(object.GetPlanet())
			{
				// Allow the same "planet" to appear multiple times in one system.
				auto it = shown.find(object.GetPlanet());
				if(it != shown.end())
					continue;
				shown.insert(object.GetPlanet());
				
				SpriteShader::Draw(planetSprite, uiPoint);
				planetY[object.GetPlanet()] = uiPoint.Y() - 60;
			
				font.Draw(object.Name(),
					uiPoint + Point(-70., -52.),
					object.GetPlanet() == selectedPlanet ? closeColor : farColor);
				
				font.Draw("Space Port",
					uiPoint + Point(-60., -32.),
					object.GetPlanet()->HasSpaceport() ? closeColor : dimColor);
				
				font.Draw("Shipyard",
					uiPoint + Point(-60., -12.),
					object.GetPlanet()->HasShipyard() ? closeColor : dimColor);
				if(commodity == SHOW_SHIPYARD)
					PointerShader::Draw(uiPoint + Point(-60., -5.), Point(1., 0.),
						10., 10., 0., closeColor);
				
				font.Draw("Outfitter",
					uiPoint + Point(-60., 8.),
					object.GetPlanet()->HasOutfitter() ? closeColor : dimColor);
				if(commodity == SHOW_OUTFITTER)
					PointerShader::Draw(uiPoint + Point(-60., 15.), Point(1., 0.),
						10., 10., 0., closeColor);
				
				bool hasVisited = player.HasVisited(object.GetPlanet());
				font.Draw(hasVisited ? "(has been visited)" : "(not yet visited)",
					uiPoint + Point(-70., 28.),
					farColor);
				if(commodity == SHOW_VISITED)
					PointerShader::Draw(uiPoint + Point(-70., 35.), Point(1., 0.),
						10., 10., 0., closeColor);
				
				uiPoint.Y() += 130.;
			}
	}
	
	uiPoint.Y() += 45.;
	tradeY = uiPoint.Y() - 95.;
	
	// Trade sprite goes from 310 to 540.
	const Sprite *tradeSprite = SpriteSet::Get("ui/map trade");
	SpriteShader::Draw(tradeSprite, uiPoint);
	
	uiPoint.X() -= 90.;
	uiPoint.Y() -= 97.;
	for(const Trade::Commodity &commodity : GameData::Commodities())
	{
		bool isSelected = false;
		if(static_cast<unsigned>(this->commodity) < GameData::Commodities().size())
			isSelected = (&commodity == &GameData::Commodities()[this->commodity]);
		Color &color = isSelected ? closeColor : farColor;
		
		font.Draw(commodity.name, uiPoint, color);
		
		string price;
		
		bool hasVisited = player.HasVisited(selectedSystem);
		if(hasVisited && selectedSystem->IsInhabited())
		{
			int value = selectedSystem->Trade(commodity.name);
			int localValue = (player.GetSystem() ? player.GetSystem()->Trade(commodity.name) : 0);
			if(!player.GetSystem() || player.GetSystem() == selectedSystem || !value || !localValue)
				price = to_string(value);
			else
			{
				value -= localValue;
				price += "(";
				if(value > 0)
					price += '+';
				price += to_string(value);
				price += ")";
			}
		}
		else
			price = (hasVisited ? "n/a" : "?");
		
		Point pos = uiPoint + Point(140. - font.Width(price), 0.);
		font.Draw(price, pos, color);
		
		if(isSelected)
			PointerShader::Draw(uiPoint + Point(0., 7.), Point(1., 0.), 10., 10., 0., color);
		
		uiPoint.Y() += 20.;
	}
	
	if(selectedPlanet && !selectedPlanet->Description().empty() && player.HasVisited(selectedPlanet))
	{
		const Sprite *panelSprite = SpriteSet::Get("ui/description panel");
		Point pos(Screen::Right() - .5 * panelSprite->Width(),
			Screen::Top() + .5 * panelSprite->Height());
		SpriteShader::Draw(panelSprite, pos);
		
		WrappedText text;
		text.SetFont(FontSet::Get(14));
		text.SetAlignment(WrappedText::JUSTIFIED);
		text.SetWrapWidth(480);
		text.Wrap(selectedPlanet->Description());
		text.Draw(Point(Screen::Right() - 500, Screen::Top() + 20), closeColor);
	}
	
	// Draw the buttons.
	Information info;
	info.SetCondition("is ports");
	if(ZoomIsMax())
		info.SetCondition("max zoom");
	if(ZoomIsMin())
		info.SetCondition("min zoom");
	const Interface *interface = GameData::Interfaces().Get("map buttons");
	interface->Draw(info, Point(-250., 0.));
}