1 /*
2     SPDX-FileCopyrightText: 2003 Russell Steffen <rsteffen@bayarea.net>
3     SPDX-FileCopyrightText: 2003 Stephan Zehetner <s.zehetner@nevox.org>
4     SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com>
5     SPDX-FileCopyrightText: 2006 Inge Wallin <inge@lysator.liu.se>
6     SPDX-FileCopyrightText: 2006 Pierre Ducroquet <pinaraf@gmail.com>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 
11 #include "map.h"
12 #include "../game.h"
13 #include "../planet.h"
14 #include <cmath>
15 
16 
Map(int rowsCount,int colsCount)17 Map::Map(int rowsCount, int colsCount) :
18     m_rows(rowsCount),
19     m_columns(colsCount)
20 {
21     resizeMap(rowsCount, colsCount);
22 }
23 
24 
~Map()25 Map::~Map()
26 {
27 }
28 
29 
30 void
resizeMap(int rowsCount,int columnsCount)31 Map::resizeMap (int rowsCount, int columnsCount)
32 {
33     m_rows = rowsCount;
34     m_columns = columnsCount;
35     m_grid.clear();
36     m_grid = QList<QList<Sector> >();
37 
38     // Initialize the grid of Sectors.
39     for (int row = 0; row < rowsCount; row++) {
40         m_grid << QList<Sector>();
41         for (int col = 0; col < columnsCount; col++) {
42             m_grid[row] << Sector(this, Coordinate(row, col));
43             connect(&m_grid[row][col], &Sector::update, this, &Map::childSectorUpdate);
44         }
45     }
46 }
47 
48 
49 void
addPlanet(Sector * sector,Player * player,int production,double killpercentage)50 Map::addPlanet(Sector *sector, Player *player, int production, double killpercentage)
51 {
52     new Planet(UniquePlanetName(), sector, player, production, killpercentage);
53 }
54 
55 
56 Planet*
addPlayerPlanetSomewhere(Player * player)57 Map::addPlayerPlanetSomewhere(Player *player)
58 {
59     Sector *sector = findRandomFreeSector();
60     if (!sector)
61         return nullptr;
62     return Planet::createPlayerPlanet(sector, player, UniquePlanetName());
63 }
64 
65 
66 Planet*
addNeutralPlanetSomewhere(Player * neutral)67 Map::addNeutralPlanetSomewhere(Player *neutral)
68 {
69     Sector *sector = findRandomFreeSector();
70     if (!sector)
71         return nullptr;
72     return Planet::createNeutralPlanet(sector, neutral, UniquePlanetName());
73 }
74 
75 
76 bool
removePlayerPlanet(Player * player)77 Map::removePlayerPlanet(Player *player)
78 {
79     for (Planet *planet : planets()) {
80         if (planet->player() == player) {
81             delete planet;
82             return true;
83         }
84     }
85     return false;
86 }
87 
88 
89 void
removePlayerPlanets(Player * player)90 Map::removePlayerPlanets(Player *player)
91 {
92     while(removePlayerPlanet(player)) ;
93 }
94 
95 
96 void
turnOverPlayerPlanets(Player * owner,Player * newOwner)97 Map::turnOverPlayerPlanets(Player* owner, Player* newOwner)
98 {
99     for (Planet *planet : planets()) {
100         if (planet->player() == owner) {
101             planet->setOwner(newOwner);
102         }
103     }
104 }
105 
106 
107 int
playerPlanetCount(Player * player)108 Map::playerPlanetCount(Player *player)
109 {
110     int count = 0;
111     for (Planet *planet : planets()) {
112         if (planet->player() == player) {
113             count++;
114         }
115     }
116     return count;
117 }
118 
119 
120 void
clearMap()121 Map::clearMap()
122 {
123     for (int x = 0; x < rows(); ++x) {
124         for (int y = 0; y < columns(); ++y) {
125              delete m_grid[x][y].planet();
126         }
127     }
128 
129     Q_EMIT update();
130 }
131 
132 
133 QString
UniquePlanetName(void)134 Map::UniquePlanetName(void)
135 {
136     char c = 'A';
137 again:
138     for (Planet *planet : planets()) {
139         if (planet->name().at(0).toLatin1() == c) {
140             c++;
141             goto again;
142         }
143     }
144     return QChar::fromLatin1(c);
145 }
146 
147 
148 void
populateMap(const QList<Player * > & players,Player * neutral,int numNeutralPlanets)149 Map::populateMap(const QList<Player *> &players, Player *neutral, int numNeutralPlanets)
150 {
151     // Create a planet for each player.
152     for (Player *player : players) {
153         addPlayerPlanetSomewhere(player);
154     }
155 
156     for (int x = 0; x < numNeutralPlanets; ++x) {
157         Sector *sector = findRandomFreeSector();
158         if (sector) {
159             Planet::createNeutralPlanet(sector, neutral, UniquePlanetName());
160         }
161     }
162 
163     Q_EMIT update();
164 }
165 
166 
167 double
distance(Planet * p1,Planet * p2)168 Map::distance(Planet *p1, Planet *p2)
169 {
170     Coordinate  diff = p1->sector()->coord() - p2->sector()->coord();
171 
172     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.
173 }
174 
175 
176 Sector*
findRandomFreeSector()177 Map::findRandomFreeSector()
178 {
179     for (const QList<Sector> &i : std::as_const(m_grid)) {
180         for (const Sector &j : i) {
181             if (!j.hasPlanet()) {
182                 goto freesectorexists;
183             }
184         }
185     }
186 
187     return nullptr;
188 
189 freesectorexists:
190 
191     Coordinate  c;
192 
193     do {
194         c = Game::generatePlanetCoordinates(rows(), columns());
195     } while (m_grid[c.x()][c.y()].hasPlanet());
196 
197     return &m_grid[c.x()][c.y()];
198 }
199 
200 
201 void
childSectorUpdate()202 Map::childSectorUpdate()
203 {
204     Q_EMIT update();
205 }
206 
207 
208 const QList <Planet*>
planets()209 Map::planets()
210 {
211     QList <Planet*>planets;
212     for (const QList<Sector> &i : std::as_const(m_grid)) {
213         for (const Sector &j : i) {
214             if (j.hasPlanet()) {
215                 planets += j.planet();
216             }
217         }
218     }
219     return planets;
220 }
221