File indexing completed on 2024-04-28 04:03:30

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"