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 ¤tColor = *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); }
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); }
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(); }
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")); }
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(); }
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")); }
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")); }
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(); }
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); } }
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); }
// 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.; } }
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); }
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.); } } }
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; } }
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")); } }
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); } }
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.)); } } }
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.; } }
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.)); }