File indexing completed on 2023-11-26 07:42:32
0001 /* 0002 SPDX-FileCopyrightText: 2003 Russell Steffen <rsteffen@bayarea.net> 0003 SPDX-FileCopyrightText: 2003 Stephan Zehetner <s.zehetner@nevox.org> 0004 SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com> 0005 SPDX-FileCopyrightText: 2006 Inge Wallin <inge@lysator.liu.se> 0006 SPDX-FileCopyrightText: 2006 Pierre Ducroquet <pinaraf@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "map.h" 0012 #include "../game.h" 0013 #include "../planet.h" 0014 #include <cmath> 0015 0016 0017 Map::Map(int rowsCount, int colsCount) : 0018 m_rows(rowsCount), 0019 m_columns(colsCount) 0020 { 0021 resizeMap(rowsCount, colsCount); 0022 } 0023 0024 0025 Map::~Map() 0026 { 0027 } 0028 0029 0030 void 0031 Map::resizeMap (int rowsCount, int columnsCount) 0032 { 0033 m_rows = rowsCount; 0034 m_columns = columnsCount; 0035 m_grid.clear(); 0036 m_grid = QList<QList<Sector> >(); 0037 0038 // Initialize the grid of Sectors. 0039 for (int row = 0; row < rowsCount; row++) { 0040 m_grid << QList<Sector>(); 0041 for (int col = 0; col < columnsCount; col++) { 0042 m_grid[row] << Sector(this, Coordinate(row, col)); 0043 connect(&m_grid[row][col], &Sector::update, this, &Map::childSectorUpdate); 0044 } 0045 } 0046 } 0047 0048 0049 void 0050 Map::addPlanet(Sector *sector, Player *player, int production, double killpercentage) 0051 { 0052 new Planet(UniquePlanetName(), sector, player, production, killpercentage); 0053 } 0054 0055 0056 Planet* 0057 Map::addPlayerPlanetSomewhere(Player *player) 0058 { 0059 Sector *sector = findRandomFreeSector(); 0060 if (!sector) 0061 return nullptr; 0062 return Planet::createPlayerPlanet(sector, player, UniquePlanetName()); 0063 } 0064 0065 0066 Planet* 0067 Map::addNeutralPlanetSomewhere(Player *neutral) 0068 { 0069 Sector *sector = findRandomFreeSector(); 0070 if (!sector) 0071 return nullptr; 0072 return Planet::createNeutralPlanet(sector, neutral, UniquePlanetName()); 0073 } 0074 0075 0076 bool 0077 Map::removePlayerPlanet(Player *player) 0078 { 0079 for (Planet *planet : planets()) { 0080 if (planet->player() == player) { 0081 delete planet; 0082 return true; 0083 } 0084 } 0085 return false; 0086 } 0087 0088 0089 void 0090 Map::removePlayerPlanets(Player *player) 0091 { 0092 while(removePlayerPlanet(player)) ; 0093 } 0094 0095 0096 void 0097 Map::turnOverPlayerPlanets(Player* owner, Player* newOwner) 0098 { 0099 for (Planet *planet : planets()) { 0100 if (planet->player() == owner) { 0101 planet->setOwner(newOwner); 0102 } 0103 } 0104 } 0105 0106 0107 int 0108 Map::playerPlanetCount(Player *player) 0109 { 0110 int count = 0; 0111 for (Planet *planet : planets()) { 0112 if (planet->player() == player) { 0113 count++; 0114 } 0115 } 0116 return count; 0117 } 0118 0119 0120 void 0121 Map::clearMap() 0122 { 0123 for (int x = 0; x < rows(); ++x) { 0124 for (int y = 0; y < columns(); ++y) { 0125 delete m_grid[x][y].planet(); 0126 } 0127 } 0128 0129 Q_EMIT update(); 0130 } 0131 0132 0133 // Create an unique name in the A-Z range 0134 // once we reach Z, go do the same but with 2 chars, etc. 0135 QString 0136 Map::UniquePlanetName() const 0137 { 0138 QString newName = QStringLiteral("A"); 0139 again: 0140 for (Planet *planet : planets()) { 0141 if (planet->name() == newName) { 0142 if (newName.back() == QLatin1Char('Z')) { 0143 bool addNewA = true; 0144 for (int i = newName.length() - 1; i >= 0; --i) { 0145 if (newName[i] != QLatin1Char('Z')) { 0146 newName[i] = static_cast<char16_t>(newName[i].unicode() + 1); 0147 for (int j = i + 1; j < newName.length(); ++j) { 0148 newName[j] = QLatin1Char('A'); 0149 } 0150 addNewA = false; 0151 break; 0152 } 0153 } 0154 if (addNewA) { 0155 for (int i = 0; i < newName.length(); ++i) { 0156 newName[i] = QLatin1Char('A'); 0157 } 0158 newName += QStringLiteral("A"); 0159 } 0160 } else { 0161 newName.back() = static_cast<char16_t>(newName.back().unicode() + 1); 0162 } 0163 goto again; 0164 } 0165 } 0166 return newName; 0167 } 0168 0169 0170 void 0171 Map::populateMap(const QList<Player *> &players, Player *neutral, int numNeutralPlanets) 0172 { 0173 // Create a planet for each player. 0174 for (Player *player : players) { 0175 addPlayerPlanetSomewhere(player); 0176 } 0177 0178 for (int x = 0; x < numNeutralPlanets; ++x) { 0179 Sector *sector = findRandomFreeSector(); 0180 if (sector) { 0181 Planet::createNeutralPlanet(sector, neutral, UniquePlanetName()); 0182 } 0183 } 0184 0185 Q_EMIT update(); 0186 } 0187 0188 0189 double 0190 Map::distance(Planet *p1, Planet *p2) 0191 { 0192 Coordinate diff = p1->sector()->coord() - p2->sector()->coord(); 0193 0194 return sqrt(double((diff.x() * diff.x()) + (diff.y() * diff.y()))) / 2; // Yes, we're dividing by two. It's not a bug, it's a feature. 0195 } 0196 0197 0198 Sector* 0199 Map::findRandomFreeSector() 0200 { 0201 for (const QList<Sector> &i : std::as_const(m_grid)) { 0202 for (const Sector &j : i) { 0203 if (!j.hasPlanet()) { 0204 goto freesectorexists; 0205 } 0206 } 0207 } 0208 0209 return nullptr; 0210 0211 freesectorexists: 0212 0213 Coordinate c; 0214 0215 do { 0216 c = Game::generatePlanetCoordinates(rows(), columns()); 0217 } while (m_grid[c.x()][c.y()].hasPlanet()); 0218 0219 return &m_grid[c.x()][c.y()]; 0220 } 0221 0222 0223 void 0224 Map::childSectorUpdate() 0225 { 0226 Q_EMIT update(); 0227 } 0228 0229 0230 const QList <Planet*> 0231 Map::planets() const 0232 { 0233 QList <Planet*>planets; 0234 for (const QList<Sector> &i : m_grid) { 0235 for (const Sector &j : i) { 0236 if (j.hasPlanet()) { 0237 planets += j.planet(); 0238 } 0239 } 0240 } 0241 return planets; 0242 } 0243 0244 #include "moc_map.cpp"