1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 #include <cmath>
20 
21 #include "game/data/player/player.h"
22 
23 #include "game/data/units/building.h"
24 #include "game/logic/client.h"
25 #include "utility/listhelpers.h"
26 #include "netmessage.h"
27 #include "game/logic/server.h"
28 #include "game/logic/serverevents.h"
29 #include "game/data/units/vehicle.h"
30 #include "game/data/report/savedreport.h"
31 #include "game/logic/turnclock.h"
32 
33 using namespace std;
34 
35 //------------------------------------------------------------------------------
36 // Implementation cPlayer class
37 //------------------------------------------------------------------------------
38 
39 //------------------------------------------------------------------------------
cPlayer(const cPlayerBasicData & splayer_)40 cPlayer::cPlayer (const cPlayerBasicData& splayer_) :
41 	splayer (splayer_),
42 	landingPosX (-1),
43 	landingPosY (-1),
44 	numEcos (0),
45 	lastDeletedUnit (0),
46 	clan (-1),
47 	hasFinishedTurn (false),
48 	isRemovedFromGame (false)
49 {
50 	// get the default (no clan) unit data
51 	VehicleData = UnitsData.getUnitData_Vehicles (-1);
52 	BuildingData = UnitsData.getUnitData_Buildings (-1);
53 
54 	researchCentersWorkingTotal = 0;
55 	for (int i = 0; i < cResearch::kNrResearchAreas; i++)
56 		researchCentersWorkingOnArea[i] = 0;
57 	credits = 0;
58 
59 	isDefeated = false;
60 
61 	splayer.nameChanged.connect ([this]() { nameChanged(); });
62 	splayer.colorChanged.connect ([this]() { colorChanged(); });
63 }
64 
65 //------------------------------------------------------------------------------
~cPlayer()66 cPlayer::~cPlayer()
67 {}
68 
69 //------------------------------------------------------------------------------
setClan(int newClan)70 void cPlayer::setClan (int newClan)
71 {
72 	if (newClan == clan || newClan < -1 || 7 < newClan)
73 		return;
74 
75 	clan = newClan;
76 
77 	VehicleData = UnitsData.getUnitData_Vehicles (clan);
78 	BuildingData = UnitsData.getUnitData_Buildings (clan);
79 }
80 
81 //------------------------------------------------------------------------------
getCredits() const82 int cPlayer::getCredits() const
83 {
84 	return credits;
85 }
86 
87 //------------------------------------------------------------------------------
setCredits(int credits_)88 void cPlayer::setCredits (int credits_)
89 {
90 	std::swap (credits, credits_);
91 	if (credits != credits_) creditsChanged();
92 }
93 
94 //------------------------------------------------------------------------------
getUnitDataCurrentVersion(const sID & id)95 sUnitData* cPlayer::getUnitDataCurrentVersion (const sID& id)
96 {
97 	const cPlayer* constMe = this;
98 	return const_cast<sUnitData*> (constMe->getUnitDataCurrentVersion (id));
99 }
100 
101 //------------------------------------------------------------------------------
getUnitDataCurrentVersion(const sID & id) const102 const sUnitData* cPlayer::getUnitDataCurrentVersion (const sID& id) const
103 {
104 	if (id.isAVehicle())
105 	{
106 		for (size_t i = 0; i != VehicleData.size(); ++i)
107 		{
108 			if (VehicleData[i].ID == id) return &VehicleData[i];
109 		}
110 	}
111 	else if (id.isABuilding())
112 	{
113 		for (unsigned int i = 0; i < BuildingData.size(); ++i)
114 		{
115 			if (BuildingData[i].ID == id) return &BuildingData[i];
116 		}
117 	}
118 	return nullptr;
119 }
120 
121 //------------------------------------------------------------------------------
122 /** initialize the maps */
123 //------------------------------------------------------------------------------
initMaps(cMap & map)124 void cPlayer::initMaps (cMap& map)
125 {
126 	mapSize = map.getSize();
127 	const int size = mapSize.x() * mapSize.y();
128 	// Scanner-Map:
129 	ScanMap.clear();
130 	ScanMap.resize (size, 0);
131 	// Ressource-Map
132 	ResourceMap.clear();
133 	ResourceMap.resize (size, 0);
134 
135 	base.map = &map;
136 	// Sentry-Map:
137 	SentriesMapAir.clear();
138 	SentriesMapAir.resize (size, 0);
139 	SentriesMapGround.clear();
140 	SentriesMapGround.resize (size, 0);
141 
142 	// Detect-Maps:
143 	DetectLandMap.clear();
144 	DetectLandMap.resize (size, 0);
145 	DetectSeaMap.clear();
146 	DetectSeaMap.resize (size, 0);
147 	DetectMinesMap.clear();
148 	DetectMinesMap.resize (size, 0);
149 }
150 
getMapSize() const151 const cPosition& cPlayer::getMapSize() const
152 {
153 	return mapSize;
154 }
155 
156 //------------------------------------------------------------------------------
addNewVehicle(const cPosition & position,const sID & id,unsigned int uid)157 cVehicle& cPlayer::addNewVehicle (const cPosition& position, const sID& id, unsigned int uid)
158 {
159 	const sUnitData& unitData = *id.getUnitDataOriginalVersion (this);
160 	auto vehicle = std::make_shared<cVehicle> (unitData, this, uid);
161 	vehicle->setPosition (position);
162 
163 	drawSpecialCircle (vehicle->getPosition(), vehicle->data.getScan(), ScanMap, mapSize);
164 	if (vehicle->data.canDetectStealthOn & TERRAIN_GROUND) drawSpecialCircle (vehicle->getPosition(), vehicle->data.getScan(), DetectLandMap, mapSize);
165 	if (vehicle->data.canDetectStealthOn & TERRAIN_SEA) drawSpecialCircle (vehicle->getPosition(), vehicle->data.getScan(), DetectSeaMap, mapSize);
166 	if (vehicle->data.canDetectStealthOn & AREA_EXP_MINE)
167 	{
168 		const int minx = std::max (vehicle->getPosition().x() - 1, 0);
169 		const int maxx = std::min (vehicle->getPosition().x() + 1, mapSize.x() - 1);
170 		const int miny = std::max (vehicle->getPosition().y() - 1, 0);
171 		const int maxy = std::min (vehicle->getPosition().y() + 1, mapSize.y() - 1);
172 		for (int x = minx; x <= maxx; ++x)
173 			for (int y = miny; y <= maxy; ++y)
174 				DetectMinesMap[x + mapSize.x() * y] = 1;
175 	}
176 
177 	auto result = vehicles.insert (std::move (vehicle));
178 	assert (result.second);
179 
180 	return * (*result.first);
181 }
182 
183 //------------------------------------------------------------------------------
addNewBuilding(const cPosition & position,const sID & id,unsigned int uid)184 cBuilding& cPlayer::addNewBuilding (const cPosition& position, const sID& id, unsigned int uid)
185 {
186 	const sUnitData* unitData = id.getUnitDataOriginalVersion (this);
187 	auto building = std::make_shared<cBuilding> (unitData, this, uid);
188 
189 	building->setPosition (position);
190 
191 	if (building->data.getScan())
192 	{
193 		if (building->data.isBig) drawSpecialCircleBig (building->getPosition(), building->data.getScan(), ScanMap, mapSize);
194 		else drawSpecialCircle (building->getPosition(), building->data.getScan(), ScanMap, mapSize);
195 	}
196 
197 	auto result = buildings.insert (std::move (building));
198 	assert (result.second);
199 	return * (*result.first);
200 }
201 
202 //------------------------------------------------------------------------------
addUnit(std::shared_ptr<cVehicle> vehicle)203 void cPlayer::addUnit (std::shared_ptr<cVehicle> vehicle)
204 {
205 	vehicles.insert (std::move (vehicle));
206 }
207 
208 //------------------------------------------------------------------------------
addUnit(std::shared_ptr<cBuilding> building)209 void cPlayer::addUnit (std::shared_ptr<cBuilding> building)
210 {
211 	buildings.insert (std::move (building));
212 }
213 
214 //------------------------------------------------------------------------------
removeUnit(const cBuilding & building)215 std::shared_ptr<cBuilding> cPlayer::removeUnit (const cBuilding& building)
216 {
217 	auto iter = buildings.find (building);
218 	if (iter == buildings.end()) return nullptr;
219 
220 	auto removed = *iter;
221 	buildings.erase (iter);
222 	return removed;
223 }
224 
225 //------------------------------------------------------------------------------
removeUnit(const cVehicle & vehicle)226 std::shared_ptr<cVehicle> cPlayer::removeUnit (const cVehicle& vehicle)
227 {
228 	auto iter = vehicles.find (vehicle);
229 	if (iter == vehicles.end()) return nullptr;
230 
231 	auto removed = *iter;
232 	vehicles.erase (iter);
233 	return removed;
234 }
235 
236 //------------------------------------------------------------------------------
removeAllUnits()237 void cPlayer::removeAllUnits()
238 {
239 	vehicles.clear();
240 	buildings.clear();
241 }
242 
243 //------------------------------------------------------------------------------
getVehicleFromId(unsigned int id) const244 cVehicle* cPlayer::getVehicleFromId (unsigned int id) const
245 {
246 	auto iter =  vehicles.find (id);
247 	return iter == vehicles.end() ? nullptr : (*iter).get();
248 }
249 
250 //------------------------------------------------------------------------------
getBuildingFromId(unsigned int id) const251 cBuilding* cPlayer::getBuildingFromId (unsigned int id) const
252 {
253 	auto iter = buildings.find (id);
254 	return iter == buildings.end() ? nullptr : (*iter).get();
255 }
256 
257 //------------------------------------------------------------------------------
getVehicles() const258 const cFlatSet<std::shared_ptr<cVehicle>, sUnitLess<cVehicle>>& cPlayer::getVehicles() const
259 {
260 	return vehicles;
261 }
262 
263 //------------------------------------------------------------------------------
getBuildings() const264 const cFlatSet<std::shared_ptr<cBuilding>, sUnitLess<cBuilding>>& cPlayer::getBuildings() const
265 {
266 	return buildings;
267 }
268 
269 //------------------------------------------------------------------------------
addSentry(cUnit & u)270 void cPlayer::addSentry (cUnit& u)
271 {
272 	u.setSentryActive (true);
273 	if (u.data.canAttack & TERRAIN_AIR)
274 	{
275 		drawSpecialCircle (u.getPosition(), u.data.getRange(), SentriesMapAir, mapSize);
276 	}
277 	if ((u.data.canAttack & TERRAIN_GROUND) || (u.data.canAttack & TERRAIN_SEA))
278 	{
279 		drawSpecialCircle (u.getPosition(), u.data.getRange(), SentriesMapGround, mapSize);
280 	}
281 }
282 
283 //------------------------------------------------------------------------------
deleteSentry(cUnit & u)284 void cPlayer::deleteSentry (cUnit& u)
285 {
286 	u.setSentryActive (false);
287 	if (u.data.canAttack & TERRAIN_AIR)
288 	{
289 		refreshSentryAir();
290 	}
291 	else if ((u.data.canAttack & TERRAIN_GROUND) || (u.data.canAttack & TERRAIN_SEA))
292 	{
293 		refreshSentryGround();
294 	}
295 }
296 
297 //------------------------------------------------------------------------------
refreshSentryAir()298 void cPlayer::refreshSentryAir()
299 {
300 	std::fill (SentriesMapAir.begin(), SentriesMapAir.end(), 0);
301 
302 	for (auto i = vehicles.begin(); i != vehicles.end(); ++i)
303 	{
304 		const auto& unit = *i;
305 		if (unit->isSentryActive() && unit->data.canAttack & TERRAIN_AIR)
306 		{
307 			drawSpecialCircle (unit->getPosition(), unit->data.getRange(), SentriesMapAir, mapSize);
308 		}
309 	}
310 
311 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
312 	{
313 		const auto& unit = *i;
314 		if (unit->isSentryActive() && unit->data.canAttack & TERRAIN_AIR)
315 		{
316 			drawSpecialCircle (unit->getPosition(), unit->data.getRange(), SentriesMapAir, mapSize);
317 		}
318 	}
319 }
320 
321 //------------------------------------------------------------------------------
refreshSentryGround()322 void cPlayer::refreshSentryGround()
323 {
324 	std::fill (SentriesMapGround.begin(), SentriesMapGround.end(), 0);
325 
326 	for (auto i = vehicles.begin(); i != vehicles.end(); ++i)
327 	{
328 		const auto& unit = *i;
329 		if (unit->isSentryActive() && ((unit->data.canAttack & TERRAIN_GROUND) || (unit->data.canAttack & TERRAIN_SEA)))
330 		{
331 			drawSpecialCircle (unit->getPosition(), unit->data.getRange(), SentriesMapGround, mapSize);
332 		}
333 	}
334 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
335 	{
336 		const auto& unit = *i;
337 		if (unit->isSentryActive() && ((unit->data.canAttack & TERRAIN_GROUND) || (unit->data.canAttack & TERRAIN_SEA)))
338 		{
339 			drawSpecialCircle (unit->getPosition(), unit->data.getRange(), SentriesMapGround, mapSize);
340 		}
341 	}
342 }
343 
344 //------------------------------------------------------------------------------
345 /** Does a scan for all units of the player */
346 //------------------------------------------------------------------------------
doScan()347 void cPlayer::doScan()
348 {
349 	if (isDefeated) return;
350 	std::fill (ScanMap.begin(), ScanMap.end(), 0);
351 	std::fill (DetectLandMap.begin(), DetectLandMap.end(), 0);
352 	std::fill (DetectSeaMap.begin(), DetectSeaMap.end(), 0);
353 	std::fill (DetectMinesMap.begin(), DetectMinesMap.end(), 0);
354 
355 	// iterate the vehicle list
356 	for (auto i = vehicles.begin(); i != vehicles.end(); ++i)
357 	{
358 		const auto& vp = *i;
359 		if (vp->isUnitLoaded()) continue;
360 
361 		if (vp->isDisabled())
362 			ScanMap[getOffset (vp->getPosition())] = 1;
363 		else
364 		{
365 			if (vp->data.isBig)
366 				drawSpecialCircleBig (vp->getPosition(), vp->data.getScan(), ScanMap, mapSize);
367 			else
368 				drawSpecialCircle (vp->getPosition(), vp->data.getScan(), ScanMap, mapSize);
369 
370 			//detection maps
371 			if (vp->data.canDetectStealthOn & TERRAIN_GROUND) drawSpecialCircle (vp->getPosition(), vp->data.getScan(), DetectLandMap, mapSize);
372 			else if (vp->data.canDetectStealthOn & TERRAIN_SEA) drawSpecialCircle (vp->getPosition(), vp->data.getScan(), DetectSeaMap, mapSize);
373 			if (vp->data.canDetectStealthOn & AREA_EXP_MINE)
374 			{
375 				const int minx = std::max (vp->getPosition().x() - 1, 0);
376 				const int maxx = std::min (vp->getPosition().x() + 1, mapSize.x() - 1);
377 				const int miny = std::max (vp->getPosition().y() - 1, 0);
378 				const int maxy = std::min (vp->getPosition().y() + 1, mapSize.y() - 1);
379 				for (int x = minx; x <= maxx; ++x)
380 				{
381 					for (int y = miny; y <= maxy; ++y)
382 					{
383 						DetectMinesMap[x + mapSize.x() * y] = 1;
384 					}
385 				}
386 			}
387 		}
388 	}
389 
390 	// iterate the building list
391 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
392 	{
393 		const auto& bp = *i;
394 		if (bp->isDisabled())
395 			ScanMap[getOffset (bp->getPosition())] = 1;
396 		else if (bp->data.getScan())
397 		{
398 			if (bp->data.isBig)
399 				drawSpecialCircleBig (bp->getPosition(), bp->data.getScan(), ScanMap, mapSize);
400 			else
401 				drawSpecialCircle (bp->getPosition(), bp->data.getScan(), ScanMap, mapSize);
402 		}
403 	}
404 }
405 
revealMap()406 void cPlayer::revealMap()
407 {
408 	std::fill (ScanMap.begin(), ScanMap.end(), 1);
409 }
410 
revealPosition(const cPosition & position)411 void cPlayer::revealPosition (const cPosition& position)
412 {
413 	if (position.x() < 0 || position.x() >= mapSize.x() || position.y() < 0 || position.y() >= mapSize.y()) return;
414 
415 	ScanMap[getOffset (position)] = 1;
416 }
417 
revealResource()418 void cPlayer::revealResource()
419 {
420 	std::fill (ResourceMap.begin(), ResourceMap.end(), 1);
421 }
422 
canSeeAnyAreaUnder(const cUnit & unit) const423 bool cPlayer::canSeeAnyAreaUnder (const cUnit& unit) const
424 {
425 	if (canSeeAt (unit.getPosition())) return true;
426 	if (!unit.data.isBig) return false;
427 
428 	return canSeeAt (unit.getPosition() + cPosition (0, 1)) ||
429 		   canSeeAt (unit.getPosition() + cPosition (1, 1)) ||
430 		   canSeeAt (unit.getPosition() + cPosition (1, 0));
431 }
432 
getNextVehicle(cVehicle * start) const433 cVehicle* cPlayer::getNextVehicle (cVehicle* start) const
434 {
435 	if (vehicles.empty()) return nullptr;
436 
437 	auto it = (start == nullptr) ? vehicles.begin() : vehicles.find (*start);
438 	if (start != nullptr && it != vehicles.end()) ++it;
439 	for (; it != vehicles.end(); ++it)
440 	{
441 		if (! (*it)->isMarkedAsDone() && (! (*it)->isUnitBuildingABuilding() || (*it)->getBuildTurns() == 0)
442 			&& ! (*it)->isUnitClearing() && ! (*it)->isSentryActive() && ! (*it)->isUnitLoaded()
443 			&& ((*it)->data.getSpeed() || (*it)->data.getShots()))
444 		{
445 			return it->get();
446 		}
447 	}
448 	return nullptr;
449 }
450 
getNextBuilding(cBuilding * start) const451 cBuilding* cPlayer::getNextBuilding (cBuilding* start) const
452 {
453 	if (buildings.empty()) return nullptr;
454 
455 	auto it = (start == nullptr) ? buildings.begin() : buildings.find (*start);
456 	if (start != nullptr && it != buildings.end()) ++it;
457 	for (; it != buildings.end(); ++it)
458 	{
459 		if (! (*it)->isMarkedAsDone() && ! (*it)->isUnitWorking() && ! (*it)->isSentryActive()
460 			&& (! (*it)->data.canBuild.empty() || (*it)->data.getShots()
461 				|| (*it)->data.canMineMaxRes > 0 || (*it)->data.convertsGold > 0
462 				|| (*it)->data.canResearch))
463 		{
464 			return it->get();
465 		}
466 	}
467 	return nullptr;
468 }
469 
getNextMiningStation(cBuilding * start) const470 cBuilding* cPlayer::getNextMiningStation (cBuilding* start) const
471 {
472 	if (buildings.empty()) return nullptr;
473 
474 	auto it = (start == nullptr) ? buildings.begin() : buildings.find (*start);
475 	if (start != nullptr && it != buildings.end()) ++it;
476 	for (; it != buildings.end(); ++it)
477 	{
478 		if ((*it)->data.canMineMaxRes > 0)
479 		{
480 			return it->get();
481 		}
482 	}
483 	return nullptr;
484 }
485 
486 //------------------------------------------------------------------------------
487 /** Returns the next unit that can still fire/shoot */
488 //------------------------------------------------------------------------------
getNextUnit(cUnit * start) const489 cUnit* cPlayer::getNextUnit (cUnit* start) const
490 {
491 	if (start == nullptr || start->getOwner() != this)
492 	{
493 		cVehicle* nextVehicle = getNextVehicle (nullptr);
494 		if (nextVehicle) return nextVehicle;
495 		cBuilding* nextBuilding = getNextBuilding (nullptr);
496 		if (nextBuilding) return nextBuilding;
497 	}
498 	else if (start->isAVehicle())
499 	{
500 		cVehicle* nextVehicle = getNextVehicle (static_cast<cVehicle*> (start));
501 		if (nextVehicle) return nextVehicle;
502 		cBuilding* nextBuilding = getNextBuilding (nullptr);
503 		if (nextBuilding) return nextBuilding;
504 		nextVehicle = getNextVehicle (nullptr);
505 		if (nextVehicle) return nextVehicle;
506 	}
507 	else
508 	{
509 		assert (start->isABuilding());
510 		cBuilding* building = static_cast<cBuilding*> (start);
511 		cBuilding* nextBuilding = getNextBuilding (building);
512 		if (nextBuilding) return nextBuilding;
513 		cVehicle* nextVehicle = getNextVehicle (nullptr);
514 		if (nextVehicle) return nextVehicle;
515 		nextBuilding = getNextBuilding (nullptr);
516 		if (nextBuilding) return nextBuilding;
517 	}
518 	// finally, return the more recent built Mining station.
519 	// since list order is by increasing age, take the first in list.
520 	return getNextMiningStation (nullptr);
521 }
522 
getPrevVehicle(cVehicle * start) const523 cVehicle* cPlayer::getPrevVehicle (cVehicle* start) const
524 {
525 	if (vehicles.empty()) return nullptr;
526 
527 	auto it = (start == nullptr) ? vehicles.end() - 1 : vehicles.find (*start);
528 	if (start != nullptr && it != vehicles.begin() && it != vehicles.end()) --it;
529 	for (; it != vehicles.end(); --it)
530 	{
531 		if (! (*it)->isMarkedAsDone() && (! (*it)->isUnitBuildingABuilding() || (*it)->getBuildTurns() == 0)
532 			&& ! (*it)->isUnitClearing() && ! (*it)->isSentryActive() && ! (*it)->isUnitLoaded()
533 			&& ((*it)->data.getSpeed() || (*it)->data.getShots()))
534 		{
535 			return it->get();
536 		}
537 		if (it == vehicles.begin()) break;
538 	}
539 	return nullptr;
540 }
541 
getPrevBuilding(cBuilding * start) const542 cBuilding* cPlayer::getPrevBuilding (cBuilding* start) const
543 {
544 	if (buildings.empty()) return nullptr;
545 
546 	auto it = (start == nullptr) ? buildings.end() - 1 : buildings.find (*start);
547 	if (start != nullptr && it != buildings.begin() && it != buildings.end()) --it;
548 	for (; it != buildings.end(); --it)
549 	{
550 		if (! (*it)->isMarkedAsDone() && ! (*it)->isUnitWorking() && ! (*it)->isSentryActive()
551 			&& (! (*it)->data.canBuild.empty() || (*it)->data.getShots()
552 				|| (*it)->data.canMineMaxRes > 0 || (*it)->data.convertsGold > 0
553 				|| (*it)->data.canResearch))
554 		{
555 			return it->get();
556 		}
557 		if (it == buildings.begin()) break;
558 	}
559 	return nullptr;
560 }
561 
getPrevMiningStation(cBuilding * start) const562 cBuilding* cPlayer::getPrevMiningStation (cBuilding* start) const
563 {
564 	if (buildings.empty()) return nullptr;
565 
566 	auto it = (start == nullptr) ? buildings.end() - 1 : buildings.find (*start);
567 	for (; it != buildings.end(); --it)
568 	{
569 		if ((*it)->data.canMineMaxRes > 0)
570 		{
571 			return it->get();
572 		}
573 		if (it == buildings.begin()) break;
574 	}
575 	return nullptr;
576 }
577 
578 //------------------------------------------------------------------------------
579 /** Returns the previous vehicle, that can still move / shoot */
580 //------------------------------------------------------------------------------
getPrevUnit(cUnit * start) const581 cUnit* cPlayer::getPrevUnit (cUnit* start) const
582 {
583 	if (start == nullptr || start->getOwner() != this)
584 	{
585 		cVehicle* prevVehicle = getPrevVehicle (nullptr);
586 		if (prevVehicle) return prevVehicle;
587 		cBuilding* prevBuilding = getPrevBuilding (nullptr);
588 		if (prevBuilding) return prevBuilding;
589 	}
590 	else if (start->isAVehicle())
591 	{
592 		cVehicle* prevVehicle = getPrevVehicle (static_cast<cVehicle*> (start));
593 		if (prevVehicle) return prevVehicle;
594 		cBuilding* prevBuilding = getPrevBuilding (nullptr);
595 		if (prevBuilding) return prevBuilding;
596 		prevVehicle = getPrevVehicle (nullptr);
597 		if (prevVehicle) return prevVehicle;
598 	}
599 	else
600 	{
601 		assert (start->isABuilding());
602 		cBuilding* building = static_cast<cBuilding*> (start);
603 		cBuilding* prevBuilding = getPrevBuilding (building);
604 		if (prevBuilding) return prevBuilding;
605 		cVehicle* prevVehicle = getPrevVehicle (nullptr);
606 		if (prevVehicle) return prevVehicle;
607 		prevBuilding = getPrevBuilding (nullptr);
608 		if (prevBuilding) return prevBuilding;
609 	}
610 	// finally, return the more recent built Mining station.
611 	// since list order is by increasing age, take the first in list.
612 	return getNextMiningStation (nullptr);
613 }
614 
615 //------------------------------------------------------------------------------
hasUnits() const616 bool cPlayer::hasUnits() const
617 {
618 	return !vehicles.empty() || !buildings.empty();
619 }
620 
621 //------------------------------------------------------------------------------
622 /** Starts a research center. */
623 //------------------------------------------------------------------------------
startAResearch(cResearch::ResearchArea researchArea)624 void cPlayer::startAResearch (cResearch::ResearchArea researchArea)
625 {
626 	if (0 <= researchArea && researchArea <= cResearch::kNrResearchAreas)
627 	{
628 		++researchCentersWorkingTotal;
629 		++researchCentersWorkingOnArea[researchArea];
630 
631 		researchCentersWorkingOnAreaChanged (researchArea);
632 		researchCentersWorkingTotalChanged();
633 	}
634 }
635 
636 //------------------------------------------------------------------------------
637 /** Stops a research center. */
638 //------------------------------------------------------------------------------
stopAResearch(cResearch::ResearchArea researchArea)639 void cPlayer::stopAResearch (cResearch::ResearchArea researchArea)
640 {
641 	if (0 <= researchArea && researchArea <= cResearch::kNrResearchAreas)
642 	{
643 		--researchCentersWorkingTotal;
644 		if (researchCentersWorkingOnArea[researchArea] > 0)
645 		{
646 			--researchCentersWorkingOnArea[researchArea];
647 			researchCentersWorkingOnAreaChanged (researchArea);
648 		}
649 		researchCentersWorkingTotalChanged();
650 	}
651 }
652 
653 //------------------------------------------------------------------------------
654 /** At turn end update the research level */
655 //------------------------------------------------------------------------------
doResearch(cServer & server)656 void cPlayer::doResearch (cServer& server)
657 {
658 	bool researchFinished = false;
659 	std::vector<sUnitData*> upgradedUnitDatas;
660 	std::vector<int> areasReachingNextLevel;
661 	currentTurnResearchAreasFinished.clear();
662 	for (int area = 0; area < cResearch::kNrResearchAreas; ++area)
663 	{
664 		if (researchCentersWorkingOnArea[area] > 0 &&
665 			researchState.doResearch (researchCentersWorkingOnArea[area], area))
666 		{
667 			// next level reached
668 			areasReachingNextLevel.push_back (area);
669 			currentTurnResearchAreasFinished.push_back (area);
670 			researchFinished = true;
671 		}
672 	}
673 	if (researchFinished)
674 	{
675 		upgradeUnitTypes (areasReachingNextLevel, upgradedUnitDatas);
676 
677 		for (size_t i = 0; i != upgradedUnitDatas.size(); ++i)
678 			sendUnitUpgrades (server, *upgradedUnitDatas[i], *this);
679 	}
680 	sendResearchLevel (server, researchState, *this);
681 	sendFinishedResearchAreas (server, currentTurnResearchAreasFinished, *this);
682 }
683 
accumulateScore(cServer & server)684 void cPlayer::accumulateScore (cServer& server)
685 {
686 	const int now = server.getTurnClock()->getTurn();
687 	int deltaScore = 0;
688 
689 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
690 	{
691 		const auto& bp = *i;
692 		if (bp->data.canScore && bp->isUnitWorking())
693 		{
694 			bp->points++;
695 			deltaScore++;
696 
697 			sendUnitScore (server, *bp);
698 		}
699 	}
700 	setScore (getScore (now) + deltaScore, now);
701 	sendScore (server, *this, now);
702 }
703 
countEcoSpheres()704 void cPlayer::countEcoSpheres()
705 {
706 	numEcos = 0;
707 
708 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
709 	{
710 		const auto& bp = *i;
711 		if (bp->data.canScore && bp->isUnitWorking())
712 			++numEcos;
713 	}
714 }
715 
setScore(int s,int turn)716 void cPlayer::setScore (int s, int turn)
717 {
718 	// turn begins at 1.
719 	unsigned int t = turn;
720 
721 	if (pointsHistory.size() < t)
722 		pointsHistory.resize (t);
723 	pointsHistory[t - 1] = s;
724 }
725 
clearDone()726 void cPlayer::clearDone()
727 {
728 	for (auto i = vehicles.begin(); i != vehicles.end(); ++i)
729 	{
730 		const auto& unit = *i;
731 		unit->setMarkedAsDone (false);
732 	}
733 
734 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
735 	{
736 		const auto& unit = *i;
737 		unit->setMarkedAsDone (false);
738 	}
739 }
740 
getScore(int turn) const741 int cPlayer::getScore (int turn) const
742 {
743 	// turn begins at 1.
744 	unsigned int t = turn;
745 
746 	if (pointsHistory.size() < t)
747 	{
748 		const int score = pointsHistory.empty() ? 0 : pointsHistory.back();
749 		pointsHistory.resize (t, score);
750 	}
751 	return pointsHistory[t - 1];
752 }
753 
getScore() const754 int cPlayer::getScore() const
755 {
756 	return pointsHistory.back();
757 }
758 
759 //------------------------------------------------------------------------------
upgradeUnitTypes(const std::vector<int> & areasReachingNextLevel,std::vector<sUnitData * > & resultUpgradedUnitDatas)760 void cPlayer::upgradeUnitTypes (const std::vector<int>& areasReachingNextLevel, std::vector<sUnitData*>& resultUpgradedUnitDatas)
761 {
762 	for (unsigned int i = 0; i < UnitsData.getNrVehicles(); i++)
763 	{
764 		const sUnitData& originalData = UnitsData.getVehicle (i, getClan());
765 		bool incrementVersion = false;
766 		for (size_t areaCounter = 0; areaCounter != areasReachingNextLevel.size(); areaCounter++)
767 		{
768 			const int researchArea = areasReachingNextLevel[areaCounter];
769 			const int newResearchLevel = researchState.getCurResearchLevel (researchArea);
770 			int startValue = 0;
771 			switch (researchArea)
772 			{
773 				case cResearch::kAttackResearch: startValue = originalData.getDamage(); break;
774 				case cResearch::kShotsResearch: startValue = originalData.getShotsMax(); break;
775 				case cResearch::kRangeResearch: startValue = originalData.getRange(); break;
776 				case cResearch::kArmorResearch: startValue = originalData.getArmor(); break;
777 				case cResearch::kHitpointsResearch: startValue = originalData.getHitpointsMax(); break;
778 				case cResearch::kScanResearch: startValue = originalData.getScan(); break;
779 				case cResearch::kSpeedResearch: startValue = originalData.getSpeedMax(); break;
780 				case cResearch::kCostResearch: startValue = originalData.buildCosts; break;
781 			}
782 			int oldResearchBonus = cUpgradeCalculator::instance().calcChangeByResearch (startValue, newResearchLevel - 10,
783 								   researchArea == cResearch::kCostResearch ? cUpgradeCalculator::kCost : -1,
784 								   originalData.isHuman ? cUpgradeCalculator::kInfantry : cUpgradeCalculator::kStandardUnit);
785 			int newResearchBonus = cUpgradeCalculator::instance().calcChangeByResearch (startValue, newResearchLevel,
786 								   researchArea == cResearch::kCostResearch ? cUpgradeCalculator::kCost : -1,
787 								   originalData.isHuman ? cUpgradeCalculator::kInfantry : cUpgradeCalculator::kStandardUnit);
788 			if (oldResearchBonus != newResearchBonus)
789 			{
790 				switch (researchArea)
791 				{
792 					case cResearch::kAttackResearch: VehicleData[i].setDamage (VehicleData[i].getDamage() + newResearchBonus - oldResearchBonus); break;
793 					case cResearch::kShotsResearch: VehicleData[i].setShotsMax (VehicleData[i].getShotsMax() + newResearchBonus - oldResearchBonus); break;
794 					case cResearch::kRangeResearch: VehicleData[i].setRange (VehicleData[i].getRange() + newResearchBonus - oldResearchBonus); break;
795 					case cResearch::kArmorResearch: VehicleData[i].setArmor (VehicleData[i].getArmor() + newResearchBonus - oldResearchBonus); break;
796 					case cResearch::kHitpointsResearch: VehicleData[i].setHitpointsMax (VehicleData[i].getHitpointsMax() + newResearchBonus - oldResearchBonus); break;
797 					case cResearch::kScanResearch: VehicleData[i].setScan (VehicleData[i].getScan() + newResearchBonus - oldResearchBonus); break;
798 					case cResearch::kSpeedResearch: VehicleData[i].setSpeedMax (VehicleData[i].getSpeedMax() + newResearchBonus - oldResearchBonus); break;
799 					case cResearch::kCostResearch: VehicleData[i].buildCosts += newResearchBonus - oldResearchBonus; break;
800 				}
801 				if (researchArea != cResearch::kCostResearch)   // don't increment the version, if the only change are the costs
802 					incrementVersion = true;
803 				if (!Contains (resultUpgradedUnitDatas, & (VehicleData[i])))
804 					resultUpgradedUnitDatas.push_back (& (VehicleData[i]));
805 			}
806 		}
807 		if (incrementVersion)
808 			VehicleData[i].setVersion (VehicleData[i].getVersion() + 1);
809 	}
810 
811 	for (unsigned int i = 0; i < UnitsData.getNrBuildings(); i++)
812 	{
813 		const sUnitData& originalData = UnitsData.getBuilding (i, getClan());
814 		bool incrementVersion = false;
815 		for (size_t areaCounter = 0; areaCounter != areasReachingNextLevel.size(); areaCounter++)
816 		{
817 			const int researchArea = areasReachingNextLevel[areaCounter];
818 			const int newResearchLevel = researchState.getCurResearchLevel (researchArea);
819 
820 			int startValue = 0;
821 			switch (researchArea)
822 			{
823 				case cResearch::kAttackResearch: startValue = originalData.getDamage(); break;
824 				case cResearch::kShotsResearch: startValue = originalData.getShotsMax(); break;
825 				case cResearch::kRangeResearch: startValue = originalData.getRange(); break;
826 				case cResearch::kArmorResearch: startValue = originalData.getArmor(); break;
827 				case cResearch::kHitpointsResearch: startValue = originalData.getHitpointsMax(); break;
828 				case cResearch::kScanResearch: startValue = originalData.getScan(); break;
829 				case cResearch::kCostResearch: startValue = originalData.buildCosts; break;
830 			}
831 			int oldResearchBonus = cUpgradeCalculator::instance().calcChangeByResearch (startValue, newResearchLevel - 10,
832 								   researchArea == cResearch::kCostResearch ? cUpgradeCalculator::kCost : -1,
833 								   cUpgradeCalculator::kBuilding);
834 			int newResearchBonus = cUpgradeCalculator::instance().calcChangeByResearch (startValue, newResearchLevel,
835 								   researchArea == cResearch::kCostResearch ? cUpgradeCalculator::kCost : -1,
836 								   cUpgradeCalculator::kBuilding);
837 			if (oldResearchBonus != newResearchBonus)
838 			{
839 				switch (researchArea)
840 				{
841 					case cResearch::kAttackResearch: BuildingData[i].setDamage (BuildingData[i].getDamage() + newResearchBonus - oldResearchBonus); break;
842 					case cResearch::kShotsResearch: BuildingData[i].setShotsMax (BuildingData[i] .getShotsMax() + newResearchBonus - oldResearchBonus); break;
843 					case cResearch::kRangeResearch: BuildingData[i].setRange (BuildingData[i].getRange() + newResearchBonus - oldResearchBonus); break;
844 					case cResearch::kArmorResearch: BuildingData[i].setArmor (BuildingData[i].getArmor() + newResearchBonus - oldResearchBonus); break;
845 					case cResearch::kHitpointsResearch: BuildingData[i].setHitpointsMax (BuildingData[i].getHitpointsMax() + newResearchBonus - oldResearchBonus); break;
846 					case cResearch::kScanResearch: BuildingData[i].setScan (BuildingData[i].getScan() + newResearchBonus - oldResearchBonus); break;
847 					case cResearch::kCostResearch: BuildingData[i].buildCosts += newResearchBonus - oldResearchBonus; break;
848 				}
849 				if (researchArea != cResearch::kCostResearch)   // don't increment the version, if the only change are the costs
850 					incrementVersion = true;
851 				if (!Contains (resultUpgradedUnitDatas, & (BuildingData[i])))
852 					resultUpgradedUnitDatas.push_back (& (BuildingData[i]));
853 			}
854 		}
855 		if (incrementVersion)
856 			BuildingData[i].setVersion (BuildingData[i].getVersion() + 1);
857 	}
858 }
859 
860 //------------------------------------------------------------------------------
refreshResearchCentersWorkingOnArea()861 void cPlayer::refreshResearchCentersWorkingOnArea()
862 {
863 	int oldResearchCentersWorkingOnArea[cResearch::kNrResearchAreas];
864 
865 	int newResearchCount = 0;
866 	for (int i = 0; i < cResearch::kNrResearchAreas; i++)
867 	{
868 		oldResearchCentersWorkingOnArea[i] = researchCentersWorkingOnArea[i];
869 		researchCentersWorkingOnArea[i] = 0;
870 	}
871 
872 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
873 	{
874 		const auto& building = *i;
875 		if (building->data.canResearch && building->isUnitWorking())
876 		{
877 			researchCentersWorkingOnArea[building->getResearchArea()] += 1;
878 			newResearchCount++;
879 		}
880 	}
881 	std::swap (researchCentersWorkingTotal, newResearchCount);
882 
883 	for (int i = 0; i < cResearch::kNrResearchAreas; i++)
884 	{
885 		if (oldResearchCentersWorkingOnArea[i] != researchCentersWorkingOnArea[i])
886 		{
887 			researchCentersWorkingOnAreaChanged ((cResearch::ResearchArea)i);
888 		}
889 	}
890 	if (researchCentersWorkingTotal != newResearchCount) researchCentersWorkingTotalChanged();
891 }
892 
893 //------------------------------------------------------------------------------
mayHaveOffensiveUnit() const894 bool cPlayer::mayHaveOffensiveUnit() const
895 {
896 	for (auto i = vehicles.begin(); i != vehicles.end(); ++i)
897 	{
898 		const auto& vehicle = *i;
899 		if (vehicle->data.canAttack || !vehicle->data.canBuild.empty()) return true;
900 	}
901 	for (auto i = buildings.begin(); i != buildings.end(); ++i)
902 	{
903 		const auto& building = *i;
904 		if (building->data.canAttack || !building->data.canBuild.empty()) return true;
905 	}
906 	return false;
907 }
908 
909 //------------------------------------------------------------------------------
addTurnReportUnit(const sID & unitTypeId)910 void cPlayer::addTurnReportUnit (const sID& unitTypeId)
911 {
912 	auto iter = std::find_if (currentTurnUnitReports.begin(), currentTurnUnitReports.end(), [unitTypeId] (const sTurnstartReport & entry) { return entry.type == unitTypeId; });
913 	if (iter != currentTurnUnitReports.end())
914 	{
915 		++iter->count;
916 	}
917 	else
918 	{
919 		sTurnstartReport entry;
920 		entry.type = unitTypeId;
921 		entry.count = 1;
922 		currentTurnUnitReports.push_back (entry);
923 	}
924 }
925 
926 //------------------------------------------------------------------------------
resetTurnReportData()927 void cPlayer::resetTurnReportData()
928 {
929 	currentTurnUnitReports.clear();
930 }
931 
932 //------------------------------------------------------------------------------
getCurrentTurnUnitReports() const933 const std::vector<sTurnstartReport>& cPlayer::getCurrentTurnUnitReports() const
934 {
935 	return currentTurnUnitReports;
936 }
937 
938 //------------------------------------------------------------------------------
getCurrentTurnResearchAreasFinished() const939 const std::vector<int>& cPlayer::getCurrentTurnResearchAreasFinished() const
940 {
941 	return currentTurnResearchAreasFinished;
942 }
943 
944 //------------------------------------------------------------------------------
setCurrentTurnResearchAreasFinished(std::vector<int> areas)945 void cPlayer::setCurrentTurnResearchAreasFinished (std::vector<int> areas)
946 {
947 	currentTurnResearchAreasFinished = std::move (areas);
948 }
949 
950 //------------------------------------------------------------------------------
isCurrentTurnResearchAreaFinished(cResearch::ResearchArea area) const951 bool cPlayer::isCurrentTurnResearchAreaFinished (cResearch::ResearchArea area) const
952 {
953 	return std::find (currentTurnResearchAreasFinished.begin(), currentTurnResearchAreasFinished.end(), area) != currentTurnResearchAreasFinished.end();
954 }
955 
956 //------------------------------------------------------------------------------
getResearchState() const957 const cResearch& cPlayer::getResearchState() const
958 {
959 	return researchState;
960 }
961 
962 //------------------------------------------------------------------------------
getResearchState()963 cResearch& cPlayer::getResearchState()
964 {
965 	return researchState;
966 }
967 
968 //------------------------------------------------------------------------------
getResearchCentersWorkingTotal() const969 int cPlayer::getResearchCentersWorkingTotal() const
970 {
971 	return researchCentersWorkingTotal;
972 }
973 
974 //------------------------------------------------------------------------------
getResearchCentersWorkingOnArea(cResearch::ResearchArea area) const975 int cPlayer::getResearchCentersWorkingOnArea (cResearch::ResearchArea area) const
976 {
977 	return researchCentersWorkingOnArea[area];
978 }
979 
980 //------------------------------------------------------------------------------
canSeeAt(const cPosition & position) const981 bool cPlayer::canSeeAt (const cPosition& position) const
982 {
983 	if (position.x() < 0 || position.x() >= mapSize.x() || position.y() < 0 || position.y() >= mapSize.y()) return false;
984 
985 	return ScanMap[getOffset (position)] != 0;
986 }
987 
988 //------------------------------------------------------------------------------
drawSpecialCircle(const cPosition & position,int iRadius,std::vector<char> & map,const cPosition & mapsize)989 void cPlayer::drawSpecialCircle (const cPosition& position, int iRadius, std::vector<char>& map, const cPosition& mapsize)
990 {
991 	const float PI_ON_180 = 0.017453f;
992 	const float PI_ON_4 = PI_ON_180 * 45;
993 	if (iRadius <= 0) return;
994 
995 	iRadius *= 10;
996 	const float step = (PI_ON_180 * 90 - acosf (1.0f / iRadius)) / 2;
997 
998 	for (float angle = 0; angle <= PI_ON_4; angle += step)
999 	{
1000 		int rx = (int) (cosf (angle) * iRadius);
1001 		int ry = (int) (sinf (angle) * iRadius);
1002 		rx /= 10;
1003 		ry /= 10;
1004 
1005 		int x1 = rx + position.x();
1006 		int x2 = -rx + position.x();
1007 		for (int k = x2; k <= x1; k++)
1008 		{
1009 			if (k < 0) continue;
1010 			if (k >= mapsize.x()) break;
1011 			if (position.y() + ry >= 0 && position.y() + ry < mapsize.y())
1012 				map[k + (position.y() + ry) * mapsize.x()] |= 1;
1013 			if (position.y() - ry >= 0 && position.y() - ry < mapsize.y())
1014 				map[k + (position.y() - ry) * mapsize.x()] |= 1;
1015 		}
1016 
1017 		x1 = ry + position.x();
1018 		x2 = -ry + position.x();
1019 		for (int k = x2; k <= x1; k++)
1020 		{
1021 			if (k < 0) continue;
1022 			if (k >= mapsize.x()) break;
1023 			if (position.y() + rx >= 0 && position.y() + rx < mapsize.y())
1024 				map[k + (position.y() + rx) *mapsize.x()] |= 1;
1025 			if (position.y() - rx >= 0 && position.y() - rx < mapsize.y())
1026 				map[k + (position.y() - rx) *mapsize.x()] |= 1;
1027 		}
1028 	}
1029 }
1030 
1031 //------------------------------------------------------------------------------
drawSpecialCircleBig(const cPosition & position,int iRadius,std::vector<char> & map,const cPosition & mapsize)1032 void cPlayer::drawSpecialCircleBig (const cPosition& position, int iRadius, std::vector<char>& map, const cPosition& mapsize)
1033 {
1034 	const float PI_ON_180 = 0.017453f;
1035 	const float PI_ON_4 = PI_ON_180 * 45;
1036 	if (iRadius <= 0) return;
1037 
1038 	--iRadius;
1039 	iRadius *= 10;
1040 	const float step = (PI_ON_180 * 90 - acosf (1.0f / iRadius)) / 2;
1041 	for (float angle = 0; angle <= PI_ON_4; angle += step)
1042 	{
1043 		int rx = (int) (cosf (angle) * iRadius);
1044 		int ry = (int) (sinf (angle) * iRadius);
1045 		rx /= 10;
1046 		ry /= 10;
1047 
1048 		int x1 = rx + position.x();
1049 		int x2 = -rx + position.x();
1050 		for (int k = x2; k <= x1 + 1; k++)
1051 		{
1052 			if (k < 0) continue;
1053 			if (k >= mapsize.x()) break;
1054 			if (position.y() + ry >= 0 && position.y() + ry < mapsize.y())
1055 				map[k + (position.y() + ry) *mapsize.x()] |= 1;
1056 			if (position.y() - ry >= 0 && position.y() - ry < mapsize.y())
1057 				map[k + (position.y() - ry) *mapsize.x()] |= 1;
1058 
1059 			if (position.y() + ry + 1 >= 0 && position.y() + ry + 1 < mapsize.y())
1060 				map[k + (position.y() + ry + 1) *mapsize.x()] |= 1;
1061 			if (position.y() - ry + 1 >= 0 && position.y() - ry + 1 < mapsize.y())
1062 				map[k + (position.y() - ry + 1) *mapsize.x()] |= 1;
1063 		}
1064 
1065 		x1 = ry + position.x();
1066 		x2 = -ry + position.x();
1067 		for (int k = x2; k <= x1 + 1; k++)
1068 		{
1069 			if (k < 0) continue;
1070 			if (k >= mapsize.x()) break;
1071 			if (position.y() + rx >= 0 && position.y() + rx < mapsize.y())
1072 				map[k + (position.y() + rx) *mapsize.x()] |= 1;
1073 			if (position.y() - rx >= 0 && position.y() - rx < mapsize.y())
1074 				map[k + (position.y() - rx) *mapsize.x()] |= 1;
1075 
1076 			if (position.y() + rx + 1 >= 0 && position.y() + rx + 1 < mapsize.y())
1077 				map[k + (position.y() + rx + 1) *mapsize.x()] |= 1;
1078 			if (position.y() - rx + 1 >= 0 && position.y() - rx + 1 < mapsize.y())
1079 				map[k + (position.y() - rx + 1) *mapsize.x()] |= 1;
1080 		}
1081 	}
1082 }
1083 
1084 //------------------------------------------------------------------------------
addSavedReport(std::unique_ptr<cSavedReport> savedReport)1085 void cPlayer::addSavedReport (std::unique_ptr<cSavedReport> savedReport)
1086 {
1087 	if (savedReport == nullptr) return;
1088 
1089 	savedReportsList.push_back (std::move (savedReport));
1090 
1091 	reportAdded (*savedReportsList.back());
1092 }
1093 
1094 //------------------------------------------------------------------------------
getSavedReports() const1095 const std::vector<std::unique_ptr<cSavedReport>>& cPlayer::getSavedReports() const
1096 {
1097 	return savedReportsList;
1098 }
1099 
1100 //------------------------------------------------------------------------------
getHasFinishedTurn() const1101 bool cPlayer::getHasFinishedTurn() const
1102 {
1103 	return hasFinishedTurn;
1104 }
1105 
1106 //------------------------------------------------------------------------------
setHasFinishedTurn(bool value)1107 void cPlayer::setHasFinishedTurn (bool value)
1108 {
1109 	std::swap (hasFinishedTurn, value);
1110 	if (hasFinishedTurn != value) hasFinishedTurnChanged();
1111 }
1112 
1113 //------------------------------------------------------------------------------
getIsRemovedFromGame() const1114 bool cPlayer::getIsRemovedFromGame() const
1115 {
1116 	return isRemovedFromGame;
1117 }
1118 
1119 //------------------------------------------------------------------------------
setIsRemovedFromGame(bool value)1120 void cPlayer::setIsRemovedFromGame (bool value)
1121 {
1122 	std::swap (isRemovedFromGame, value);
1123 	if (isRemovedFromGame != value) isRemovedFromGameChanged();
1124 }
1125