1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name player.cpp - The player source file. */
12 //
13 //      (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon, Nehal Mistry
14 //		and Andrettin
15 //
16 //      This program is free software; you can redistribute it and/or modify
17 //      it under the terms of the GNU General Public License as published by
18 //      the Free Software Foundation; only version 2 of the License.
19 //
20 //      This program is distributed in the hope that it will be useful,
21 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
22 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 //      GNU General Public License for more details.
24 //
25 //      You should have received a copy of the GNU General Public License
26 //      along with this program; if not, write to the Free Software
27 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 //      02111-1307, USA.
29 //
30 
31 //@{
32 
33 /*----------------------------------------------------------------------------
34 -- Includes
35 ----------------------------------------------------------------------------*/
36 
37 #include <stdarg.h>
38 
39 #include "stratagus.h"
40 
41 #include "player.h"
42 
43 #include "action/action_upgradeto.h"
44 #include "actions.h"
45 #include "age.h"
46 #include "ai.h"
47 //Wyrmgus start
48 #include "../ai/ai_local.h" //for using AiHelpers
49 #include "civilization.h"
50 #include "commands.h" //for faction setting
51 #include "currency.h"
52 #include "editor.h"
53 #include "font.h"
54 #include "game.h"
55 #include "iocompat.h"
56 //Wyrmgus end
57 #include "iolib.h"
58 //Wyrmgus start
59 #include "grand_strategy.h"
60 #include "luacallback.h"
61 //Wyrmgus end
62 #include "map/map.h"
63 #include "map/map_layer.h"
64 #include "map/site.h"
65 #include "network.h"
66 #include "netconnect.h"
67 //Wyrmgus start
68 #include "parameters.h"
69 #include "quest.h"
70 #include "religion/deity.h"
71 #include "religion/deity_domain.h"
72 #include "religion/religion.h"
73 #include "settings.h"
74 //Wyrmgus end
75 #include "sound.h"
76 #include "time/calendar.h"
77 #include "time/time_of_day.h"
78 #include "translate.h"
79 #include "ui/button_action.h"
80 #include "ui/ui.h"
81 #include "unit/unit.h"
82 //Wyrmgus start
83 #include "unit/unit_find.h"
84 #include "unit/unittype.h"
85 //Wyrmgus end
86 #include "unitsound.h"
87 #include "upgrade/dependency.h"
88 //Wyrmgus start
89 #include "upgrade/upgrade.h"
90 //Wyrmgus end
91 #include "upgrade/upgrade_modifier.h"
92 #include "video.h"
93 #include "world.h"
94 
95 //Wyrmgus start
96 #include "../ai/ai_local.h"
97 //Wyrmgus end
98 
99 /*----------------------------------------------------------------------------
100 --  Documentation
101 ----------------------------------------------------------------------------*/
102 
103 /**
104 **  @class CPlayer player.h
105 **
106 **  \#include "player.h"
107 **
108 **  This structure contains all information about a player in game.
109 **
110 **  The player structure members:
111 **
112 **  CPlayer::Player
113 **
114 **    This is the unique slot number. It is not possible that two
115 **    players have the same slot number at the same time. The slot
116 **    numbers are reused in the future. This means if a player is
117 **    defeated, a new player can join using this slot. Currently
118 **    #PlayerMax (16) players are supported. This member is used to
119 **    access bit fields.
120 **    Slot #PlayerNumNeutral (15) is reserved for the neutral units
121 **    like gold-mines or critters.
122 **
123 **    @note Should call this member Slot?
124 **
125 **  CPlayer::Name
126 **
127 **    Name of the player used for displays and network game.
128 **    It is restricted to 15 characters plus final zero.
129 **
130 **  CPlayer::Type
131 **
132 **    Type of the player. This field is setup from the level (map).
133 **    We support currently #PlayerNeutral,
134 **    #PlayerNobody, #PlayerComputer, #PlayerPerson,
135 **    #PlayerRescuePassive and #PlayerRescueActive.
136 **    @see #PlayerTypes.
137 **
138 **  CPlayer::RaceName
139 **
140 **    Name of the race to which the player belongs, used to select
141 **    the user interface and the AI.
142 **    We have 'orc', 'human', 'alliance' or 'mythical'. Should
143 **    only be used during configuration and not during runtime.
144 **
145 **  CPlayer::Race
146 **
147 **    Race number of the player. This field is setup from the level
148 **    map. This number is mapped with #PlayerRaces to the symbolic
149 **    name CPlayer::RaceName.
150 **
151 **  CPlayer::AiName
152 **
153 **    AI name for computer. This field is setup
154 **    from the map. Used to select the AI for the computer
155 **    player.
156 **
157 **  CPlayer::Team
158 **
159 **    Team of player. Selected during network game setup. All players
160 **    of the same team are allied and enemy to all other teams.
161 **    @note It is planned to show the team on the map.
162 **
163 **  CPlayer::Enemy
164 **
165 **    A bit field which contains the enemies of this player.
166 **    If CPlayer::Enemy & (1<<CPlayer::Player) != 0 its an enemy.
167 **    Setup during startup using the CPlayer::Team, can later be
168 **    changed with diplomacy. CPlayer::Enemy and CPlayer::Allied
169 **    are combined, if none bit is set, the player is neutral.
170 **    @note You can be allied to a player, which sees you as enemy.
171 **
172 **  CPlayer::Allied
173 **
174 **    A bit field which contains the allies of this player.
175 **    If CPlayer::Allied & (1<<CPlayer::Player) != 0 its an allied.
176 **    Setup during startup using the Player:Team, can later be
177 **    changed with diplomacy. CPlayer::Enemy and CPlayer::Allied
178 **    are combined, if none bit is set, the player is neutral.
179 **    @note You can be allied to a player, which sees you as enemy.
180 **
181 **  CPlayer::SharedVision
182 **
183 **    A bit field which contains shared vision for this player.
184 **    Shared vision only works when it's activated both ways. Really.
185 **
186 **  CPlayer::StartX CPlayer::StartY
187 **
188 **    The tile map coordinates of the player start position. 0,0 is
189 **    the upper left on the map. This members are setup from the
190 **    map and only important for the game start.
191 **    Ignored if game starts with level settings. Used to place
192 **    the initial workers if you play with 1 or 3 workers.
193 **
194 **  CPlayer::Resources[::MaxCosts]
195 **
196 **    How many resources the player owns. Needed for building
197 **    units and structures.
198 **    @see _costs_, TimeCost, GoldCost, WoodCost, OilCost, MaxCosts.
199 **
200 **  CPlayer::MaxResources[::MaxCosts]
201 **
202 **    How many resources the player can store at the moment.
203 **
204 **  CPlayer::Incomes[::MaxCosts]
205 **
206 **    Income of the resources, when they are delivered at a store.
207 **    @see _costs_, TimeCost, GoldCost, WoodCost, OilCost, MaxCosts.
208 **
209 **  CPlayer::LastResources[::MaxCosts]
210 **
211 **    Keeps track of resources in time (used for calculating
212 **    CPlayer::Revenue, see below)
213 **
214 **  CPlayer::Revenue[::MaxCosts]
215 **
216 **    Production of resources per minute (or estimates)
217 **    Used just as information (statistics) for the player...
218 **
219 **  CPlayer::UnitTypesCount[::UnitTypeMax]
220 **
221 **    Total count for each different unit type. Used by the AI and
222 **    for dependencies checks. The addition of all counts should
223 **    be CPlayer::TotalNumUnits.
224 **    @note Should not use the maximum number of unit-types here,
225 **    only the real number of unit-types used.
226 **
227 **  CPlayer::AiEnabled
228 **
229 **    If the player is controlled by the computer and this flag is
230 **    true, than the player is handled by the AI on this local
231 **    computer.
232 **
233 **    @note Currently the AI is calculated parallel on all computers
234 **    in a network play. It is planned to change this.
235 **
236 **  CPlayer::Ai
237 **
238 **    AI structure pointer. Please look at #PlayerAi for more
239 **    information.
240 **
241 **  CPlayer::Units
242 **
243 **    A table of all (CPlayer::TotalNumUnits) units of the player.
244 **
245 **  CPlayer::TotalNumUnits
246 **
247 **    Total number of units (incl. buildings) in the CPlayer::Units
248 **    table.
249 **
250 **  CPlayer::Demand
251 **
252 **    Total unit demand, used to demand limit.
253 **    A player can only build up to CPlayer::Food units and not more
254 **    than CPlayer::FoodUnitLimit units.
255 **
256 **    @note that CPlayer::NumFoodUnits > CPlayer::Food, when enough
257 **    farms are destroyed.
258 **
259 **  CPlayer::NumBuildings
260 **
261 **    Total number buildings, units that don't need food.
262 **
263 **  CPlayer::Food
264 **
265 **    Number of food available/produced. Player can't train more
266 **    CPlayer::NumFoodUnits than this.
267 **    @note that all limits are always checked.
268 **
269 **  CPlayer::FoodUnitLimit
270 **
271 **    Number of food units allowed. Player can't train more
272 **    CPlayer::NumFoodUnits than this.
273 **    @note that all limits are always checked.
274 **
275 **  CPlayer::BuildingLimit
276 **
277 **    Number of buildings allowed.  Player can't build more
278 **    CPlayer::NumBuildings than this.
279 **    @note that all limits are always checked.
280 **
281 **  CPlayer::TotalUnitLimit
282 **
283 **    Number of total units allowed. Player can't have more
284 **    CPlayer::NumFoodUnits+CPlayer::NumBuildings=CPlayer::TotalNumUnits
285 **    this.
286 **    @note that all limits are always checked.
287 **
288 **  CPlayer::Score
289 **
290 **    Total number of points. You can get points for killing units,
291 **    destroying buildings ...
292 **
293 **  CPlayer::TotalUnits
294 **
295 **    Total number of units made.
296 **
297 **  CPlayer::TotalBuildings
298 **
299 **    Total number of buildings made.
300 **
301 **  CPlayer::TotalResources[::MaxCosts]
302 **
303 **    Total number of resources collected.
304 **    @see _costs_, TimeCost, GoldCost, WoodCost, OilCost, MaxCosts.
305 **
306 **  CPlayer::TotalRazings
307 **
308 **    Total number of buildings destroyed.
309 **
310 **  CPlayer::TotalKills
311 **
312 **    Total number of kills.
313 **
314 **  CPlayer::Color
315 **
316 **    Color of units of this player on the minimap. Index number
317 **    into the global palette.
318 **
319 **  CPlayer::UnitColors
320 **
321 **    Unit colors of this player. Contains the hardware dependent
322 **    pixel values for the player colors (palette index #208-#211).
323 **    Setup from the global palette.
324 **    @note Index #208-#211 are various SHADES of the team color
325 **    (#208 is brightest shade, #211 is darkest shade) .... these
326 **    numbers are NOT red=#208, blue=#209, etc
327 **
328 **  CPlayer::Allow
329 **
330 **    Contains which unit-types and upgrades are allowed for the
331 **    player. Possible values are:
332 **    @li  'A' -- allowed,
333 **    @li  'F' -- forbidden,
334 **    @li  'R' -- acquired, perhaps other values
335 **    @li  'Q' -- acquired but forbidden (does it make sense?:))
336 **    @li  'E' -- enabled, allowed by level but currently forbidden
337 **    @see CAllow
338 **
339 **  CPlayer::UpgradeTimers
340 **
341 **    Timer for the upgrades. One timer for all possible upgrades.
342 **    Initial 0 counted up by the upgrade action, until it reaches
343 **    the upgrade time.
344 **    @see _upgrade_timers_
345 **    @note it is planned to combine research for faster upgrades.
346 */
347 
348 /*----------------------------------------------------------------------------
349 --  Variables
350 ----------------------------------------------------------------------------*/
351 
352 int NumPlayers;                  /// How many player slots used
353 CPlayer Players[PlayerMax];       /// All players in play
354 CPlayer *ThisPlayer;              /// Player on this computer
355 PlayerRace PlayerRaces;          /// Player races
356 
357 bool NoRescueCheck;               /// Disable rescue check
358 
359 /**
360 **  Colors used for minimap.
361 */
362 //Wyrmgus start
363 //std::vector<CColor> PlayerColorsRGB[PlayerMax];
364 //std::vector<IntColor> PlayerColors[PlayerMax];
365 
366 //std::string PlayerColorNames[PlayerMax];
367 std::vector<CColor> PlayerColorsRGB[PlayerColorMax];
368 std::vector<IntColor> PlayerColors[PlayerColorMax];
369 std::string PlayerColorNames[PlayerColorMax];
370 std::vector<int> ConversiblePlayerColors;
371 //Wyrmgus end
372 
373 /**
374 **  Which indexes to replace with player color
375 */
376 int PlayerColorIndexStart;
377 int PlayerColorIndexCount;
378 
379 //Wyrmgus start
380 std::map<std::string, int> FactionStringToIndex;
381 std::map<std::string, int> DynastyStringToIndex;
382 std::map<std::string, CLanguage *> LanguageIdentToPointer;
383 
384 bool LanguageCacheOutdated = false;
385 //Wyrmgus end
386 
387 /*----------------------------------------------------------------------------
388 --  Functions
389 ----------------------------------------------------------------------------*/
390 
391 /**
392 **  Clean up the PlayerRaces names.
393 */
Clean()394 void PlayerRace::Clean()
395 {
396 	//Wyrmgus start
397 	if (!CCivilization::Civilizations.empty()) { //don't clean the languages if first defining the civilizations
398 		for (size_t i = 0; i < this->Languages.size(); ++i) {
399 			for (size_t j = 0; j < this->Languages[i]->LanguageWords.size(); ++j) {
400 				for (size_t k = 0; k < this->Languages[i]->Dialects.size(); ++k) { //remove word from dialects, so that they don't try to delete it too
401 					this->Languages[i]->Dialects[k]->RemoveWord(this->Languages[i]->LanguageWords[j]);
402 				}
403 
404 				delete this->Languages[i]->LanguageWords[j];
405 			}
406 			this->Languages[i]->LanguageWords.clear();
407 
408 			this->Languages[i]->NameTranslations.clear();
409 		}
410 	}
411 	//Wyrmgus end
412 	for (size_t i = 0; i != CCivilization::Civilizations.size(); ++i) {
413 		this->Name[i].clear();
414 		this->Display[i].clear();
415 		this->Visible[i] = false;
416 		//Wyrmgus start
417 		this->CivilizationUpgrades[i].clear();
418 		this->CivilizationClassUnitTypes[i].clear();
419 		this->CivilizationClassUpgrades[i].clear();
420 		this->Playable[i] = false;
421 		this->Species[i].clear();
422 		this->DefaultColor[i].clear();
423 		this->DevelopsFrom[i].clear();
424 		this->DevelopsTo[i].clear();
425 		this->CivilizationUIFillers[i].clear();
426 		//Wyrmgus end
427 	}
428 	//Wyrmgus start
429 	for (size_t i = 0; i < PlayerRaces.Factions.size(); ++i) {
430 		delete this->Factions[i];
431 	}
432 	this->Factions.clear();
433 	for (size_t i = 0; i < PlayerRaces.Dynasties.size(); ++i) {
434 		delete this->Dynasties[i];
435 	}
436 	this->Dynasties.clear();
437 	//Wyrmgus end
438 }
439 
440 //Wyrmgus start
GetFactionIndexByName(const std::string & faction_ident) const441 int PlayerRace::GetFactionIndexByName(const std::string &faction_ident) const
442 {
443 	if (faction_ident.empty()) {
444 		return -1;
445 	}
446 
447 	if (FactionStringToIndex.find(faction_ident) != FactionStringToIndex.end()) {
448 		return FactionStringToIndex[faction_ident];
449 	} else {
450 		return -1;
451 	}
452 }
453 
GetFaction(const std::string & faction_ident) const454 CFaction *PlayerRace::GetFaction(const std::string &faction_ident) const
455 {
456 	if (faction_ident.empty()) {
457 		return nullptr;
458 	}
459 
460 	if (FactionStringToIndex.find(faction_ident) != FactionStringToIndex.end()) {
461 		return PlayerRaces.Factions[FactionStringToIndex[faction_ident]];
462 	} else {
463 		return nullptr;
464 	}
465 }
466 
GetDynasty(const std::string & dynasty_ident) const467 CDynasty *PlayerRace::GetDynasty(const std::string &dynasty_ident) const
468 {
469 	if (dynasty_ident.empty()) {
470 		return nullptr;
471 	}
472 
473 	if (DynastyStringToIndex.find(dynasty_ident) != DynastyStringToIndex.end()) {
474 		return PlayerRaces.Dynasties[DynastyStringToIndex[dynasty_ident]];
475 	} else {
476 		return nullptr;
477 	}
478 }
479 
GetLanguage(const std::string & language_ident) const480 CLanguage *PlayerRace::GetLanguage(const std::string &language_ident) const
481 {
482 	if (LanguageIdentToPointer.find(language_ident) != LanguageIdentToPointer.end()) {
483 		return LanguageIdentToPointer[language_ident];
484 	}
485 	return nullptr;
486 }
487 
GetCivilizationClassUnitType(int civilization,int class_id)488 int PlayerRace::GetCivilizationClassUnitType(int civilization, int class_id)
489 {
490 	if (civilization == -1 || class_id == -1) {
491 		return -1;
492 	}
493 
494 	if (CivilizationClassUnitTypes[civilization].find(class_id) != CivilizationClassUnitTypes[civilization].end()) {
495 		return CivilizationClassUnitTypes[civilization][class_id];
496 	}
497 
498 	if (CCivilization::Civilizations[civilization]->ParentCivilization) {
499 		return GetCivilizationClassUnitType(CCivilization::Civilizations[civilization]->ParentCivilization->ID, class_id);
500 	}
501 
502 	return -1;
503 }
504 
GetCivilizationClassUpgrade(int civilization,int class_id)505 int PlayerRace::GetCivilizationClassUpgrade(int civilization, int class_id)
506 {
507 	if (civilization == -1 || class_id == -1) {
508 		return -1;
509 	}
510 
511 	if (CivilizationClassUpgrades[civilization].find(class_id) != CivilizationClassUpgrades[civilization].end()) {
512 		return CivilizationClassUpgrades[civilization][class_id];
513 	}
514 
515 	if (CCivilization::Civilizations[civilization]->ParentCivilization) {
516 		return GetCivilizationClassUpgrade(CCivilization::Civilizations[civilization]->ParentCivilization->ID, class_id);
517 	}
518 
519 	return -1;
520 }
521 
GetFactionClassUnitType(int faction,int class_id)522 int PlayerRace::GetFactionClassUnitType(int faction, int class_id)
523 {
524 	if (faction == -1 || class_id == -1) {
525 		return -1;
526 	}
527 
528 	if (PlayerRaces.Factions[faction]->ClassUnitTypes.find(class_id) != PlayerRaces.Factions[faction]->ClassUnitTypes.end()) {
529 		return PlayerRaces.Factions[faction]->ClassUnitTypes[class_id];
530 	}
531 
532 	if (PlayerRaces.Factions[faction]->ParentFaction != -1) {
533 		return GetFactionClassUnitType(PlayerRaces.Factions[faction]->ParentFaction, class_id);
534 	}
535 
536 	return GetCivilizationClassUnitType(PlayerRaces.Factions[faction]->Civilization->ID, class_id);
537 }
538 
GetFactionClassUpgrade(int faction,int class_id)539 int PlayerRace::GetFactionClassUpgrade(int faction, int class_id)
540 {
541 	if (faction == -1 || class_id == -1) {
542 		return -1;
543 	}
544 
545 	if (PlayerRaces.Factions[faction]->ClassUpgrades.find(class_id) != PlayerRaces.Factions[faction]->ClassUpgrades.end()) {
546 		return PlayerRaces.Factions[faction]->ClassUpgrades[class_id];
547 	}
548 
549 	if (PlayerRaces.Factions[faction]->ParentFaction != -1) {
550 		return GetFactionClassUpgrade(PlayerRaces.Factions[faction]->ParentFaction, class_id);
551 	}
552 
553 	return GetCivilizationClassUpgrade(PlayerRaces.Factions[faction]->Civilization->ID, class_id);
554 }
555 
GetCivilizationLanguage(int civilization)556 CLanguage *PlayerRace::GetCivilizationLanguage(int civilization)
557 {
558 	if (civilization == -1) {
559 		return nullptr;
560 	}
561 
562 	if (CCivilization::Civilizations[civilization] && CCivilization::Civilizations[civilization]->Language) {
563 		return CCivilization::Civilizations[civilization]->Language;
564 	}
565 
566 	if (CCivilization::Civilizations[civilization]->ParentCivilization) {
567 		return GetCivilizationLanguage(CCivilization::Civilizations[civilization]->ParentCivilization->ID);
568 	}
569 
570 	return nullptr;
571 }
572 
GetCivilizationUIFillers(int civilization)573 std::vector<CFiller> PlayerRace::GetCivilizationUIFillers(int civilization)
574 {
575 	if (civilization == -1) {
576 		return std::vector<CFiller>();
577 	}
578 
579 	if (CivilizationUIFillers[civilization].size() > 0) {
580 		return CivilizationUIFillers[civilization];
581 	}
582 
583 	if (CCivilization::Civilizations[civilization]->ParentCivilization) {
584 		return GetCivilizationUIFillers(CCivilization::Civilizations[civilization]->ParentCivilization->ID);
585 	}
586 
587 	return std::vector<CFiller>();
588 }
589 
GetFactionUIFillers(int faction)590 std::vector<CFiller> PlayerRace::GetFactionUIFillers(int faction)
591 {
592 	if (faction == -1) {
593 		return std::vector<CFiller>();
594 	}
595 
596 	if (Factions[faction]->UIFillers.size() > 0) {
597 		return Factions[faction]->UIFillers;
598 	}
599 
600 	if (PlayerRaces.Factions[faction]->ParentFaction != -1) {
601 		return GetFactionUIFillers(PlayerRaces.Factions[faction]->ParentFaction);
602 	}
603 
604 	return GetCivilizationUIFillers(PlayerRaces.Factions[faction]->Civilization->ID);
605 }
606 
607 /**
608 **  "Translate" (that is, adapt) a proper name from one culture (civilization) to another.
609 */
TranslateName(const std::string & name,CLanguage * language)610 std::string PlayerRace::TranslateName(const std::string &name, CLanguage *language)
611 {
612 	std::string new_name;
613 
614 	if (!language || name.empty()) {
615 		return new_name;
616 	}
617 
618 	// try to translate the entire name, as a particular translation for it may exist
619 	if (language->NameTranslations.find(name) != language->NameTranslations.end()) {
620 		return language->NameTranslations[name][SyncRand(language->NameTranslations[name].size())];
621 	}
622 
623 	//if adapting the entire name failed, try to match prefixes and suffixes
624 	if (name.size() > 1) {
625 		if (name.find(" ") == std::string::npos) {
626 			for (size_t i = 0; i < name.size(); ++i) {
627 				std::string name_prefix = name.substr(0, i + 1);
628 				std::string name_suffix = CapitalizeString(name.substr(i + 1, name.size() - (i + 1)));
629 
630 	//			fprintf(stdout, "Trying to match prefix \"%s\" and suffix \"%s\" for translating name \"%s\" to the \"%s\" language.\n", name_prefix.c_str(), name_suffix.c_str(), name.c_str(), language->Ident.c_str());
631 
632 				if (language->NameTranslations.find(name_prefix) != language->NameTranslations.end() && language->NameTranslations.find(name_suffix) != language->NameTranslations.end()) { // if both a prefix and suffix have been matched
633 					name_prefix = language->NameTranslations[name_prefix][SyncRand(language->NameTranslations[name_prefix].size())];
634 					name_suffix = language->NameTranslations[name_suffix][SyncRand(language->NameTranslations[name_suffix].size())];
635 					name_suffix = DecapitalizeString(name_suffix);
636 					if (name_prefix.substr(name_prefix.size() - 2, 2) == "gs" && name_suffix.substr(0, 1) == "g") { //if the last two characters of the prefix are "gs", and the first character of the suffix is "g", then remove the final "s" from the prefix (as in "K�niggr�tz")
637 						name_prefix = FindAndReplaceStringEnding(name_prefix, "gs", "g");
638 					}
639 					if (name_prefix.substr(name_prefix.size() - 1, 1) == "s" && name_suffix.substr(0, 1) == "s") { //if the prefix ends in "s" and the suffix begins in "s" as well, then remove the final "s" from the prefix (as in "Josefstadt", "Kronstadt" and "Leopoldstadt")
640 						name_prefix = FindAndReplaceStringEnding(name_prefix, "s", "");
641 					}
642 
643 					return name_prefix + name_suffix;
644 				}
645 			}
646 		} else { // if the name contains a space, try to translate each of its elements separately
647 			size_t previous_pos = 0;
648 			new_name = name;
649 			for (size_t i = 0; i < name.size(); ++i) {
650 				if ((i + 1) == name.size() || name[i + 1] == ' ') {
651 					std::string name_element = TranslateName(name.substr(previous_pos, i + 1 - previous_pos), language);
652 
653 					if (name_element.empty()) {
654 						new_name = "";
655 						break;
656 					}
657 
658 					new_name = FindAndReplaceString(new_name, name.substr(previous_pos, i + 1 - previous_pos), name_element);
659 
660 					previous_pos = i + 2;
661 				}
662 			}
663 		}
664 	}
665 
666 	return new_name;
667 }
668 
~CFaction()669 CFaction::~CFaction()
670 {
671 	for (std::map<int, std::vector<CForceTemplate *>>::iterator iterator = this->ForceTemplates.begin(); iterator != this->ForceTemplates.end(); ++iterator) {
672 		for (size_t i = 0; i < iterator->second.size(); ++i) {
673 			delete iterator->second[i];
674 		}
675 	}
676 
677 	for (size_t i = 0; i < this->AiBuildingTemplates.size(); ++i) {
678 		delete this->AiBuildingTemplates[i];
679 	}
680 
681 	if (this->Conditions) {
682 		delete Conditions;
683 	}
684 
685 	this->UIFillers.clear();
686 }
687 
GetUpgradePriority(const CUpgrade * upgrade) const688 int CFaction::GetUpgradePriority(const CUpgrade *upgrade) const
689 {
690 	if (!upgrade) {
691 		fprintf(stderr, "Error in CFaction::GetUpgradePriority: the upgrade is null.\n");
692 	}
693 
694 	if (this->UpgradePriorities.find(upgrade) != this->UpgradePriorities.end()) {
695 		return this->UpgradePriorities.find(upgrade)->second;
696 	}
697 
698 	if (this->Civilization == nullptr) {
699 		fprintf(stderr, "Error in CFaction::GetUpgradePriority: the faction has no civilization.\n");
700 	}
701 
702 	return this->Civilization->GetUpgradePriority(upgrade);
703 }
704 
GetForceTypeWeight(int force_type) const705 int CFaction::GetForceTypeWeight(int force_type) const
706 {
707 	if (force_type == -1) {
708 		fprintf(stderr, "Error in CFaction::GetForceTypeWeight: the force_type is -1.\n");
709 	}
710 
711 	if (this->ForceTypeWeights.find(force_type) != this->ForceTypeWeights.end()) {
712 		return this->ForceTypeWeights.find(force_type)->second;
713 	}
714 
715 	if (this->ParentFaction != -1) {
716 		return PlayerRaces.Factions[this->ParentFaction]->GetForceTypeWeight(force_type);
717 	}
718 
719 	if (this->Civilization == nullptr) {
720 		fprintf(stderr, "Error in CFaction::GetForceTypeWeight: the faction has no civilization.\n");
721 	}
722 
723 	return this->Civilization->GetForceTypeWeight(force_type);
724 }
725 
726 /**
727 **	@brief	Get the faction's currency
728 **
729 **	@return	The faction's currency
730 */
GetCurrency() const731 CCurrency *CFaction::GetCurrency() const
732 {
733 	if (this->Currency) {
734 		return this->Currency;
735 	}
736 
737 	if (this->ParentFaction != -1) {
738 		return PlayerRaces.Factions[this->ParentFaction]->GetCurrency();
739 	}
740 
741 	if (this->Civilization != nullptr) {
742 		return this->Civilization->GetCurrency();
743 	}
744 
745 	return nullptr;
746 }
747 
GetForceTemplates(int force_type) const748 std::vector<CForceTemplate *> CFaction::GetForceTemplates(int force_type) const
749 {
750 	if (force_type == -1) {
751 		fprintf(stderr, "Error in CFaction::GetForceTemplates: the force_type is -1.\n");
752 	}
753 
754 	if (this->ForceTemplates.find(force_type) != this->ForceTemplates.end()) {
755 		return this->ForceTemplates.find(force_type)->second;
756 	}
757 
758 	if (this->ParentFaction != -1) {
759 		return PlayerRaces.Factions[this->ParentFaction]->GetForceTemplates(force_type);
760 	}
761 
762 	if (this->Civilization == nullptr) {
763 		fprintf(stderr, "Error in CFaction::GetForceTemplates: the faction has no civilization.\n");
764 	}
765 
766 	return this->Civilization->GetForceTemplates(force_type);
767 }
768 
GetAiBuildingTemplates() const769 std::vector<CAiBuildingTemplate *> CFaction::GetAiBuildingTemplates() const
770 {
771 	if (this->AiBuildingTemplates.size() > 0) {
772 		return this->AiBuildingTemplates;
773 	}
774 
775 	if (this->ParentFaction != -1) {
776 		return PlayerRaces.Factions[this->ParentFaction]->GetAiBuildingTemplates();
777 	}
778 
779 	if (this->Civilization == nullptr) {
780 		fprintf(stderr, "Error in CFaction::GetAiBuildingTemplates: the faction has no civilization.\n");
781 	}
782 
783 	return this->Civilization->GetAiBuildingTemplates();
784 }
785 
GetShipNames()786 std::vector<std::string> &CFaction::GetShipNames()
787 {
788 	if (this->ShipNames.size() > 0) {
789 		return this->ShipNames;
790 	}
791 
792 	if (this->ParentFaction != -1) {
793 		return PlayerRaces.Factions[this->ParentFaction]->GetShipNames();
794 	}
795 
796 	return this->Civilization->GetShipNames();
797 }
798 
~CDynasty()799 CDynasty::~CDynasty()
800 {
801 	if (this->Conditions) {
802 		delete Conditions;
803 	}
804 }
805 //Wyrmgus end
806 
807 /**
808 **  Init players.
809 */
InitPlayers()810 void InitPlayers()
811 {
812 	for (int p = 0; p < PlayerMax; ++p) {
813 		Players[p].Index = p;
814 		if (!Players[p].Type) {
815 			Players[p].Type = PlayerNobody;
816 		}
817 		//Wyrmgus start
818 //		for (int x = 0; x < PlayerColorIndexCount; ++x) {
819 //			PlayerColors[p][x] = Video.MapRGB(TheScreen->format, PlayerColorsRGB[p][x]);
820 //		}
821 		//Wyrmgus end
822 	}
823 	//Wyrmgus start
824 	for (int p = 0; p < PlayerColorMax; ++p) {
825 		for (int x = 0; x < PlayerColorIndexCount; ++x) {
826 			PlayerColors[p][x] = Video.MapRGB(TheScreen->format, PlayerColorsRGB[p][x]);
827 		}
828 	}
829 	//Wyrmgus end
830 }
831 
832 /**
833 **  Clean up players.
834 */
CleanPlayers()835 void CleanPlayers()
836 {
837 	ThisPlayer = nullptr;
838 	for (unsigned int i = 0; i < PlayerMax; ++i) {
839 		Players[i].Clear();
840 	}
841 	NumPlayers = 0;
842 	NoRescueCheck = false;
843 }
844 
FreePlayerColors()845 void FreePlayerColors()
846 {
847 	for (int i = 0; i < PlayerMax; ++i) {
848 		Players[i].UnitColors.Colors.clear();
849 		//Wyrmgus start
850 //		PlayerColorsRGB[i].clear();
851 //		PlayerColors[i].clear();
852 		//Wyrmgus end
853 	}
854 	//Wyrmgus start
855 	for (int i = 0; i < PlayerColorMax; ++i) {
856 		PlayerColorsRGB[i].clear();
857 		PlayerColors[i].clear();
858 	}
859 	//Wyrmgus end
860 }
861 
862 /**
863 **  Save state of players to file.
864 **
865 **  @param file  Output file.
866 **
867 **  @note FIXME: Not completely saved.
868 */
SavePlayers(CFile & file)869 void SavePlayers(CFile &file)
870 {
871 	file.printf("\n--------------------------------------------\n");
872 	file.printf("--- MODULE: players\n\n");
873 
874 	//  Dump all players
875 	for (int i = 0; i < NumPlayers; ++i) {
876 		Players[i].Save(file);
877 	}
878 
879 	file.printf("SetThisPlayer(%d)\n\n", ThisPlayer->Index);
880 }
881 
882 
Save(CFile & file) const883 void CPlayer::Save(CFile &file) const
884 {
885 	const CPlayer &p = *this;
886 	file.printf("Player(%d,\n", this->Index);
887 	//Wyrmgus start
888 	file.printf(" \"race\", \"%s\",", PlayerRaces.Name[p.Race].c_str());
889 	if (p.Faction != -1) {
890 		file.printf(" \"faction\", %d,", p.Faction);
891 	}
892 	if (p.Dynasty) {
893 		file.printf(" \"dynasty\", \"%s\",", p.Dynasty->Ident.c_str());
894 	}
895 	if (p.Age) {
896 		file.printf(" \"age\", \"%s\",", p.Age->Ident.c_str());
897 	}
898 	for (int i = 0; i < PlayerColorMax; ++i) {
899 		if (PlayerColors[i][0] == this->Color) {
900 			file.printf(" \"color\", %d,", i);
901 			break;
902 		}
903 	}
904 	//Wyrmgus end
905 	file.printf("  \"name\", \"%s\",\n", p.Name.c_str());
906 	file.printf("  \"type\", ");
907 	switch (p.Type) {
908 		case PlayerNeutral:       file.printf("\"neutral\",");         break;
909 		case PlayerNobody:        file.printf("\"nobody\",");          break;
910 		case PlayerComputer:      file.printf("\"computer\",");        break;
911 		case PlayerPerson:        file.printf("\"person\",");          break;
912 		case PlayerRescuePassive: file.printf("\"rescue-passive\","); break;
913 		case PlayerRescueActive:  file.printf("\"rescue-active\","); break;
914 		default:                  file.printf("%d,", p.Type); break;
915 	}
916 	//Wyrmgus start
917 //	file.printf(" \"race\", \"%s\",", PlayerRaces.Name[p.Race].c_str());
918 	//Wyrmgus end
919 	file.printf(" \"ai-name\", \"%s\",\n", p.AiName.c_str());
920 	file.printf("  \"team\", %d,", p.Team);
921 
922 	file.printf(" \"enemy\", \"");
923 	for (int j = 0; j < PlayerMax; ++j) {
924 		file.printf("%c", (p.Enemy & (1 << j)) ? 'X' : '_');
925 	}
926 	file.printf("\", \"allied\", \"");
927 	for (int j = 0; j < PlayerMax; ++j) {
928 		file.printf("%c", (p.Allied & (1 << j)) ? 'X' : '_');
929 	}
930 	file.printf("\", \"shared-vision\", \"");
931 	for (int j = 0; j < PlayerMax; ++j) {
932 		file.printf("%c", (p.SharedVision & (1 << j)) ? 'X' : '_');
933 	}
934 	file.printf("\",\n  \"start\", {%d, %d},\n", p.StartPos.x, p.StartPos.y);
935 	//Wyrmgus start
936 	file.printf("  \"start-map-layer\", %d,\n", p.StartMapLayer);
937 	if (p.Overlord) {
938 		file.printf("  \"overlord\", %d,\n", p.Overlord->Index);
939 	}
940 	//Wyrmgus end
941 
942 	// Resources
943 	file.printf("  \"resources\", {");
944 	for (int j = 0; j < MaxCosts; ++j) {
945 		//Wyrmgus start
946 		if (!p.Resources[j]) {
947 			continue;
948 		}
949 		//Wyrmgus end
950 		file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.Resources[j]);
951 	}
952 	// Stored Resources
953 	file.printf("},\n  \"stored-resources\", {");
954 	for (int j = 0; j < MaxCosts; ++j) {
955 		//Wyrmgus start
956 		if (!p.StoredResources[j]) {
957 			continue;
958 		}
959 		//Wyrmgus end
960 		file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.StoredResources[j]);
961 	}
962 	// Max Resources
963 	file.printf("},\n  \"max-resources\", {");
964 	for (int j = 0; j < MaxCosts; ++j) {
965 		file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.MaxResources[j]);
966 	}
967 	// Last Resources
968 	file.printf("},\n  \"last-resources\", {");
969 	for (int j = 0; j < MaxCosts; ++j) {
970 		//Wyrmgus start
971 		if (!p.LastResources[j]) {
972 			continue;
973 		}
974 		//Wyrmgus end
975 		file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.LastResources[j]);
976 	}
977 	// Incomes
978 	file.printf("},\n  \"incomes\", {");
979 	for (int j = 0; j < MaxCosts; ++j) {
980 		if (j) {
981 			if (j == MaxCosts / 2) {
982 				file.printf("\n ");
983 			} else {
984 				file.printf(" ");
985 			}
986 		}
987 		file.printf("\"%s\", %d,", DefaultResourceNames[j].c_str(), p.Incomes[j]);
988 	}
989 	// Revenue
990 	file.printf("},\n  \"revenue\", {");
991 	for (int j = 0; j < MaxCosts; ++j) {
992 		//Wyrmgus start
993 //		if (j) {
994 //			if (j == MaxCosts / 2) {
995 //				file.printf("\n ");
996 //			} else {
997 //				file.printf(" ");
998 //			}
999 //		}
1000 //		file.printf("\"%s\", %d,", DefaultResourceNames[j].c_str(), p.Revenue[j]);
1001 		if (p.Revenue[j]) {
1002 			file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.Revenue[j]);
1003 		}
1004 		//Wyrmgus end
1005 	}
1006 
1007 	//Wyrmgus start
1008 	file.printf("},\n  \"prices\", {");
1009 	for (int j = 0; j < MaxCosts; ++j) {
1010 		if (p.Prices[j]) {
1011 			file.printf("\"%s\", %d, ", DefaultResourceNames[j].c_str(), p.Prices[j]);
1012 		}
1013 	}
1014 	//Wyrmgus end
1015 
1016 	// UnitTypesCount done by load units.
1017 
1018 	file.printf("},\n  \"%s\",\n", p.AiEnabled ? "ai-enabled" : "ai-disabled");
1019 
1020 	// Ai done by load ais.
1021 	// Units done by load units.
1022 	// TotalNumUnits done by load units.
1023 	// NumBuildings done by load units.
1024 
1025 	//Wyrmgus start
1026 	if (p.Revealed) {
1027 		file.printf(" \"revealed\",");
1028 	}
1029 	//Wyrmgus end
1030 
1031 	file.printf(" \"supply\", %d,", p.Supply);
1032 	file.printf(" \"trade-cost\", %d,", p.TradeCost);
1033 	file.printf(" \"unit-limit\", %d,", p.UnitLimit);
1034 	file.printf(" \"building-limit\", %d,", p.BuildingLimit);
1035 	file.printf(" \"total-unit-limit\", %d,", p.TotalUnitLimit);
1036 
1037 	file.printf("\n  \"score\", %d,", p.Score);
1038 	file.printf("\n  \"total-units\", %d,", p.TotalUnits);
1039 	file.printf("\n  \"total-buildings\", %d,", p.TotalBuildings);
1040 	file.printf("\n  \"total-resources\", {");
1041 	for (int j = 0; j < MaxCosts; ++j) {
1042 		if (j) {
1043 			file.printf(" ");
1044 		}
1045 		file.printf("%d,", p.TotalResources[j]);
1046 	}
1047 	file.printf("},");
1048 	file.printf("\n  \"total-razings\", %d,", p.TotalRazings);
1049 	file.printf("\n  \"total-kills\", %d,", p.TotalKills);
1050 	//Wyrmgus start
1051 	file.printf("\n  \"unit-type-kills\", {");
1052 	for (size_t i = 0; i < UnitTypes.size(); ++i) {
1053 		if (p.UnitTypeKills[i] != 0) {
1054 			file.printf("\"%s\", %d, ", UnitTypes[i]->Ident.c_str(), p.UnitTypeKills[i]);
1055 		}
1056 	}
1057 	file.printf("},");
1058 	//Wyrmgus end
1059 	if (p.LostTownHallTimer != 0) {
1060 		file.printf("\n  \"lost-town-hall-timer\", %d,", p.LostTownHallTimer);
1061 	}
1062 	if (p.HeroCooldownTimer != 0) {
1063 		file.printf("\n  \"hero-cooldown-timer\", %d,", p.HeroCooldownTimer);
1064 	}
1065 	//Wyrmgus end
1066 
1067 	file.printf("\n  \"speed-resource-harvest\", {");
1068 	for (int j = 0; j < MaxCosts; ++j) {
1069 		if (j) {
1070 			file.printf(" ");
1071 		}
1072 		file.printf("%d,", p.SpeedResourcesHarvest[j]);
1073 	}
1074 	file.printf("},");
1075 	file.printf("\n  \"speed-resource-return\", {");
1076 	for (int j = 0; j < MaxCosts; ++j) {
1077 		if (j) {
1078 			file.printf(" ");
1079 		}
1080 		file.printf("%d,", p.SpeedResourcesReturn[j]);
1081 	}
1082 	file.printf("},");
1083 	file.printf("\n  \"speed-build\", %d,", p.SpeedBuild);
1084 	file.printf("\n  \"speed-train\", %d,", p.SpeedTrain);
1085 	file.printf("\n  \"speed-upgrade\", %d,", p.SpeedUpgrade);
1086 	file.printf("\n  \"speed-research\", %d,", p.SpeedResearch);
1087 
1088 	//Wyrmgus start
1089 	/*
1090 	Uint8 r, g, b;
1091 
1092 	SDL_GetRGB(p.Color, TheScreen->format, &r, &g, &b);
1093 	file.printf("\n  \"color\", { %d, %d, %d },", r, g, b);
1094 	*/
1095 	//Wyrmgus end
1096 
1097 	//Wyrmgus start
1098 	file.printf("\n  \"current-quests\", {");
1099 	for (size_t j = 0; j < p.CurrentQuests.size(); ++j) {
1100 		if (j) {
1101 			file.printf(" ");
1102 		}
1103 		file.printf("\"%s\",", p.CurrentQuests[j]->Ident.c_str());
1104 	}
1105 	file.printf("},");
1106 
1107 	file.printf("\n  \"completed-quests\", {");
1108 	for (size_t j = 0; j < p.CompletedQuests.size(); ++j) {
1109 		if (j) {
1110 			file.printf(" ");
1111 		}
1112 		file.printf("\"%s\",", p.CompletedQuests[j]->Ident.c_str());
1113 	}
1114 	file.printf("},");
1115 
1116 	file.printf("\n  \"quest-objectives\", {");
1117 	for (size_t j = 0; j < p.QuestObjectives.size(); ++j) {
1118 		if (j) {
1119 			file.printf(" ");
1120 		}
1121 		file.printf("{");
1122 		file.printf("\"quest\", \"%s\",", p.QuestObjectives[j]->Quest->Ident.c_str());
1123 		file.printf("\"objective-type\", \"%s\",", GetQuestObjectiveTypeNameById(p.QuestObjectives[j]->ObjectiveType).c_str());
1124 		file.printf("\"objective-string\", \"%s\",", p.QuestObjectives[j]->ObjectiveString.c_str());
1125 		file.printf("\"quantity\", %d,", p.QuestObjectives[j]->Quantity);
1126 		file.printf("\"counter\", %d,", p.QuestObjectives[j]->Counter);
1127 		if (p.QuestObjectives[j]->Resource != -1) {
1128 			file.printf("\"resource\", \"%s\",", DefaultResourceNames[p.QuestObjectives[j]->Resource].c_str());
1129 		}
1130 		if (p.QuestObjectives[j]->UnitClass != -1) {
1131 			file.printf("\"unit-class\", \"%s\",", UnitTypeClasses[p.QuestObjectives[j]->UnitClass].c_str());
1132 		}
1133 		for (const CUnitType *unit_type : p.QuestObjectives[j]->UnitTypes) {
1134 			file.printf("\"unit-type\", \"%s\",", unit_type->Ident.c_str());
1135 		}
1136 		if (p.QuestObjectives[j]->Upgrade) {
1137 			file.printf("\"upgrade\", \"%s\",", p.QuestObjectives[j]->Upgrade->Ident.c_str());
1138 		}
1139 		if (p.QuestObjectives[j]->Character) {
1140 			file.printf("\"character\", \"%s\",", p.QuestObjectives[j]->Character->Ident.c_str());
1141 		}
1142 		if (p.QuestObjectives[j]->Unique) {
1143 			file.printf("\"unique\", \"%s\",", p.QuestObjectives[j]->Unique->Ident.c_str());
1144 		}
1145 		if (p.QuestObjectives[j]->Settlement) {
1146 			file.printf("\"settlement\", \"%s\",", p.QuestObjectives[j]->Settlement->Ident.c_str());
1147 		}
1148 		if (p.QuestObjectives[j]->Faction) {
1149 			file.printf("\"faction\", \"%s\",", p.QuestObjectives[j]->Faction->Ident.c_str());
1150 		}
1151 		file.printf("},");
1152 	}
1153 	file.printf("},");
1154 
1155 	file.printf("\n  \"modifiers\", {");
1156 	for (size_t j = 0; j < p.Modifiers.size(); ++j) {
1157 		if (j) {
1158 			file.printf(" ");
1159 		}
1160 		file.printf("\"%s\", %d,", p.Modifiers[j].first->Ident.c_str(), p.Modifiers[j].second);
1161 	}
1162 	file.printf("},");
1163 	//Wyrmgus end
1164 
1165 	file.printf("\n  \"autosell-resources\", {");
1166 	for (size_t j = 0; j < p.AutosellResources.size(); ++j) {
1167 		if (j) {
1168 			file.printf(" ");
1169 		}
1170 		file.printf("\"%s\",", DefaultResourceNames[p.AutosellResources[j]].c_str());
1171 	}
1172 	file.printf("},");
1173 
1174 	// UnitColors done by init code.
1175 	// Allow saved by allow.
1176 
1177 	file.printf("\n  \"timers\", {");
1178 	//Wyrmgus start
1179 	bool first = true;
1180 	//Wyrmgus end
1181 	for (int j = 0; j < UpgradeMax; ++j) {
1182 		//Wyrmgus start
1183 //		if (j) {
1184 //			file.printf(" ,");
1185 //		}
1186 //		file.printf("%d", p.UpgradeTimers.Upgrades[j]);
1187 		if (p.UpgradeTimers.Upgrades[j]) {
1188 			if (first) {
1189 				first = false;
1190 			} else {
1191 				file.printf(", ");
1192 			}
1193 			file.printf("\"%s\", %d", AllUpgrades[j]->Ident.c_str(), p.UpgradeTimers.Upgrades[j]);
1194 		}
1195 		//Wyrmgus end
1196 	}
1197 	file.printf("}");
1198 
1199 	file.printf(")\n\n");
1200 
1201 	DebugPrint("FIXME: must save unit-stats?\n");
1202 }
1203 
1204 /**
1205 **  Create a new player.
1206 **
1207 **  @param type  Player type (Computer,Human,...).
1208 */
CreatePlayer(int type)1209 void CreatePlayer(int type)
1210 {
1211 	if (NumPlayers == PlayerMax) { // already done for bigmaps!
1212 		return;
1213 	}
1214 	CPlayer &player = Players[NumPlayers];
1215 	player.Index = NumPlayers;
1216 
1217 	player.Init(type);
1218 }
1219 
1220 //Wyrmgus start
GetFactionPlayer(const CFaction * faction)1221 CPlayer *GetFactionPlayer(const CFaction *faction)
1222 {
1223 	if (!faction) {
1224 		return nullptr;
1225 	}
1226 
1227 	for (int i = 0; i < NumPlayers; ++i) {
1228 		if (Players[i].Race == faction->Civilization->ID && Players[i].Faction == faction->ID) {
1229 			return &Players[i];
1230 		}
1231 	}
1232 
1233 	return nullptr;
1234 }
1235 
GetOrAddFactionPlayer(const CFaction * faction)1236 CPlayer *GetOrAddFactionPlayer(const CFaction *faction)
1237 {
1238 	CPlayer *faction_player = GetFactionPlayer(faction);
1239 	if (faction_player) {
1240 		return faction_player;
1241 	}
1242 
1243 	// no player belonging to this faction, so let's make an unused player slot be created for it
1244 
1245 	for (int i = 0; i < NumPlayers; ++i) {
1246 		if (Players[i].Type == PlayerNobody) {
1247 			Players[i].Type = PlayerComputer;
1248 			Players[i].SetCivilization(faction->Civilization->ID);
1249 			Players[i].SetFaction(faction);
1250 			Players[i].AiEnabled = true;
1251 			Players[i].AiName = faction->DefaultAI;
1252 			Players[i].Team = 1;
1253 			Players[i].Resources[CopperCost] = 2500; // give the new player enough resources to start up
1254 			Players[i].Resources[WoodCost] = 2500;
1255 			Players[i].Resources[StoneCost] = 2500;
1256 			return &Players[i];
1257 		}
1258 	}
1259 
1260 	fprintf(stderr, "Cannot add player for faction \"%s\": no player slots available.\n", faction->Ident.c_str());
1261 
1262 	return nullptr;
1263 }
1264 //Wyrmgus end
1265 
Init(int type)1266 void CPlayer::Init(/* PlayerTypes */ int type)
1267 {
1268 	std::vector<CUnit *>().swap(this->Units);
1269 	std::vector<CUnit *>().swap(this->FreeWorkers);
1270 	//Wyrmgus start
1271 	std::vector<CUnit *>().swap(this->LevelUpUnits);
1272 	//Wyrmgus end
1273 
1274 	//  Take first slot for person on this computer,
1275 	//  fill other with computer players.
1276 	if (type == PlayerPerson && !NetPlayers) {
1277 		if (!ThisPlayer) {
1278 			ThisPlayer = this;
1279 		} else {
1280 			type = PlayerComputer;
1281 		}
1282 	}
1283 	if (NetPlayers && NumPlayers == NetLocalPlayerNumber) {
1284 		ThisPlayer = &Players[NetLocalPlayerNumber];
1285 	}
1286 
1287 	if (NumPlayers == PlayerMax) {
1288 		static int already_warned;
1289 
1290 		if (!already_warned) {
1291 			DebugPrint("Too many players\n");
1292 			already_warned = 1;
1293 		}
1294 		return;
1295 	}
1296 
1297 	//  Make simple teams:
1298 	//  All person players are enemies.
1299 	int team;
1300 	switch (type) {
1301 		case PlayerNeutral:
1302 		case PlayerNobody:
1303 		default:
1304 			team = 0;
1305 			this->SetName("Neutral");
1306 			break;
1307 		case PlayerComputer:
1308 			team = 1;
1309 			this->SetName("Computer");
1310 			break;
1311 		case PlayerPerson:
1312 			team = 2 + NumPlayers;
1313 			this->SetName("Person");
1314 			break;
1315 		case PlayerRescuePassive:
1316 		case PlayerRescueActive:
1317 			// FIXME: correct for multiplayer games?
1318 			this->SetName("Computer");
1319 			team = 2 + NumPlayers;
1320 			break;
1321 	}
1322 	DebugPrint("CreatePlayer name %s\n" _C_ this->Name.c_str());
1323 
1324 	this->Type = type;
1325 	this->Race = 0;
1326 	this->Faction = -1;
1327 	this->Religion = nullptr;
1328 	this->Dynasty = nullptr;
1329 	this->Age = nullptr;
1330 	this->Overlord = nullptr;
1331 	this->Team = team;
1332 	this->Enemy = 0;
1333 	this->Allied = 0;
1334 	this->AiName = "ai-passive";
1335 
1336 	//  Calculate enemy/allied mask.
1337 	for (int i = 0; i < NumPlayers; ++i) {
1338 		switch (type) {
1339 			case PlayerNeutral:
1340 			case PlayerNobody:
1341 			default:
1342 				break;
1343 			case PlayerComputer:
1344 				// Computer allied with computer and enemy of all persons.
1345 				//Wyrmgus start
1346 				/*
1347 				if (Players[i].Type == PlayerComputer) {
1348 					this->Allied |= (1 << i);
1349 					Players[i].Allied |= (1 << NumPlayers);
1350 				} else if (Players[i].Type == PlayerPerson || Players[i].Type == PlayerRescueActive) {
1351 				*/
1352 				// make computer players be hostile to each other by default
1353 				if (Players[i].Type == PlayerComputer || Players[i].Type == PlayerPerson || Players[i].Type == PlayerRescueActive) {
1354 				//Wyrmgus end
1355 					this->Enemy |= (1 << i);
1356 					Players[i].Enemy |= (1 << NumPlayers);
1357 				}
1358 				break;
1359 			case PlayerPerson:
1360 				// Humans are enemy of all?
1361 				if (Players[i].Type == PlayerComputer || Players[i].Type == PlayerPerson) {
1362 					this->Enemy |= (1 << i);
1363 					Players[i].Enemy |= (1 << NumPlayers);
1364 				} else if (Players[i].Type == PlayerRescueActive || Players[i].Type == PlayerRescuePassive) {
1365 					this->Allied |= (1 << i);
1366 					Players[i].Allied |= (1 << NumPlayers);
1367 				}
1368 				break;
1369 			case PlayerRescuePassive:
1370 				// Rescue passive are allied with persons
1371 				if (Players[i].Type == PlayerPerson) {
1372 					this->Allied |= (1 << i);
1373 					Players[i].Allied |= (1 << NumPlayers);
1374 				}
1375 				break;
1376 			case PlayerRescueActive:
1377 				// Rescue active are allied with persons and enemies of computer
1378 				if (Players[i].Type == PlayerComputer) {
1379 					this->Enemy |= (1 << i);
1380 					Players[i].Enemy |= (1 << NumPlayers);
1381 				} else if (Players[i].Type == PlayerPerson) {
1382 					this->Allied |= (1 << i);
1383 					Players[i].Allied |= (1 << NumPlayers);
1384 				}
1385 				break;
1386 		}
1387 	}
1388 
1389 	//  Initial default incomes.
1390 	for (int i = 0; i < MaxCosts; ++i) {
1391 		this->Incomes[i] = CResource::Resources[i]->DefaultIncome;
1392 	}
1393 
1394 	this->TradeCost = DefaultTradeCost;
1395 
1396 	//  Initial max resource amounts.
1397 	for (int i = 0; i < MaxCosts; ++i) {
1398 		this->MaxResources[i] = CResource::Resources[i]->DefaultMaxAmount;
1399 	}
1400 
1401 	//Wyrmgus start
1402 	this->UnitTypesCount.clear();
1403 	this->UnitTypesUnderConstructionCount.clear();
1404 	this->UnitTypesAiActiveCount.clear();
1405 	this->Heroes.clear();
1406 	this->Deities.clear();
1407 	this->UnitsByType.clear();
1408 	this->AiActiveUnitsByType.clear();
1409 	//Wyrmgus end
1410 
1411 	this->Supply = 0;
1412 	this->Demand = 0;
1413 	this->NumBuildings = 0;
1414 	//Wyrmgus start
1415 	this->NumBuildingsUnderConstruction = 0;
1416 	this->NumTownHalls = 0;
1417 	//Wyrmgus end
1418 	this->Score = 0;
1419 	//Wyrmgus start
1420 	this->LostTownHallTimer = 0;
1421 	this->HeroCooldownTimer = 0;
1422 	//Wyrmgus end
1423 
1424 	this->Color = PlayerColors[NumPlayers][0];
1425 
1426 	if (Players[NumPlayers].Type == PlayerComputer || Players[NumPlayers].Type == PlayerRescueActive) {
1427 		this->AiEnabled = true;
1428 	} else {
1429 		this->AiEnabled = false;
1430 	}
1431 	//Wyrmgus start
1432 	this->Revealed = false;
1433 	//Wyrmgus end
1434 	++NumPlayers;
1435 }
1436 
1437 /**
1438 **  Change player name.
1439 **
1440 **  @param name    New name.
1441 */
SetName(const std::string & name)1442 void CPlayer::SetName(const std::string &name)
1443 {
1444 	Name = name;
1445 }
1446 
1447 //Wyrmgus start
SetCivilization(int civilization)1448 void CPlayer::SetCivilization(int civilization)
1449 {
1450 	if (this->Race != -1 && (GameRunning || GameEstablishing)) {
1451 		if (!PlayerRaces.CivilizationUpgrades[this->Race].empty() && this->Allow.Upgrades[CUpgrade::Get(PlayerRaces.CivilizationUpgrades[this->Race])->ID] == 'R') {
1452 			UpgradeLost(*this, CUpgrade::Get(PlayerRaces.CivilizationUpgrades[this->Race])->ID);
1453 		}
1454 	}
1455 
1456 	int old_civilization = this->Race;
1457 	int old_faction = this->Faction;
1458 
1459 	if (GameRunning) {
1460 		this->SetFaction(nullptr);
1461 	} else {
1462 		this->Faction = -1;
1463 	}
1464 
1465 	this->Race = civilization;
1466 
1467 	//if the civilization of the person player changed, update the UI
1468 	if ((ThisPlayer && ThisPlayer->Index == this->Index) || (!ThisPlayer && this->Index == 0)) {
1469 		//load proper UI
1470 		char buf[256];
1471 		snprintf(buf, sizeof(buf), "if (LoadCivilizationUI ~= nil) then LoadCivilizationUI(\"%s\") end;", PlayerRaces.Name[this->Race].c_str());
1472 		CclCommand(buf);
1473 
1474 		UI.Load();
1475 		SetDefaultTextColors(UI.NormalFontColor, UI.ReverseFontColor);
1476 	}
1477 
1478 	if (this->Race != -1) {
1479 		CUpgrade *civilization_upgrade = CUpgrade::Get(PlayerRaces.CivilizationUpgrades[this->Race]);
1480 		if (civilization_upgrade && this->Allow.Upgrades[civilization_upgrade->ID] != 'R') {
1481 			UpgradeAcquire(*this, civilization_upgrade);
1482 		}
1483 	}
1484 }
1485 
1486 /**
1487 **  Change player faction.
1488 **
1489 **  @param faction    New faction.
1490 */
SetFaction(const CFaction * faction)1491 void CPlayer::SetFaction(const CFaction *faction)
1492 {
1493 	int old_faction_id = this->Faction;
1494 
1495 	if (faction && faction->Civilization->ID != this->Race) {
1496 		this->SetCivilization(faction->Civilization->ID);
1497 	}
1498 
1499 	if (this->Faction != -1) {
1500 		if (!PlayerRaces.Factions[this->Faction]->FactionUpgrade.empty() && this->Allow.Upgrades[CUpgrade::Get(PlayerRaces.Factions[this->Faction]->FactionUpgrade)->ID] == 'R') {
1501 			UpgradeLost(*this, CUpgrade::Get(PlayerRaces.Factions[this->Faction]->FactionUpgrade)->ID);
1502 		}
1503 
1504 		int faction_type_upgrade_id = UpgradeIdByIdent("upgrade-" + GetFactionTypeNameById(PlayerRaces.Factions[this->Faction]->Type));
1505 		if (faction_type_upgrade_id != -1 && this->Allow.Upgrades[faction_type_upgrade_id] == 'R') {
1506 			UpgradeLost(*this, faction_type_upgrade_id);
1507 		}
1508 	}
1509 
1510 	int faction_id = faction ? faction->ID : -1;
1511 
1512 	if (old_faction_id != -1 && faction_id != -1) {
1513 		for (size_t i = 0; i < UpgradeClasses.size(); ++i) {
1514 			if (PlayerRaces.GetFactionClassUpgrade(old_faction_id, i) != PlayerRaces.GetFactionClassUpgrade(faction_id, i)) { //if the upgrade for a certain class is different for the new faction than the old faction (and it has been acquired), remove the modifiers of the old upgrade and apply the modifiers of the new
1515 				if (PlayerRaces.GetFactionClassUpgrade(old_faction_id, i) != -1 && this->Allow.Upgrades[PlayerRaces.GetFactionClassUpgrade(old_faction_id, i)] == 'R') {
1516 					UpgradeLost(*this, PlayerRaces.GetFactionClassUpgrade(old_faction_id, i));
1517 
1518 					if (PlayerRaces.GetFactionClassUpgrade(faction_id, i) != -1) {
1519 						UpgradeAcquire(*this, AllUpgrades[PlayerRaces.GetFactionClassUpgrade(faction_id, i)]);
1520 					}
1521 				}
1522 			}
1523 		}
1524 	}
1525 
1526 	bool personal_names_changed = true;
1527 	bool ship_names_changed = true;
1528 	if (this->Faction != -1 && faction_id != -1) {
1529 		ship_names_changed = PlayerRaces.Factions[this->Faction]->GetShipNames() != PlayerRaces.Factions[faction_id]->GetShipNames();
1530 		personal_names_changed = false; // setting to a faction of the same civilization
1531 	}
1532 
1533 	this->Faction = faction_id;
1534 
1535 	if (this->Index == ThisPlayer->Index) {
1536 		UI.Load();
1537 	}
1538 
1539 	if (this->Faction == -1) {
1540 		return;
1541 	}
1542 
1543 	if (!IsNetworkGame()) { //only set the faction's name as the player's name if this is a single player game
1544 		this->SetName(PlayerRaces.Factions[this->Faction]->Name);
1545 	}
1546 	if (this->Faction != -1) {
1547 		int color = -1;
1548 		for (size_t i = 0; i < PlayerRaces.Factions[faction_id]->Colors.size(); ++i) {
1549 			if (!IsPlayerColorUsed(PlayerRaces.Factions[faction_id]->Colors[i])) {
1550 				color = PlayerRaces.Factions[faction_id]->Colors[i];
1551 				break;
1552 			}
1553 		}
1554 		if (color == -1) { //if all of the faction's colors are used, get a unused player color
1555 			for (int i = 0; i < PlayerColorMax; ++i) {
1556 				if (!IsPlayerColorUsed(i)) {
1557 					color = i;
1558 					break;
1559 				}
1560 			}
1561 		}
1562 
1563 		if (color != -1) {
1564 			if (this->Color != PlayerColors[color][0]) {
1565 				this->Color = PlayerColors[color][0];
1566 				this->UnitColors.Colors = PlayerColorsRGB[color];
1567 			}
1568 		}
1569 
1570 		if (!PlayerRaces.Factions[this->Faction]->FactionUpgrade.empty()) {
1571 			CUpgrade *faction_upgrade = CUpgrade::Get(PlayerRaces.Factions[this->Faction]->FactionUpgrade);
1572 			if (faction_upgrade && this->Allow.Upgrades[faction_upgrade->ID] != 'R') {
1573 				if (GameEstablishing) {
1574 					AllowUpgradeId(*this, faction_upgrade->ID, 'R');
1575 				} else {
1576 					UpgradeAcquire(*this, faction_upgrade);
1577 				}
1578 			}
1579 		}
1580 
1581 		int faction_type_upgrade_id = UpgradeIdByIdent("upgrade-" + GetFactionTypeNameById(PlayerRaces.Factions[this->Faction]->Type));
1582 		if (faction_type_upgrade_id != -1 && this->Allow.Upgrades[faction_type_upgrade_id] != 'R') {
1583 			if (GameEstablishing) {
1584 				AllowUpgradeId(*this, faction_type_upgrade_id, 'R');
1585 			} else {
1586 				UpgradeAcquire(*this, AllUpgrades[faction_type_upgrade_id]);
1587 			}
1588 		}
1589 	} else {
1590 		fprintf(stderr, "Invalid faction \"%s\" tried to be set for player %d of civilization \"%s\".\n", faction->Name.c_str(), this->Index, PlayerRaces.Name[this->Race].c_str());
1591 	}
1592 
1593 	for (int i = 0; i < this->GetUnitCount(); ++i) {
1594 		CUnit &unit = this->GetUnit(i);
1595 		if (!unit.Unique && unit.Type->PersonalNames.size() == 0) {
1596 			if (!unit.Type->BoolFlag[ORGANIC_INDEX].value && unit.Type->UnitType == UnitTypeNaval && ship_names_changed) {
1597 				unit.UpdatePersonalName();
1598 			}
1599 		}
1600 		if (personal_names_changed && unit.Type->BoolFlag[ORGANIC_INDEX].value && !unit.Character && unit.Type->Civilization != -1 && PlayerRaces.Species[unit.Type->Civilization] == PlayerRaces.Species[faction->Civilization->ID] && unit.Type->Slot == PlayerRaces.GetFactionClassUnitType(faction->ID, unit.Type->Class)) {
1601 			unit.UpdatePersonalName();
1602 		}
1603 		unit.UpdateSoldUnits();
1604 		unit.UpdateButtonIcons();
1605 	}
1606 }
1607 
1608 /**
1609 **  Change player faction to a randomly chosen one.
1610 **
1611 **  @param faction    New faction.
1612 */
SetRandomFaction()1613 void CPlayer::SetRandomFaction()
1614 {
1615 	// set random one from the civilization's factions
1616 	std::vector<CFaction *> local_factions;
1617 
1618 	for (size_t i = 0; i < PlayerRaces.Factions.size(); ++i) {
1619 		CFaction *faction = PlayerRaces.Factions[i];
1620 		if (faction->Civilization->ID != this->Race) {
1621 			continue;
1622 		}
1623 		if (!faction->Playable) {
1624 			continue;
1625 		}
1626 		if (!this->CanFoundFaction(faction)) {
1627 			continue;
1628 		}
1629 
1630 		int faction_type = faction->Type;
1631 		bool has_writing = this->HasUpgradeClass(GetUpgradeClassIndexByName("writing"));
1632 		if (
1633 			!(faction_type == FactionTypeTribe && !has_writing)
1634 			&& !(faction_type == FactionTypePolity && has_writing)
1635 		) {
1636 			continue;
1637 		}
1638 
1639 		local_factions.push_back(faction);
1640 	}
1641 
1642 	if (local_factions.size() > 0) {
1643 		CFaction *chosen_faction = local_factions[SyncRand(local_factions.size())];
1644 		this->SetFaction(chosen_faction);
1645 	} else {
1646 		this->SetFaction(nullptr);
1647 	}
1648 }
1649 
1650 /**
1651 **	@brief	Change player dynasty.
1652 **
1653 **	@param	dynasty	New dynasty.
1654 */
SetDynasty(CDynasty * dynasty)1655 void CPlayer::SetDynasty(CDynasty *dynasty)
1656 {
1657 	CDynasty *old_dynasty = this->Dynasty;
1658 
1659 	if (this->Dynasty) {
1660 		if (this->Dynasty->DynastyUpgrade && this->Allow.Upgrades[this->Dynasty->DynastyUpgrade->ID] == 'R') {
1661 			UpgradeLost(*this, this->Dynasty->DynastyUpgrade->ID);
1662 		}
1663 	}
1664 
1665 	this->Dynasty = dynasty;
1666 
1667 	if (!this->Dynasty) {
1668 		return;
1669 	}
1670 
1671 	if (this->Dynasty->DynastyUpgrade) {
1672 		if (this->Allow.Upgrades[this->Dynasty->DynastyUpgrade->ID] != 'R') {
1673 			if (GameEstablishing) {
1674 				AllowUpgradeId(*this, this->Dynasty->DynastyUpgrade->ID, 'R');
1675 			} else {
1676 				UpgradeAcquire(*this, this->Dynasty->DynastyUpgrade);
1677 			}
1678 		}
1679 	}
1680 
1681 	for (int i = 0; i < this->GetUnitCount(); ++i) {
1682 		CUnit &unit = this->GetUnit(i);
1683 		unit.UpdateSoldUnits(); //in case conditions changed (i.e. some heroes may require a certain dynasty)
1684 	}
1685 }
1686 
1687 /**
1688 **	@brief	Check which age fits the player's current situation best, and set it as the player's age
1689 */
CheckAge()1690 void CPlayer::CheckAge()
1691 {
1692 	//pick an age which fits the player, giving priority to the first ones (ages are already sorted by priority)
1693 
1694 	for (CAge *potential_age : CAge::Ages) {
1695 		if (!CheckDependencies(potential_age, this)) {
1696 			continue;
1697 		}
1698 
1699 		this->SetAge(potential_age);
1700 		return;
1701 	}
1702 
1703 	this->SetAge(nullptr);
1704 }
1705 
1706 /**
1707 **	@brief	Set the player's age
1708 **
1709 **	@param	age	The age to be set for the player
1710 */
SetAge(CAge * age)1711 void CPlayer::SetAge(CAge *age)
1712 {
1713 	if (this->Age == age) {
1714 		return;
1715 	}
1716 
1717 	this->Age = age;
1718 
1719 	if (this == ThisPlayer) {
1720 		if (this->Age) {
1721 			UI.AgePanel.Text = this->Age->Name;
1722 			UI.AgePanel.G = this->Age->G;
1723 
1724 			if (GameCycle > 0 && !SaveGameLoading) {
1725 				this->Notify(_("The %s has dawned upon us."), this->Age->Name.c_str());
1726 			}
1727 		} else {
1728 			UI.AgePanel.Text.clear();
1729 			UI.AgePanel.G = nullptr;
1730 		}
1731 	}
1732 
1733 	CAge::CheckCurrentAge();
1734 }
1735 
1736 /**
1737 **	@brief	Get the player's currency
1738 **
1739 **	@return	The player's currency
1740 */
GetCurrency() const1741 CCurrency *CPlayer::GetCurrency() const
1742 {
1743 	if (this->Faction != -1) {
1744 		return PlayerRaces.Factions[this->Faction]->GetCurrency();
1745 	}
1746 
1747 	if (this->Race != -1) {
1748 		return CCivilization::Civilizations[this->Race]->GetCurrency();
1749 	}
1750 
1751 	return nullptr;
1752 }
1753 
ShareUpgradeProgress(CPlayer & player,CUnit & unit)1754 void CPlayer::ShareUpgradeProgress(CPlayer &player, CUnit &unit)
1755 {
1756 	std::vector<CUpgrade *> upgrade_list = this->GetResearchableUpgrades();
1757 	std::vector<CUpgrade *> potential_upgrades;
1758 
1759 	for (size_t i = 0; i < upgrade_list.size(); ++i) {
1760 		if (this->Allow.Upgrades[upgrade_list[i]->ID] != 'R') {
1761 			continue;
1762 		}
1763 
1764 		if (upgrade_list[i]->Class == -1) {
1765 			continue;
1766 		}
1767 
1768 		int upgrade_id = PlayerRaces.GetFactionClassUpgrade(player.Faction, upgrade_list[i]->Class);
1769 		if (upgrade_id == -1) {
1770 			continue;
1771 		}
1772 
1773 		CUpgrade *upgrade = AllUpgrades[upgrade_id];
1774 
1775 		if (player.Allow.Upgrades[upgrade->ID] != 'A' || !CheckDependencies(upgrade, &player)) {
1776 			continue;
1777 		}
1778 
1779 		if (player.UpgradeRemovesExistingUpgrade(upgrade, player.AiEnabled)) {
1780 			continue;
1781 		}
1782 
1783 		potential_upgrades.push_back(upgrade);
1784 	}
1785 
1786 	if (potential_upgrades.size() > 0) {
1787 		CUpgrade *chosen_upgrade = potential_upgrades[SyncRand(potential_upgrades.size())];
1788 
1789 		if (!chosen_upgrade->Name.empty()) {
1790 			player.Notify(NotifyGreen, unit.tilePos, unit.MapLayer->ID, _("%s acquired through contact with %s"), chosen_upgrade->Name.c_str(), this->Name.c_str());
1791 		}
1792 		if (&player == ThisPlayer) {
1793 			CSound *sound = GameSounds.ResearchComplete[player.Race].Sound;
1794 
1795 			if (sound) {
1796 				PlayGameSound(sound, MaxSampleVolume);
1797 			}
1798 		}
1799 		if (player.AiEnabled) {
1800 			AiResearchComplete(unit, chosen_upgrade);
1801 		}
1802 		UpgradeAcquire(player, chosen_upgrade);
1803 	}
1804 }
1805 
IsPlayerColorUsed(int color)1806 bool CPlayer::IsPlayerColorUsed(int color)
1807 {
1808 	bool color_used = false;
1809 	for (int i = 0; i < PlayerMax; ++i) {
1810 		if (this->Index != i && Players[i].Faction != -1 && Players[i].Type != PlayerNobody && Players[i].Color == PlayerColors[color][0]) {
1811 			color_used = true;
1812 		}
1813 	}
1814 	return color_used;
1815 }
1816 
HasUpgradeClass(const int upgrade_class) const1817 bool CPlayer::HasUpgradeClass(const int upgrade_class) const
1818 {
1819 	if (this->Race == -1 || upgrade_class == -1) {
1820 		return false;
1821 	}
1822 
1823 	int upgrade_id = -1;
1824 
1825 	if (this->Faction != -1) {
1826 		upgrade_id = PlayerRaces.GetFactionClassUpgrade(this->Faction, upgrade_class);
1827 	} else {
1828 		upgrade_id = PlayerRaces.GetCivilizationClassUpgrade(this->Race, upgrade_class);
1829 	}
1830 
1831 	if (upgrade_id != -1 && this->Allow.Upgrades[upgrade_id] == 'R') {
1832 		return true;
1833 	}
1834 
1835 	return false;
1836 }
1837 
HasSettlement(const CSite * settlement) const1838 bool CPlayer::HasSettlement(const CSite *settlement) const
1839 {
1840 	if (!settlement) {
1841 		return false;
1842 	}
1843 
1844 	if (settlement->SiteUnit && settlement->SiteUnit->Player == this) {
1845 		return true;
1846 	}
1847 
1848 	return false;
1849 }
1850 
HasSettlementNearWaterZone(int water_zone) const1851 bool CPlayer::HasSettlementNearWaterZone(int water_zone) const
1852 {
1853 	std::vector<CUnit *> settlement_unit_table;
1854 
1855 	int town_hall_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, GetUnitTypeClassIndexByName("town-hall"));
1856 	if (town_hall_type_id == -1) {
1857 		return false;
1858 	}
1859 	CUnitType *town_hall_type = UnitTypes[town_hall_type_id];
1860 
1861 	int stronghold_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, GetUnitTypeClassIndexByName("stronghold"));
1862 	CUnitType *stronghold_type = nullptr;
1863 	if (stronghold_type_id != -1) {
1864 		stronghold_type = UnitTypes[stronghold_type_id];
1865 	}
1866 
1867 	FindPlayerUnitsByType(*this, *town_hall_type, settlement_unit_table, true);
1868 
1869 	if (stronghold_type) {
1870 		FindPlayerUnitsByType(*this, *stronghold_type, settlement_unit_table, true); //adds strongholds to the table
1871 	}
1872 	for (size_t i = 0; i < settlement_unit_table.size(); ++i) {
1873 		CUnit *settlement_unit = settlement_unit_table[i];
1874 		if (!settlement_unit->IsAliveOnMap()) {
1875 			continue;
1876 		}
1877 
1878 		int settlement_landmass = Map.GetTileLandmass(settlement_unit->tilePos, settlement_unit->MapLayer->ID);
1879 		if (std::find(Map.BorderLandmasses[settlement_landmass].begin(), Map.BorderLandmasses[settlement_landmass].end(), water_zone) == Map.BorderLandmasses[settlement_landmass].end()) { //settlement's landmass doesn't even border the water zone, continue
1880 			continue;
1881 		}
1882 
1883 		Vec2i pos(0, 0);
1884 		if (FindTerrainType(0, 0, 8, *this, settlement_unit->tilePos, &pos, settlement_unit->MapLayer->ID, water_zone)) {
1885 			return true;
1886 		}
1887 	}
1888 
1889 	return false;
1890 }
1891 
GetNearestSettlement(const Vec2i & pos,int z,const Vec2i & size) const1892 CSite *CPlayer::GetNearestSettlement(const Vec2i &pos, int z, const Vec2i &size) const
1893 {
1894 	CUnit *best_hall = nullptr;
1895 	int best_distance = -1;
1896 
1897 	for (size_t i = 0; i < Map.SiteUnits.size(); ++i) {
1898 		CUnit *settlement_unit = Map.SiteUnits[i];
1899 		if (!settlement_unit || !settlement_unit->IsAliveOnMap() || !settlement_unit->Type->BoolFlag[TOWNHALL_INDEX].value || z != settlement_unit->MapLayer->ID) {
1900 			continue;
1901 		}
1902 		if (!this->HasNeutralFactionType() && this != settlement_unit->Player) {
1903 			continue;
1904 		}
1905 		int distance = MapDistance(size, pos, z, settlement_unit->Type->TileSize, settlement_unit->tilePos, settlement_unit->MapLayer->ID);
1906 		if (!best_hall || distance < best_distance) {
1907 			best_hall = settlement_unit;
1908 			best_distance = distance;
1909 		}
1910 	}
1911 
1912 	if (best_hall) {
1913 		return best_hall->Settlement;
1914 	} else {
1915 		return nullptr;
1916 	}
1917 }
1918 
HasUnitBuilder(const CUnitType * type,const CSite * settlement) const1919 bool CPlayer::HasUnitBuilder(const CUnitType *type, const CSite *settlement) const
1920 {
1921 	if (type->BoolFlag[BUILDING_INDEX].value && type->Slot < (int) AiHelpers.Build.size()) {
1922 		for (size_t j = 0; j < AiHelpers.Build[type->Slot].size(); ++j) {
1923 			if (this->GetUnitTypeCount(AiHelpers.Build[type->Slot][j]) > 0) {
1924 				return true;
1925 			}
1926 		}
1927 	} else if (!type->BoolFlag[BUILDING_INDEX].value && type->Slot < (int) AiHelpers.Train.size()) {
1928 		for (size_t j = 0; j < AiHelpers.Train[type->Slot].size(); ++j) {
1929 			if (this->GetUnitTypeCount(AiHelpers.Train[type->Slot][j]) > 0) {
1930 				return true;
1931 			}
1932 		}
1933 	}
1934 	if (type->Slot < (int) AiHelpers.Upgrade.size()) {
1935 		for (size_t j = 0; j < AiHelpers.Upgrade[type->Slot].size(); ++j) {
1936 			if (this->GetUnitTypeCount(AiHelpers.Upgrade[type->Slot][j]) > 0) {
1937 				if (!settlement) {
1938 					return true;
1939 				} else {
1940 					for (int i = 0; i < this->GetUnitCount(); ++i) {
1941 						CUnit &unit = this->GetUnit(i);
1942 						if (unit.Type == AiHelpers.Upgrade[type->Slot][j] && unit.Settlement == settlement) {
1943 							return true;
1944 						}
1945 					}
1946 				}
1947 			}
1948 		}
1949 	}
1950 	return false;
1951 }
1952 
HasUpgradeResearcher(const CUpgrade * upgrade) const1953 bool CPlayer::HasUpgradeResearcher(const CUpgrade *upgrade) const
1954 {
1955 	if (upgrade->ID < (int) AiHelpers.Research.size()) {
1956 		for (size_t j = 0; j < AiHelpers.Research[upgrade->ID].size(); ++j) {
1957 			CUnitType *researcher_type = AiHelpers.Research[upgrade->ID][j];
1958 			if (this->GetUnitTypeCount(researcher_type) > 0 || HasUnitBuilder(researcher_type)) {
1959 				return true;
1960 			}
1961 		}
1962 	}
1963 	return false;
1964 }
1965 
1966 /**
1967 **  Check if the player can found a particular faction.
1968 **
1969 **  @param faction    New faction.
1970 */
CanFoundFaction(CFaction * faction,bool pre)1971 bool CPlayer::CanFoundFaction(CFaction *faction, bool pre)
1972 {
1973 	if (CurrentQuest != nullptr) {
1974 		return false;
1975 	}
1976 
1977 	if (!faction->FactionUpgrade.empty()) {
1978 		CUpgrade *faction_upgrade = CUpgrade::Get(faction->FactionUpgrade);
1979 
1980 		if (faction_upgrade) {
1981 			if (!CheckDependencies(faction_upgrade, this, false, pre)) {
1982 				return false;
1983 			}
1984 		} else {
1985 			fprintf(stderr, "Faction upgrade \"%s\" doesn't exist.\n", faction->FactionUpgrade.c_str());
1986 		}
1987 	}
1988 
1989 	for (int i = 0; i < PlayerMax; ++i) {
1990 		if (this->Index != i && Players[i].Type != PlayerNobody && Players[i].Race == faction->Civilization->ID && Players[i].Faction == faction->ID) {
1991 			// faction is already in use
1992 			return false;
1993 		}
1994 	}
1995 
1996 	if (!pre) {
1997 		//check if the required core settlements are owned by the player
1998 		if (CurrentCampaign != nullptr) { //only check for settlements in the Scenario mode
1999 			for (size_t i = 0; i < faction->Cores.size(); ++i) {
2000 				if (!faction->Cores[i]->SiteUnit || faction->Cores[i]->SiteUnit->Player != this || faction->Cores[i]->SiteUnit->CurrentAction() == UnitActionBuilt) {
2001 					return false;
2002 				}
2003 			}
2004 		}
2005 
2006 		if (faction->Conditions) {
2007 			CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2008 			faction->Conditions->pushPreamble();
2009 			faction->Conditions->run(1);
2010 			if (faction->Conditions->popBoolean() == false) {
2011 				return false;
2012 			}
2013 		}
2014 	}
2015 
2016 	return true;
2017 }
2018 
2019 /**
2020 **  Check if the player can choose a particular dynasty.
2021 **
2022 **  @param dynasty    New dynasty.
2023 */
CanChooseDynasty(CDynasty * dynasty,bool pre)2024 bool CPlayer::CanChooseDynasty(CDynasty *dynasty, bool pre)
2025 {
2026 	if (CurrentQuest != nullptr) {
2027 		return false;
2028 	}
2029 
2030 	if (dynasty->DynastyUpgrade) {
2031 		if (!CheckDependencies(dynasty->DynastyUpgrade, this, false, pre)) {
2032 			return false;
2033 		}
2034 	} else {
2035 		return false;
2036 	}
2037 
2038 	if (!pre) {
2039 		if (dynasty->Conditions) {
2040 			CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2041 			dynasty->Conditions->pushPreamble();
2042 			dynasty->Conditions->run(1);
2043 			if (dynasty->Conditions->popBoolean() == false) {
2044 				return false;
2045 			}
2046 		}
2047 	}
2048 
2049 	return true;
2050 }
2051 
2052 /**
2053 **  Check if the player can recruit a particular hero.
2054 **
2055 **  @param character    Hero.
2056 */
CanRecruitHero(const CCharacter * character,bool ignore_neutral) const2057 bool CPlayer::CanRecruitHero(const CCharacter *character, bool ignore_neutral) const
2058 {
2059 	if (character->Deity != nullptr) { //character is a deity
2060 		return false;
2061 	}
2062 
2063 	if (!character->Civilization || character->Civilization->ID != this->Race) {
2064 		return false;
2065 	}
2066 
2067 	if (!CheckDependencies(character->Type, this, true)) {
2068 		return false;
2069 	}
2070 
2071 	if (!character->Factions.empty() && (this->Faction == -1 || std::find(character->Factions.begin(), character->Factions.end(), PlayerRaces.Factions[this->Faction]) == character->Factions.end())) {
2072 		return false;
2073 	}
2074 
2075 	if (character->Conditions) {
2076 		CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2077 		character->Conditions->pushPreamble();
2078 		character->Conditions->run(1);
2079 		if (character->Conditions->popBoolean() == false) {
2080 			return false;
2081 		}
2082 	}
2083 
2084 	if (!character->CanAppear(ignore_neutral)) {
2085 		return false;
2086 	}
2087 
2088 	return true;
2089 }
2090 
2091 /**
2092 **  Check if the upgrade removes an existing upgrade of the player.
2093 **
2094 **  @param upgrade    Upgrade.
2095 */
UpgradeRemovesExistingUpgrade(const CUpgrade * upgrade,bool ignore_lower_priority) const2096 bool CPlayer::UpgradeRemovesExistingUpgrade(const CUpgrade *upgrade, bool ignore_lower_priority) const
2097 {
2098 	for (size_t z = 0; z < upgrade->UpgradeModifiers.size(); ++z) {
2099 		for (size_t j = 0; j < upgrade->UpgradeModifiers[z]->RemoveUpgrades.size(); ++j) {
2100 			const CUpgrade *removed_upgrade = upgrade->UpgradeModifiers[z]->RemoveUpgrades[j];
2101 			bool has_upgrade = this->AiEnabled ? AiHasUpgrade(*this->Ai, removed_upgrade, true) : (UpgradeIdAllowed(*this, removed_upgrade->ID) == 'R');
2102 			if (has_upgrade) {
2103 				if (ignore_lower_priority && this->Faction != -1 && PlayerRaces.Factions[this->Faction]->GetUpgradePriority(removed_upgrade) < PlayerRaces.Factions[this->Faction]->GetUpgradePriority(upgrade)) {
2104 					continue;
2105 				}
2106 				return true;
2107 			}
2108 		}
2109 	}
2110 
2111 	return false;
2112 }
2113 
GetFactionTitleName() const2114 std::string CPlayer::GetFactionTitleName() const
2115 {
2116 	if (this->Race == -1 || this->Faction == -1) {
2117 		return "";
2118 	}
2119 
2120 	CFaction *faction = PlayerRaces.Factions[this->Faction];
2121 	int faction_tier = faction->DefaultTier;
2122 	int government_type = faction->DefaultGovernmentType;
2123 
2124 	if (faction->Type == FactionTypePolity) {
2125 		if (!faction->Titles[government_type][faction_tier].empty()) {
2126 			return faction->Titles[government_type][faction_tier];
2127 		} else {
2128 			if (government_type == GovernmentTypeMonarchy) {
2129 				if (faction_tier == FactionTierBarony) {
2130 					return "Barony";
2131 				} else if (faction_tier == FactionTierCounty) {
2132 					return "County";
2133 				} else if (faction_tier == FactionTierDuchy) {
2134 					return "Duchy";
2135 				} else if (faction_tier == FactionTierGrandDuchy) {
2136 					return "Grand Duchy";
2137 				} else if (faction_tier == FactionTierKingdom) {
2138 					return "Kingdom";
2139 				} else if (faction_tier == FactionTierEmpire) {
2140 					return "Empire";
2141 				}
2142 			} else if (government_type == GovernmentTypeRepublic) {
2143 				return "Republic";
2144 			} else if (government_type == GovernmentTypeTheocracy) {
2145 				return "Theocracy";
2146 			}
2147 		}
2148 	}
2149 
2150 	return "";
2151 }
2152 
GetCharacterTitleName(int title_type,int gender) const2153 std::string CPlayer::GetCharacterTitleName(int title_type, int gender) const
2154 {
2155 	if (this->Race == -1 || this->Faction == -1 || title_type == -1 || gender == -1) {
2156 		return "";
2157 	}
2158 
2159 	CCivilization *civilization = CCivilization::Civilizations[this->Race];
2160 	CFaction *faction = PlayerRaces.Factions[this->Faction];
2161 	int faction_tier = faction->DefaultTier;
2162 	int government_type = faction->DefaultGovernmentType;
2163 
2164 	if (faction->Type == FactionTypePolity) {
2165 		if (!faction->MinisterTitles[title_type][gender][government_type][faction_tier].empty()) {
2166 			return faction->MinisterTitles[title_type][gender][government_type][faction_tier];
2167 		} else if (!faction->MinisterTitles[title_type][NoGender][government_type][faction_tier].empty()) {
2168 			return faction->MinisterTitles[title_type][NoGender][government_type][faction_tier];
2169 		} else if (!faction->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][faction_tier].empty()) {
2170 			return faction->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][faction_tier];
2171 		} else if (!faction->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][faction_tier].empty()) {
2172 			return faction->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][faction_tier];
2173 		} else if (!faction->MinisterTitles[title_type][gender][government_type][FactionTierNoFactionTier].empty()) {
2174 			return faction->MinisterTitles[title_type][gender][government_type][FactionTierNoFactionTier];
2175 		} else if (!faction->MinisterTitles[title_type][NoGender][government_type][FactionTierNoFactionTier].empty()) {
2176 			return faction->MinisterTitles[title_type][NoGender][government_type][FactionTierNoFactionTier];
2177 		} else if (!faction->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier].empty()) {
2178 			return faction->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier];
2179 		} else if (!faction->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier].empty()) {
2180 			return faction->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier];
2181 		} else if (!civilization->MinisterTitles[title_type][gender][government_type][faction_tier].empty()) {
2182 			return civilization->MinisterTitles[title_type][gender][government_type][faction_tier];
2183 		} else if (!civilization->MinisterTitles[title_type][NoGender][government_type][faction_tier].empty()) {
2184 			return civilization->MinisterTitles[title_type][NoGender][government_type][faction_tier];
2185 		} else if (!civilization->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][faction_tier].empty()) {
2186 			return civilization->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][faction_tier];
2187 		} else if (!civilization->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][faction_tier].empty()) {
2188 			return civilization->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][faction_tier];
2189 		} else if (!civilization->MinisterTitles[title_type][gender][government_type][FactionTierNoFactionTier].empty()) {
2190 			return civilization->MinisterTitles[title_type][gender][government_type][FactionTierNoFactionTier];
2191 		} else if (!civilization->MinisterTitles[title_type][NoGender][government_type][FactionTierNoFactionTier].empty()) {
2192 			return civilization->MinisterTitles[title_type][NoGender][government_type][FactionTierNoFactionTier];
2193 		} else if (!civilization->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier].empty()) {
2194 			return civilization->MinisterTitles[title_type][gender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier];
2195 		} else if (!civilization->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier].empty()) {
2196 			return civilization->MinisterTitles[title_type][NoGender][GovernmentTypeNoGovernmentType][FactionTierNoFactionTier];
2197 		}
2198 	}
2199 
2200 	if (title_type == CharacterTitleHeadOfState) {
2201 		if (faction->Type == FactionTypeTribe) {
2202 			if (gender != FemaleGender) {
2203 				return "Chieftain";
2204 			} else {
2205 				return "Chieftess";
2206 			}
2207 		} else if (faction->Type == FactionTypePolity) {
2208 			std::string faction_title = this->GetFactionTitleName();
2209 
2210 			if (faction_title == "Barony") {
2211 				if (gender != FemaleGender) {
2212 					return "Baron";
2213 				} else {
2214 					return "Baroness";
2215 				}
2216 			} else if (faction_title == "Lordship") {
2217 				if (gender != FemaleGender) {
2218 					return "Lord";
2219 				} else {
2220 					return "Lady";
2221 				}
2222 			} else if (faction_title == "County") {
2223 				if (gender != FemaleGender) {
2224 					return "Count";
2225 				} else {
2226 					return "Countess";
2227 				}
2228 			} else if (faction_title == "City-State") {
2229 				return "Archon";
2230 			} else if (faction_title == "Duchy") {
2231 				if (gender != FemaleGender) {
2232 					return "Duke";
2233 				} else {
2234 					return "Duchess";
2235 				}
2236 			} else if (faction_title == "Principality") {
2237 				if (gender != FemaleGender) {
2238 					return "Prince";
2239 				} else {
2240 					return "Princess";
2241 				}
2242 			} else if (faction_title == "Margraviate") {
2243 				return "Margrave";
2244 			} else if (faction_title == "Landgraviate") {
2245 				return "Landgrave";
2246 			} else if (faction_title == "Grand Duchy") {
2247 				if (gender != FemaleGender) {
2248 					return "Grand Duke";
2249 				} else {
2250 					return "Grand Duchess";
2251 				}
2252 			} else if (faction_title == "Archduchy") {
2253 				if (gender != FemaleGender) {
2254 					return "Archduke";
2255 				} else {
2256 					return "Archduchess";
2257 				}
2258 			} else if (faction_title == "Kingdom") {
2259 				if (gender != FemaleGender) {
2260 					return "King";
2261 				} else {
2262 					return "Queen";
2263 				}
2264 			} else if (faction_title == "Khanate") {
2265 				return "Khan";
2266 			} else if (faction_title == "Empire") {
2267 				if (gender != FemaleGender) {
2268 					return "Emperor";
2269 				} else {
2270 					return "Empress";
2271 				}
2272 			} else if (faction_title == "Republic") {
2273 				return "Consul";
2274 			} else if (faction_title == "Confederation") {
2275 				return "Chancellor";
2276 			} else if (faction_title == "Theocracy") {
2277 				if (gender != FemaleGender) {
2278 					return "High Priest";
2279 				} else {
2280 					return "High Priestess";
2281 				}
2282 			} else if (faction_title == "Bishopric") {
2283 				return "Bishop";
2284 			} else if (faction_title == "Archbishopric") {
2285 				return "Archbishop";
2286 			}
2287 		}
2288 	} else if (title_type == CharacterTitleHeadOfGovernment) {
2289 		return "Prime Minister";
2290 	} else if (title_type == CharacterTitleEducationMinister) {
2291 //		return "Education Minister"; //education minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2292 		return "Master Educator";
2293 	} else if (title_type == CharacterTitleFinanceMinister) {
2294 //		return "Finance Minister"; //finance minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2295 		return "Treasurer";
2296 	} else if (title_type == CharacterTitleForeignMinister) {
2297 //		return "Foreign Minister"; //foreign minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2298 		return "Chancellor";
2299 	} else if (title_type == CharacterTitleIntelligenceMinister) {
2300 //		return "Intelligence Minister"; //intelligence minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2301 		return "Spymaster";
2302 	} else if (title_type == CharacterTitleInteriorMinister) {
2303 //		return "Interior Minister"; //interior minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2304 		return "High Constable";
2305 	} else if (title_type == CharacterTitleJusticeMinister) {
2306 //		return "Justice Minister"; //justice minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2307 		return "Master of Laws";
2308 	} else if (title_type == CharacterTitleWarMinister) {
2309 //		return "War Minister"; //war minister sounds too modern, considering the technology tree we have up to now only goes to the medieval era
2310 		return "Marshal";
2311 	} else if (title_type == CharacterTitleGovernor) {
2312 		return "Governor";
2313 	} else if (title_type == CharacterTitleMayor) {
2314 		return "Mayor";
2315 	}
2316 
2317 	return "";
2318 }
2319 
GetWorkerLandmasses(std::vector<int> & worker_landmasses,const CUnitType * building)2320 void CPlayer::GetWorkerLandmasses(std::vector<int>& worker_landmasses, const CUnitType *building)
2321 {
2322 	for (unsigned int i = 0; i < AiHelpers.Build[building->Slot].size(); ++i) {
2323 		if (this->GetUnitTypeAiActiveCount(AiHelpers.Build[building->Slot][i])) {
2324 			std::vector<CUnit *> worker_table;
2325 
2326 			FindPlayerUnitsByType(*this, *AiHelpers.Build[building->Slot][i], worker_table, true);
2327 
2328 			for (size_t j = 0; j != worker_table.size(); ++j) {
2329 				int worker_landmass = Map.GetTileLandmass(worker_table[j]->tilePos, worker_table[j]->MapLayer->ID);
2330 				if (std::find(worker_landmasses.begin(), worker_landmasses.end(), worker_landmass) == worker_landmasses.end()) {
2331 					worker_landmasses.push_back(worker_landmass);
2332 				}
2333 			}
2334 		}
2335 	}
2336 }
2337 
GetResearchableUpgrades()2338 std::vector<CUpgrade *> CPlayer::GetResearchableUpgrades()
2339 {
2340 	std::vector<CUpgrade *> researchable_upgrades;
2341 	for (std::map<const CUnitType *, int>::iterator iterator = this->UnitTypesAiActiveCount.begin(); iterator != this->UnitTypesAiActiveCount.end(); ++iterator) {
2342 		const CUnitType *type = iterator->first;
2343 		if (type->Slot < ((int) AiHelpers.ResearchedUpgrades.size())) {
2344 			for (size_t i = 0; i < AiHelpers.ResearchedUpgrades[type->Slot].size(); ++i) {
2345 				CUpgrade *upgrade = AiHelpers.ResearchedUpgrades[type->Slot][i];
2346 				if (std::find(researchable_upgrades.begin(), researchable_upgrades.end(), upgrade) == researchable_upgrades.end()) {
2347 					researchable_upgrades.push_back(upgrade);
2348 				}
2349 			}
2350 		}
2351 	}
2352 
2353 	return researchable_upgrades;
2354 }
2355 //Wyrmgus end
2356 
2357 /**
2358 **  Clear all player data excepts members which don't change.
2359 **
2360 **  The fields that are not cleared are
2361 **  UnitLimit, BuildingLimit, TotalUnitLimit and Allow.
2362 */
Clear()2363 void CPlayer::Clear()
2364 {
2365 	Index = 0;
2366 	Name.clear();
2367 	Type = 0;
2368 	Race = 0;
2369 	Faction = -1;
2370 	Religion = nullptr;
2371 	Dynasty = nullptr;
2372 	Age = nullptr;
2373 	Overlord = nullptr;
2374 	Vassals.clear();
2375 	AiName.clear();
2376 	Team = 0;
2377 	Enemy = 0;
2378 	Allied = 0;
2379 	SharedVision = 0;
2380 	StartPos.x = 0;
2381 	StartPos.y = 0;
2382 	//Wyrmgus start
2383 	StartMapLayer = 0;
2384 	//Wyrmgus end
2385 	memset(Resources, 0, sizeof(Resources));
2386 	memset(StoredResources, 0, sizeof(StoredResources));
2387 	memset(MaxResources, 0, sizeof(MaxResources));
2388 	memset(LastResources, 0, sizeof(LastResources));
2389 	memset(Incomes, 0, sizeof(Incomes));
2390 	memset(Revenue, 0, sizeof(Revenue));
2391 	//Wyrmgus start
2392 	memset(ResourceDemand, 0, sizeof(ResourceDemand));
2393 	memset(StoredResourceDemand, 0, sizeof(StoredResourceDemand));
2394 	//Wyrmgus end
2395 	this->UnitTypesCount.clear();
2396 	this->UnitTypesUnderConstructionCount.clear();
2397 	this->UnitTypesAiActiveCount.clear();
2398 	//Wyrmgus start
2399 	this->Heroes.clear();
2400 	this->Deities.clear();
2401 	this->UnitsByType.clear();
2402 	this->AiActiveUnitsByType.clear();
2403 	this->AvailableQuests.clear();
2404 	this->CurrentQuests.clear();
2405 	this->CompletedQuests.clear();
2406 	this->AutosellResources.clear();
2407 	for (size_t i = 0; i < this->QuestObjectives.size(); ++i) {
2408 		delete this->QuestObjectives[i];
2409 	}
2410 	this->QuestObjectives.clear();
2411 	this->Modifiers.clear();
2412 	//Wyrmgus end
2413 	AiEnabled = false;
2414 	//Wyrmgus start
2415 	Revealed = false;
2416 	//Wyrmgus end
2417 	Ai = 0;
2418 	this->Units.resize(0);
2419 	this->FreeWorkers.resize(0);
2420 	//Wyrmgus start
2421 	this->LevelUpUnits.resize(0);
2422 	//Wyrmgus end
2423 	NumBuildings = 0;
2424 	//Wyrmgus start
2425 	NumBuildingsUnderConstruction = 0;
2426 	NumTownHalls = 0;
2427 	//Wyrmgus end
2428 	Supply = 0;
2429 	Demand = 0;
2430 	TradeCost = 0;
2431 	// FIXME: can't clear limits since it's initialized already
2432 	//	UnitLimit = 0;
2433 	//	BuildingLimit = 0;
2434 	//	TotalUnitLimit = 0;
2435 	Score = 0;
2436 	TotalUnits = 0;
2437 	TotalBuildings = 0;
2438 	memset(TotalResources, 0, sizeof(TotalResources));
2439 	TotalRazings = 0;
2440 	TotalKills = 0;
2441 	//Wyrmgus start
2442 	memset(UnitTypeKills, 0, sizeof(UnitTypeKills));
2443 	LostTownHallTimer = 0;
2444 	HeroCooldownTimer = 0;
2445 	//Wyrmgus end
2446 	Color = 0;
2447 	UpgradeTimers.Clear();
2448 	for (int i = 0; i < MaxCosts; ++i) {
2449 		SpeedResourcesHarvest[i] = SPEEDUP_FACTOR;
2450 		SpeedResourcesReturn[i] = SPEEDUP_FACTOR;
2451 		//Wyrmgus start
2452 		Prices[i] = CResource::Resources[i]->BasePrice;
2453 		//Wyrmgus end
2454 	}
2455 	SpeedBuild = SPEEDUP_FACTOR;
2456 	SpeedTrain = SPEEDUP_FACTOR;
2457 	SpeedUpgrade = SPEEDUP_FACTOR;
2458 	SpeedResearch = SPEEDUP_FACTOR;
2459 }
2460 
2461 
AddUnit(CUnit & unit)2462 void CPlayer::AddUnit(CUnit &unit)
2463 {
2464 	Assert(unit.Player != this);
2465 	Assert(unit.PlayerSlot == static_cast<size_t>(-1));
2466 	unit.PlayerSlot = this->Units.size();
2467 	this->Units.push_back(&unit);
2468 	unit.Player = this;
2469 	Assert(this->Units[unit.PlayerSlot] == &unit);
2470 }
2471 
RemoveUnit(CUnit & unit)2472 void CPlayer::RemoveUnit(CUnit &unit)
2473 {
2474 	Assert(unit.Player == this);
2475 	//Wyrmgus start
2476 	if (unit.PlayerSlot == -1 || this->Units[unit.PlayerSlot] != &unit) {
2477 		fprintf(stderr, "Error in CPlayer::RemoveUnit: the unit's PlayerSlot doesn't match its position in the player's units array; Unit's PlayerSlot: %d, Unit Type: \"%s\".\n", unit.PlayerSlot, unit.Type ? unit.Type->Ident.c_str() : "");
2478 		return;
2479 	}
2480 	//Wyrmgus end
2481 	Assert(this->Units[unit.PlayerSlot] == &unit);
2482 
2483 	//	unit.Player = nullptr; // we can remove dying unit...
2484 	CUnit *last = this->Units.back();
2485 
2486 	this->Units[unit.PlayerSlot] = last;
2487 	last->PlayerSlot = unit.PlayerSlot;
2488 	this->Units.pop_back();
2489 	unit.PlayerSlot = static_cast<size_t>(-1);
2490 	Assert(last == &unit || this->Units[last->PlayerSlot] == last);
2491 }
2492 
UpdateFreeWorkers()2493 void CPlayer::UpdateFreeWorkers()
2494 {
2495 	FreeWorkers.clear();
2496 	if (FreeWorkers.capacity() != 0) {
2497 		// Just calling FreeWorkers.clear() is not always appropriate.
2498 		// Certain paths may leave FreeWorkers in an invalid state, so
2499 		// it's safer to re-initialize.
2500 		std::vector<CUnit*>().swap(FreeWorkers);
2501 	}
2502 	const int nunits = this->GetUnitCount();
2503 
2504 	for (int i = 0; i < nunits; ++i) {
2505 		CUnit &unit = this->GetUnit(i);
2506 		//Wyrmgus start
2507 //		if (unit.IsAlive() && unit.Type->BoolFlag[HARVESTER_INDEX].value && !unit.Removed) {
2508 		if (unit.IsAlive() && unit.Type->BoolFlag[HARVESTER_INDEX].value && !unit.Removed && !unit.Type->BoolFlag[TRADER_INDEX].value) {
2509 		//Wyrmgus end
2510 			if (unit.CurrentAction() == UnitActionStill) {
2511 				FreeWorkers.push_back(&unit);
2512 			}
2513 		}
2514 	}
2515 }
2516 
2517 //Wyrmgus start
PerformResourceTrade()2518 void CPlayer::PerformResourceTrade()
2519 {
2520 	CUnit *market_unit = this->GetMarketUnit();
2521 
2522 	if (!market_unit) {
2523 		return;
2524 	}
2525 
2526 	for (size_t i = 0; i < this->AutosellResources.size(); ++i) {
2527 		const int res = this->AutosellResources[i];
2528 
2529 		if ((this->Resources[res] + this->StoredResources[res]) >= 100) { //sell 100 per second, as long as there is enough of the resource stored
2530 			market_unit->SellResource(res, this->Index);
2531 		}
2532 
2533 		//increase price due to domestic demand
2534 		this->StoredResourceDemand[res] += this->GetEffectiveResourceDemand(res);
2535 		while (this->StoredResourceDemand[res] >= 100) {
2536 			this->IncreaseResourcePrice(res);
2537 			this->StoredResourceDemand[res] -= 100;
2538 		}
2539 	}
2540 
2541 	for (size_t i = 0; i < LuxuryResources.size(); ++i) {
2542 		const int res = LuxuryResources[i];
2543 
2544 		while ((this->Resources[res] + this->StoredResources[res]) >= 100) {
2545 			market_unit->SellResource(res, this->Index);
2546 		}
2547 
2548 		//increase price due to domestic demand
2549 		this->StoredResourceDemand[res] += this->GetEffectiveResourceDemand(res);
2550 		while (this->StoredResourceDemand[res] >= 100) {
2551 			this->IncreaseResourcePrice(res);
2552 			this->StoredResourceDemand[res] -= 100;
2553 		}
2554 	}
2555 }
2556 
2557 /**
2558 **	@brief	Get whether the player has a market unit
2559 **
2560 **	@return	True if the player has a market unit, or false otherwise
2561 */
HasMarketUnit() const2562 bool CPlayer::HasMarketUnit() const
2563 {
2564 	const int n_m = AiHelpers.SellMarkets[0].size();
2565 
2566 	for (int i = 0; i < n_m; ++i) {
2567 		CUnitType &market_type = *AiHelpers.SellMarkets[0][i];
2568 
2569 		if (this->GetUnitTypeCount(&market_type)) {
2570 			return true;
2571 		}
2572 	}
2573 
2574 	return false;
2575 }
2576 
2577 /**
2578 **	@brief	Get the player's market unit, if any
2579 **
2580 **	@return	The market unit if present, or null otherwise
2581 */
GetMarketUnit() const2582 CUnit *CPlayer::GetMarketUnit() const
2583 {
2584 	CUnit *market_unit = nullptr;
2585 
2586 	const int n_m = AiHelpers.SellMarkets[0].size();
2587 
2588 	for (int i = 0; i < n_m; ++i) {
2589 		CUnitType &market_type = *AiHelpers.SellMarkets[0][i];
2590 
2591 		if (this->GetUnitTypeCount(&market_type)) {
2592 			std::vector<CUnit *> market_table;
2593 			FindPlayerUnitsByType(*this, market_type, market_table);
2594 			if (market_table.size() > 0) {
2595 				market_unit = market_table[SyncRand() % market_table.size()];
2596 				break;
2597 			}
2598 		}
2599 	}
2600 
2601 	return market_unit;
2602 }
2603 
GetAutosellResources() const2604 std::vector<int> CPlayer::GetAutosellResources() const
2605 {
2606 	return this->AutosellResources;
2607 }
2608 
AutosellResource(const int resource)2609 void CPlayer::AutosellResource(const int resource)
2610 {
2611 	if (std::find(this->AutosellResources.begin(), this->AutosellResources.end(), resource) != this->AutosellResources.end()) {
2612 		this->AutosellResources.erase(std::remove(this->AutosellResources.begin(), this->AutosellResources.end(), resource), this->AutosellResources.end());
2613 	} else {
2614 		this->AutosellResources.push_back(resource);
2615 	}
2616 }
2617 
UpdateLevelUpUnits()2618 void CPlayer::UpdateLevelUpUnits()
2619 {
2620 	LevelUpUnits.clear();
2621 	if (LevelUpUnits.capacity() != 0) {
2622 		// Just calling LevelUpUnits.clear() is not always appropriate.
2623 		// Certain paths may leave LevelUpUnits in an invalid state, so
2624 		// it's safer to re-initialize.
2625 		std::vector<CUnit*>().swap(LevelUpUnits);
2626 	}
2627 	const int nunits = this->GetUnitCount();
2628 
2629 	for (int i = 0; i < nunits; ++i) {
2630 		CUnit &unit = this->GetUnit(i);
2631 		if (unit.IsAlive() && unit.Variable[LEVELUP_INDEX].Value >= 1) {
2632 			LevelUpUnits.push_back(&unit);
2633 		}
2634 	}
2635 }
2636 
UpdateQuestPool()2637 void CPlayer::UpdateQuestPool()
2638 {
2639 	if (CurrentCampaign == nullptr) { // in-game quests only while playing the campaign mode
2640 		return;
2641 	}
2642 
2643 	bool exausted_available_quests = (this->AvailableQuests.size() == 0);
2644 
2645 	this->AvailableQuests.clear();
2646 
2647 	std::vector<CQuest *> potential_quests;
2648 	for (size_t i = 0; i < Quests.size(); ++i) {
2649 		if (this->CanAcceptQuest(Quests[i])) {
2650 			potential_quests.push_back(Quests[i]);
2651 		}
2652 	}
2653 
2654 	int max_quest_pool_size = 3 - ((int) this->CurrentQuests.size());
2655 	for (int i = 0; i < max_quest_pool_size; ++i) { // fill the quest pool with up to three quests
2656 		if (potential_quests.size() == 0) {
2657 			break;
2658 		}
2659 		this->AvailableQuests.push_back(potential_quests[SyncRand(potential_quests.size())]);
2660 		int available_quest_quantity = this->AvailableQuests.size();
2661 		potential_quests.erase(std::remove(potential_quests.begin(), potential_quests.end(), this->AvailableQuests[available_quest_quantity - 1]), potential_quests.end());
2662 	}
2663 
2664 	this->AvailableQuestsChanged();
2665 
2666 	// notify the player when new quests are available (but only if the player has already exausted the quests available to him, so that they aren't bothered if they choose not to engage with the quest system)
2667 	if (this == ThisPlayer && GameCycle >= CYCLES_PER_MINUTE && this->AvailableQuests.size() > 0 && exausted_available_quests && this->NumTownHalls > 0) {
2668 		ThisPlayer->Notify("%s", _("New quests available"));
2669 	}
2670 
2671 	if (this->AiEnabled) { // if is an AI player, accept all quests that it can
2672 		int available_quest_quantity = this->AvailableQuests.size();
2673 		for (int i = (available_quest_quantity  - 1); i >= 0; --i) {
2674 			if (this->CanAcceptQuest(this->AvailableQuests[i])) { // something may have changed, so recheck if the player is able to accept the quest
2675 				this->AcceptQuest(this->AvailableQuests[i]);
2676 			}
2677 		}
2678 	}
2679 }
2680 
AvailableQuestsChanged()2681 void CPlayer::AvailableQuestsChanged()
2682 {
2683 	if (this == ThisPlayer) {
2684 		for (int i = 0; i < (int) UnitButtonTable.size(); ++i) {
2685 			if (UnitButtonTable[i]->Action != ButtonQuest || UnitButtonTable[i]->Value >= (int) this->AvailableQuests.size()) {
2686 				continue;
2687 			}
2688 
2689 			const CQuest *quest = this->AvailableQuests[UnitButtonTable[i]->Value];
2690 			UnitButtonTable[i]->Hint = "Quest: " + quest->Name;
2691 			UnitButtonTable[i]->Description = quest->Description + "\n \nObjectives:";
2692 			for (size_t j = 0; j < quest->Objectives.size(); ++j) {
2693 				UnitButtonTable[i]->Description += "\n- " + quest->Objectives[j]->ObjectiveString;
2694 			}
2695 			for (size_t j = 0; j < quest->ObjectiveStrings.size(); ++j) {
2696 				UnitButtonTable[i]->Description += "\n" + quest->ObjectiveStrings[j];
2697 			}
2698 			if (!quest->Rewards.empty()) {
2699 				UnitButtonTable[i]->Description += "\n \nRewards: " + quest->Rewards;
2700 			}
2701 			if (!quest->Hint.empty()) {
2702 				UnitButtonTable[i]->Description += "\n \nHint: " + quest->Hint;
2703 			}
2704 			if (quest->HighestCompletedDifficulty > DifficultyNoDifficulty) {
2705 				std::string highest_completed_difficulty;
2706 				if (quest->HighestCompletedDifficulty == DifficultyEasy) {
2707 					highest_completed_difficulty = "Easy";
2708 				} else if (quest->HighestCompletedDifficulty == DifficultyNormal) {
2709 					highest_completed_difficulty = "Normal";
2710 				} else if (quest->HighestCompletedDifficulty == DifficultyHard) {
2711 					highest_completed_difficulty = "Hard";
2712 				} else if (quest->HighestCompletedDifficulty == DifficultyBrutal) {
2713 					highest_completed_difficulty = "Brutal";
2714 				}
2715 				UnitButtonTable[i]->Description += "\n \nHighest Completed Difficulty: " + highest_completed_difficulty;
2716 			}
2717 
2718 		}
2719 
2720 		if (!Selected.empty() && Selected[0]->Type->BoolFlag[TOWNHALL_INDEX].value) {
2721 			UI.ButtonPanel.Update();
2722 		}
2723 	}
2724 }
2725 
UpdateCurrentQuests()2726 void CPlayer::UpdateCurrentQuests()
2727 {
2728 	for (size_t i = 0; i < this->QuestObjectives.size(); ++i) {
2729 		CPlayerQuestObjective *objective = this->QuestObjectives[i];
2730 		if (objective->ObjectiveType == HaveResourceObjectiveType) {
2731 			objective->Counter = std::min(this->GetResource(objective->Resource, STORE_BOTH), objective->Quantity);
2732 		} else if (objective->ObjectiveType == ResearchUpgradeObjectiveType) {
2733 			objective->Counter = UpgradeIdAllowed(*this, objective->Upgrade->ID) == 'R' ? 1 : 0;
2734 		} else if (objective->ObjectiveType == RecruitHeroObjectiveType) {
2735 			objective->Counter = this->HasHero(objective->Character) ? 1 : 0;
2736 		}
2737 	}
2738 
2739 	for (int i = (this->CurrentQuests.size()  - 1); i >= 0; --i) {
2740 		std::string failed_quest = this->HasFailedQuest(this->CurrentQuests[i]);
2741 		if (!failed_quest.empty()) {
2742 			this->FailQuest(this->CurrentQuests[i], failed_quest);
2743 		} else if (this->HasCompletedQuest(this->CurrentQuests[i])) {
2744 			this->CompleteQuest(this->CurrentQuests[i]);
2745 		}
2746 	}
2747 }
2748 
AcceptQuest(CQuest * quest)2749 void CPlayer::AcceptQuest(CQuest *quest)
2750 {
2751 	if (!quest) {
2752 		return;
2753 	}
2754 
2755 	this->AvailableQuests.erase(std::remove(this->AvailableQuests.begin(), this->AvailableQuests.end(), quest), this->AvailableQuests.end());
2756 	this->CurrentQuests.push_back(quest);
2757 
2758 	for (size_t i = 0; i < quest->Objectives.size(); ++i) {
2759 		CPlayerQuestObjective *objective = new CPlayerQuestObjective;
2760 		objective->ObjectiveType = quest->Objectives[i]->ObjectiveType;
2761 		objective->Quest = quest->Objectives[i]->Quest;
2762 		objective->ObjectiveString = quest->Objectives[i]->ObjectiveString;
2763 		objective->Quantity = quest->Objectives[i]->Quantity;
2764 		objective->Resource = quest->Objectives[i]->Resource;
2765 		objective->UnitClass = quest->Objectives[i]->UnitClass;
2766 		objective->UnitTypes = quest->Objectives[i]->UnitTypes;
2767 		objective->Upgrade = quest->Objectives[i]->Upgrade;
2768 		objective->Character = quest->Objectives[i]->Character;
2769 		objective->Unique = quest->Objectives[i]->Unique;
2770 		objective->Settlement = quest->Objectives[i]->Settlement;
2771 		objective->Faction = quest->Objectives[i]->Faction;
2772 		this->QuestObjectives.push_back(objective);
2773 	}
2774 
2775 	CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2776 
2777 	if (quest->AcceptEffects) {
2778 		quest->AcceptEffects->pushPreamble();
2779 		quest->AcceptEffects->run();
2780 	}
2781 
2782 	this->AvailableQuestsChanged();
2783 
2784 	this->UpdateCurrentQuests();
2785 }
2786 
CompleteQuest(CQuest * quest)2787 void CPlayer::CompleteQuest(CQuest *quest)
2788 {
2789 	if (std::find(this->CompletedQuests.begin(), this->CompletedQuests.end(), quest) != this->CompletedQuests.end()) {
2790 		return;
2791 	}
2792 
2793 	RemoveCurrentQuest(quest);
2794 
2795 	this->CompletedQuests.push_back(quest);
2796 	if (quest->Competitive) {
2797 		quest->CurrentCompleted = true;
2798 	}
2799 
2800 	CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2801 
2802 	if (quest->CompletionEffects) {
2803 		quest->CompletionEffects->pushPreamble();
2804 		quest->CompletionEffects->run();
2805 	}
2806 
2807 	if (this == ThisPlayer) {
2808 		SetQuestCompleted(quest->Ident, GameSettings.Difficulty);
2809 		SaveQuestCompletion();
2810 		std::string rewards_string;
2811 		if (!quest->Rewards.empty()) {
2812 			rewards_string = "Rewards: " + quest->Rewards;
2813 		}
2814 		CclCommand("if (GenericDialog ~= nil) then GenericDialog(\"Quest Completed\", \"You have completed the " + quest->Name + " quest!\\n\\n" + rewards_string + "\", nil, \"" + quest->Icon.Name + "\", \"" + PlayerColorNames[quest->PlayerColor] + "\", " + std::to_string((long long) (quest->Icon.Icon ? quest->Icon.Icon->Frame : 0)) + ") end;");
2815 	}
2816 }
2817 
FailQuest(CQuest * quest,std::string fail_reason)2818 void CPlayer::FailQuest(CQuest *quest, std::string fail_reason)
2819 {
2820 	this->RemoveCurrentQuest(quest);
2821 
2822 	CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2823 
2824 	if (quest->FailEffects) {
2825 		quest->FailEffects->pushPreamble();
2826 		quest->FailEffects->run();
2827 	}
2828 
2829 	if (this == ThisPlayer) {
2830 		CclCommand("if (GenericDialog ~= nil) then GenericDialog(\"Quest Failed\", \"You have failed the " + quest->Name + " quest! " + fail_reason + "\", nil, \"" + quest->Icon.Name + "\", \"" + PlayerColorNames[quest->PlayerColor] + "\") end;");
2831 	}
2832 }
2833 
RemoveCurrentQuest(CQuest * quest)2834 void CPlayer::RemoveCurrentQuest(CQuest *quest)
2835 {
2836 	this->CurrentQuests.erase(std::remove(this->CurrentQuests.begin(), this->CurrentQuests.end(), quest), this->CurrentQuests.end());
2837 
2838 	for (int i = (this->QuestObjectives.size()  - 1); i >= 0; --i) {
2839 		if (this->QuestObjectives[i]->Quest == quest) {
2840 			this->QuestObjectives.erase(std::remove(this->QuestObjectives.begin(), this->QuestObjectives.end(), this->QuestObjectives[i]), this->QuestObjectives.end());
2841 		}
2842 	}
2843 }
2844 
CanAcceptQuest(CQuest * quest)2845 bool CPlayer::CanAcceptQuest(CQuest *quest)
2846 {
2847 	if (quest->Hidden || quest->CurrentCompleted || quest->Unobtainable) {
2848 		return false;
2849 	}
2850 
2851 	if (std::find(this->CurrentQuests.begin(), this->CurrentQuests.end(), quest) != this->CurrentQuests.end() || std::find(this->CompletedQuests.begin(), this->CompletedQuests.end(), quest) != this->CompletedQuests.end()) {
2852 		return false;
2853 	}
2854 
2855 	int recruit_heroes_quantity = 0;
2856 	for (size_t i = 0; i < quest->Objectives.size(); ++i) {
2857 		CQuestObjective *objective = quest->Objectives[i];
2858 		if (objective->ObjectiveType == BuildUnitsObjectiveType || objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
2859 			std::vector<const CUnitType *> unit_types = objective->UnitTypes;
2860 			if (objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
2861 				int unit_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, objective->UnitClass);
2862 				if (unit_type_id == -1) {
2863 					return false;
2864 				}
2865 				unit_types.clear();
2866 				unit_types.push_back(UnitTypes[unit_type_id]);
2867 			}
2868 
2869 			bool validated = false;
2870 			for (const CUnitType *unit_type : unit_types) {
2871 				if (objective->Settlement && !this->HasSettlement(objective->Settlement) && !unit_type->BoolFlag[TOWNHALL_INDEX].value) {
2872 					continue;
2873 				}
2874 
2875 				if (!this->HasUnitBuilder(unit_type, objective->Settlement) || !CheckDependencies(unit_type, this)) {
2876 					continue;
2877 				}
2878 
2879 				validated = true;
2880 			}
2881 
2882 			if (!validated) {
2883 				return false;
2884 			}
2885 		} else if (objective->ObjectiveType == ResearchUpgradeObjectiveType) {
2886 			const CUpgrade *upgrade = objective->Upgrade;
2887 
2888 			bool has_researcher = this->HasUpgradeResearcher(upgrade);
2889 
2890 			if (!has_researcher && upgrade->ID < (int) AiHelpers.Research.size()) { //check if the quest includes an objective to build a researcher of the upgrade
2891 				for (CQuestObjective *second_objective : quest->Objectives) {
2892 					if (second_objective == objective) {
2893 						continue;
2894 					}
2895 
2896 					if (second_objective->ObjectiveType == BuildUnitsObjectiveType || second_objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
2897 						std::vector<const CUnitType *> unit_types = second_objective->UnitTypes;
2898 						if (second_objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
2899 							int unit_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, second_objective->UnitClass);
2900 							if (unit_type_id == -1) {
2901 								continue;
2902 							}
2903 							unit_types.clear();
2904 							unit_types.push_back(UnitTypes[unit_type_id]);
2905 						}
2906 
2907 						for (const CUnitType *unit_type : unit_types) {
2908 							if (std::find(AiHelpers.Research[upgrade->ID].begin(), AiHelpers.Research[upgrade->ID].end(), unit_type) != AiHelpers.Research[upgrade->ID].end()) { //if the unit type of the other objective is a researcher of this upgrade
2909 								has_researcher = true;
2910 								break;
2911 							}
2912 						}
2913 
2914 						if (has_researcher) {
2915 							break;
2916 						}
2917 					}
2918 				}
2919 			}
2920 
2921 			if (!has_researcher || this->Allow.Upgrades[upgrade->ID] != 'A' || !CheckDependencies(upgrade, this)) {
2922 				return false;
2923 			}
2924 		} else if (objective->ObjectiveType == RecruitHeroObjectiveType) {
2925 			if (!this->CanRecruitHero(objective->Character, true)) {
2926 				return false;
2927 			}
2928 			recruit_heroes_quantity++;
2929 		} else if (objective->ObjectiveType == DestroyUnitsObjectiveType || objective->ObjectiveType == DestroyHeroObjectiveType || objective->ObjectiveType == DestroyUniqueObjectiveType) {
2930 			if (objective->Faction) {
2931 				CPlayer *faction_player = GetFactionPlayer(objective->Faction);
2932 				if (faction_player == nullptr || faction_player->GetUnitCount() == 0) {
2933 					return false;
2934 				}
2935 
2936 				if (objective->Settlement && !faction_player->HasSettlement(objective->Settlement)) {
2937 					return false;
2938 				}
2939 			}
2940 
2941 			if (objective->ObjectiveType == DestroyHeroObjectiveType) {
2942 				if (objective->Character->CanAppear()) { //if the character "can appear" it doesn't already exist, and thus can't be destroyed
2943 					return false;
2944 				}
2945 			} else if (objective->ObjectiveType == DestroyUniqueObjectiveType) {
2946 				if (objective->Unique->CanDrop()) { //if the unique "can drop" it doesn't already exist, and thus can't be destroyed
2947 					return false;
2948 				}
2949 			}
2950 		} else if (objective->ObjectiveType == DestroyFactionObjectiveType) {
2951 			CPlayer *faction_player = GetFactionPlayer(objective->Faction);
2952 			if (faction_player == nullptr || faction_player->GetUnitCount() == 0) {
2953 				return false;
2954 			}
2955 		}
2956 	}
2957 
2958 	if (recruit_heroes_quantity > 0 && (this->Heroes.size() + recruit_heroes_quantity) > PlayerHeroMax) {
2959 		return false;
2960 	}
2961 
2962 	for (size_t i = 0; i < quest->HeroesMustSurvive.size(); ++i) {
2963 		if (!this->HasHero(quest->HeroesMustSurvive[i])) {
2964 			return false;
2965 		}
2966 	}
2967 
2968 	if (quest->Conditions) {
2969 		CclCommand("trigger_player = " + std::to_string((long long) this->Index) + ";");
2970 		quest->Conditions->pushPreamble();
2971 		quest->Conditions->run(1);
2972 		return quest->Conditions->popBoolean();
2973 	} else {
2974 		return true;
2975 	}
2976 }
2977 
HasCompletedQuest(CQuest * quest)2978 bool CPlayer::HasCompletedQuest(CQuest *quest)
2979 {
2980 	if (quest->Uncompleteable) {
2981 		return false;
2982 	}
2983 
2984 	for (size_t i = 0; i < this->QuestObjectives.size(); ++i) {
2985 		if (this->QuestObjectives[i]->Quest != quest) {
2986 			continue;
2987 		}
2988 		if (this->QuestObjectives[i]->Quantity > 0 && this->QuestObjectives[i]->Counter < this->QuestObjectives[i]->Quantity) {
2989 			return false;
2990 		}
2991 	}
2992 
2993 	return true;
2994 }
2995 
HasFailedQuest(CQuest * quest)2996 std::string CPlayer::HasFailedQuest(CQuest *quest) // returns the reason for failure (empty if none)
2997 {
2998 	for (size_t i = 0; i < quest->HeroesMustSurvive.size(); ++i) { // put it here, because "unfailable" quests should also fail when a hero which should survive dies
2999 		if (!this->HasHero(quest->HeroesMustSurvive[i])) {
3000 			return "A hero necessary for the quest has died.";
3001 		}
3002 	}
3003 
3004 	if (quest->CurrentCompleted) { // quest already completed by someone else
3005 		return "Another faction has completed the quest before you could.";
3006 	}
3007 
3008 	if (quest->Unfailable) {
3009 		return "";
3010 	}
3011 
3012 	for (size_t i = 0; i < this->QuestObjectives.size(); ++i) {
3013 		CPlayerQuestObjective *objective = this->QuestObjectives[i];
3014 		if (objective->Quest != quest) {
3015 			continue;
3016 		}
3017 		if (objective->ObjectiveType == BuildUnitsObjectiveType || objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
3018 			if (objective->Counter < objective->Quantity) {
3019 				std::vector<const CUnitType *> unit_types = objective->UnitTypes;
3020 				if (objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
3021 					int unit_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, objective->UnitClass);
3022 					if (unit_type_id == -1) {
3023 						return "You can no longer produce the required unit.";
3024 					}
3025 					unit_types.clear();
3026 					unit_types.push_back(UnitTypes[unit_type_id]);
3027 				}
3028 
3029 				bool validated = false;
3030 				std::string validation_error;
3031 				for (const CUnitType *unit_type : unit_types) {
3032 					if (objective->Settlement && !this->HasSettlement(objective->Settlement) && !unit_type->BoolFlag[TOWNHALL_INDEX].value) {
3033 						validation_error = "You no longer hold the required settlement.";
3034 						continue;
3035 					}
3036 
3037 					if (!this->HasUnitBuilder(unit_type, objective->Settlement) || !CheckDependencies(unit_type, this)) {
3038 						validation_error = "You can no longer produce the required unit.";
3039 						continue;
3040 					}
3041 
3042 					validated = true;
3043 				}
3044 
3045 				if (!validated) {
3046 					return validation_error;
3047 				}
3048 			}
3049 		} else if (objective->ObjectiveType == ResearchUpgradeObjectiveType) {
3050 			const CUpgrade *upgrade = objective->Upgrade;
3051 
3052 			if (this->Allow.Upgrades[upgrade->ID] != 'R') {
3053 				bool has_researcher = this->HasUpgradeResearcher(upgrade);
3054 
3055 				if (!has_researcher && upgrade->ID < (int) AiHelpers.Research.size()) { //check if the quest includes an objective to build a researcher of the upgrade
3056 					for (CPlayerQuestObjective *second_objective : this->QuestObjectives) {
3057 						if (second_objective->Quest != quest || second_objective == objective || second_objective->Counter >= second_objective->Quantity) { //if the objective has been fulfilled, then there should be a researcher, if there isn't it is due to i.e. the researcher having been destroyed later on, or upgraded to another type, and then the quest should fail if the upgrade can no longer be researched
3058 							continue;
3059 						}
3060 
3061 						if (second_objective->ObjectiveType == BuildUnitsObjectiveType || second_objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
3062 							std::vector<const CUnitType *> unit_types = second_objective->UnitTypes;
3063 							if (second_objective->ObjectiveType == BuildUnitsOfClassObjectiveType) {
3064 								int unit_type_id = PlayerRaces.GetFactionClassUnitType(this->Faction, second_objective->UnitClass);
3065 								if (unit_type_id == -1) {
3066 									continue;
3067 								}
3068 								unit_types.clear();
3069 								unit_types.push_back(UnitTypes[unit_type_id]);
3070 							}
3071 
3072 							for (const CUnitType *unit_type : unit_types) {
3073 								if (std::find(AiHelpers.Research[upgrade->ID].begin(), AiHelpers.Research[upgrade->ID].end(), unit_type) != AiHelpers.Research[upgrade->ID].end()) { //if the unit type of the other objective is a researcher of this upgrade
3074 									has_researcher = true;
3075 									break;
3076 								}
3077 							}
3078 
3079 							if (has_researcher) {
3080 								break;
3081 							}
3082 						}
3083 					}
3084 				}
3085 
3086 				if (!has_researcher || this->Allow.Upgrades[upgrade->ID] != 'A' || !CheckDependencies(upgrade, this)) {
3087 					return "You can no longer research the required upgrade.";
3088 				}
3089 			}
3090 		} else if (objective->ObjectiveType == RecruitHeroObjectiveType) {
3091 			if (!this->HasHero(objective->Character) && !this->CanRecruitHero(objective->Character, true)) {
3092 				return "The hero can no longer be recruited.";
3093 			}
3094 		} else if (objective->ObjectiveType == DestroyUnitsObjectiveType || objective->ObjectiveType == DestroyHeroObjectiveType || objective->ObjectiveType == DestroyUniqueObjectiveType) {
3095 			if (objective->Faction && objective->Counter < objective->Quantity) {
3096 				CPlayer *faction_player = GetFactionPlayer(objective->Faction);
3097 				if (faction_player == nullptr || faction_player->GetUnitCount() == 0) {
3098 					return "The target no longer exists.";
3099 				}
3100 
3101 				if (objective->Settlement && !faction_player->HasSettlement(objective->Settlement)) {
3102 					return "The target no longer exists.";
3103 				}
3104 			}
3105 
3106 			if (objective->ObjectiveType == DestroyHeroObjectiveType) {
3107 				if (objective->Counter == 0 && objective->Character->CanAppear()) {  // if is supposed to destroy a character, but it is nowhere to be found, fail the quest
3108 					return "The target no longer exists.";
3109 				}
3110 			} else if (objective->ObjectiveType == DestroyUniqueObjectiveType) {
3111 				if (objective->Counter == 0 && objective->Unique->CanDrop()) {  // if is supposed to destroy a unique, but it is nowhere to be found, fail the quest
3112 					return "The target no longer exists.";
3113 				}
3114 			}
3115 		} else if (objective->ObjectiveType == DestroyFactionObjectiveType) {
3116 			if (objective->Counter == 0) {  // if is supposed to destroy a faction, but it is nowhere to be found, fail the quest
3117 				CPlayer *faction_player = GetFactionPlayer(objective->Faction);
3118 				if (faction_player == nullptr || faction_player->GetUnitCount() == 0) {
3119 					return "The target no longer exists.";
3120 				}
3121 			}
3122 		}
3123 	}
3124 
3125 	return "";
3126 }
3127 
AddModifier(CUpgrade * modifier,int cycles)3128 void CPlayer::AddModifier(CUpgrade *modifier, int cycles)
3129 {
3130 	if (this->Allow.Upgrades[modifier->ID] == 'R') {
3131 		for (size_t i = 0; i < this->Modifiers.size(); ++i) { //if already has the modifier, make it have the greater duration of the new or old one
3132 			if (this->Modifiers[i].first == modifier) {
3133 				this->Modifiers[i].second = std::max(this->Modifiers[i].second, (int) (GameCycle + cycles));
3134 			}
3135 		}
3136 	} else {
3137 		this->Modifiers.push_back(std::pair<CUpgrade *, int>(modifier, GameCycle + cycles));
3138 		UpgradeAcquire(*this, modifier);
3139 	}
3140 
3141 }
3142 
RemoveModifier(CUpgrade * modifier)3143 void CPlayer::RemoveModifier(CUpgrade *modifier)
3144 {
3145 	if (this->Allow.Upgrades[modifier->ID] == 'R') {
3146 		UpgradeLost(*this, modifier->ID);
3147 		for (size_t i = 0; i < this->Modifiers.size(); ++i) { //if already has the modifier, make it have the greater duration of the new or old one
3148 			if (this->Modifiers[i].first == modifier) {
3149 				this->Modifiers.erase(std::remove(this->Modifiers.begin(), this->Modifiers.end(), this->Modifiers[i]), this->Modifiers.end());
3150 				break;
3151 			}
3152 		}
3153 	}
3154 
3155 }
3156 
AtPeace() const3157 bool CPlayer::AtPeace() const
3158 {
3159 	for (int i = 0; i < PlayerNumNeutral; ++i) {
3160 		if (this->IsEnemy(Players[i]) && this->HasContactWith(Players[i]) && Players[i].GetUnitCount() > 0) {
3161 			return false;
3162 		}
3163 	}
3164 
3165 	return true;
3166 }
3167 //Wyrmgus end
3168 
UnitBegin() const3169 std::vector<CUnit *>::const_iterator CPlayer::UnitBegin() const
3170 {
3171 	return Units.begin();
3172 }
3173 
UnitBegin()3174 std::vector<CUnit *>::iterator CPlayer::UnitBegin()
3175 {
3176 	return Units.begin();
3177 }
3178 
UnitEnd() const3179 std::vector<CUnit *>::const_iterator CPlayer::UnitEnd() const
3180 {
3181 	return Units.end();
3182 }
3183 
UnitEnd()3184 std::vector<CUnit *>::iterator CPlayer::UnitEnd()
3185 {
3186 	return Units.end();
3187 }
3188 
GetUnit(int index) const3189 CUnit &CPlayer::GetUnit(int index) const
3190 {
3191 	return *Units[index];
3192 }
3193 
GetUnitCount() const3194 int CPlayer::GetUnitCount() const
3195 {
3196 	return static_cast<int>(Units.size());
3197 }
3198 
3199 
3200 
3201 /*----------------------------------------------------------------------------
3202 --  Resource management
3203 ----------------------------------------------------------------------------*/
3204 
3205 /**
3206 **  Gets the player resource.
3207 **
3208 **  @param resource  Resource to get.
3209 **  @param type      Storing type
3210 **
3211 **  @note Storing types: 0 - overall store, 1 - store buildings, 2 - both
3212 */
GetResource(const int resource,const int type)3213 int CPlayer::GetResource(const int resource, const int type)
3214 {
3215 	switch (type) {
3216 		case STORE_OVERALL:
3217 			return this->Resources[resource];
3218 		case STORE_BUILDING:
3219 			return this->StoredResources[resource];
3220 		case STORE_BOTH:
3221 			return this->Resources[resource] + this->StoredResources[resource];
3222 		default:
3223 			DebugPrint("Wrong resource type\n");
3224 			return -1;
3225 	}
3226 }
3227 
3228 /**
3229 **  Adds/subtracts some resources to/from the player store
3230 **
3231 **  @param resource  Resource to add/subtract.
3232 **  @param value     How many of this resource (can be negative).
3233 **  @param store     If true, sets the building store resources, else the overall resources.
3234 */
ChangeResource(const int resource,const int value,const bool store)3235 void CPlayer::ChangeResource(const int resource, const int value, const bool store)
3236 {
3237 	if (value < 0) {
3238 		const int fromStore = std::min(this->StoredResources[resource], abs(value));
3239 		this->StoredResources[resource] -= fromStore;
3240 		this->Resources[resource] -= abs(value) - fromStore;
3241 		this->Resources[resource] = std::max(this->Resources[resource], 0);
3242 	} else {
3243 		if (store && this->MaxResources[resource] != -1) {
3244 			this->StoredResources[resource] += std::min(value, this->MaxResources[resource] - this->StoredResources[resource]);
3245 		} else {
3246 			this->Resources[resource] += value;
3247 		}
3248 	}
3249 }
3250 
3251 /**
3252 **  Change the player resource.
3253 **
3254 **  @param resource  Resource to change.
3255 **  @param value     How many of this resource.
3256 **  @param type      Resource types: 0 - overall store, 1 - store buildings, 2 - both
3257 */
SetResource(const int resource,const int value,const int type)3258 void CPlayer::SetResource(const int resource, const int value, const int type)
3259 {
3260 	if (type == STORE_BOTH) {
3261 		if (this->MaxResources[resource] != -1) {
3262 			const int toRes = std::max(0, value - this->StoredResources[resource]);
3263 			this->Resources[resource] = std::max(0, toRes);
3264 			this->StoredResources[resource] = std::min(value - toRes, this->MaxResources[resource]);
3265 		} else {
3266 			this->Resources[resource] = value;
3267 		}
3268 	} else if (type == STORE_BUILDING && this->MaxResources[resource] != -1) {
3269 		this->StoredResources[resource] = std::min(value, this->MaxResources[resource]);
3270 	} else if (type == STORE_OVERALL) {
3271 		this->Resources[resource] = value;
3272 	}
3273 }
3274 
3275 /**
3276 **  Check, if there enough resources for action.
3277 **
3278 **  @param resource  Resource to change.
3279 **  @param value     How many of this resource.
3280 */
CheckResource(const int resource,const int value)3281 bool CPlayer::CheckResource(const int resource, const int value)
3282 {
3283 	int result = this->Resources[resource];
3284 	if (this->MaxResources[resource] != -1) {
3285 		result += this->StoredResources[resource];
3286 	}
3287 	return result < value ? false : true;
3288 }
3289 
3290 //Wyrmgus start
3291 /**
3292 **  Increase resource price
3293 **
3294 **  @param resource  Resource.
3295 */
IncreaseResourcePrice(const int resource)3296 void CPlayer::IncreaseResourcePrice(const int resource)
3297 {
3298 	int price_change = CResource::Resources[resource]->BasePrice / std::max(this->Prices[resource], 100);
3299 	price_change = std::max(1, price_change);
3300 	this->Prices[resource] += price_change;
3301 }
3302 
3303 /**
3304 **  Decrease resource price
3305 **
3306 **  @param resource  Resource.
3307 */
DecreaseResourcePrice(const int resource)3308 void CPlayer::DecreaseResourcePrice(const int resource)
3309 {
3310 	int price_change = this->Prices[resource] / CResource::Resources[resource]->BasePrice;
3311 	price_change = std::max(1, price_change);
3312 	this->Prices[resource] -= price_change;
3313 	this->Prices[resource] = std::max(1, this->Prices[resource]);
3314 }
3315 
3316 /**
3317 **  Converges prices with another player (and returns how many convergences were effected)
3318 */
ConvergePricesWith(CPlayer & player,int max_convergences)3319 int CPlayer::ConvergePricesWith(CPlayer &player, int max_convergences)
3320 {
3321 	int convergences = 0;
3322 
3323 	bool converged = true;
3324 	while (converged) {
3325 		converged = false;
3326 
3327 		for (int i = 1; i < MaxCosts; ++i) {
3328 			if (!CResource::Resources[i]->BasePrice) {
3329 				continue;
3330 			}
3331 
3332 			int convergence_increase = 100;
3333 
3334 			if (this->Prices[i] < player.Prices[i] && convergences < max_convergences) {
3335 				this->IncreaseResourcePrice(i);
3336 				convergences += convergence_increase;
3337 				converged = true;
3338 
3339 				if (this->Prices[i] < player.Prices[i] && convergences < max_convergences) { //now do the convergence for the other side as well, if possible
3340 					player.DecreaseResourcePrice(i);
3341 					convergences += convergence_increase;
3342 					converged = true;
3343 				}
3344 			} else if (this->Prices[i] > player.Prices[i] && convergences < max_convergences) {
3345 				this->DecreaseResourcePrice(i);
3346 				convergences += convergence_increase;
3347 				converged = true;
3348 
3349 				if (this->Prices[i] > player.Prices[i] && convergences < max_convergences) { //do the convergence for the other side as well, if possible
3350 					player.IncreaseResourcePrice(i);
3351 					convergences += convergence_increase;
3352 					converged = true;
3353 				}
3354 			}
3355 		}
3356 	}
3357 
3358 	return convergences;
3359 }
3360 
3361 /**
3362 **  Get the price of a resource for the player
3363 **
3364 **  @param resource  Resource.
3365 */
GetResourcePrice(const int resource) const3366 int CPlayer::GetResourcePrice(const int resource) const
3367 {
3368 	if (resource == CopperCost) {
3369 		return 100;
3370 	}
3371 
3372 	return this->Prices[resource];
3373 }
3374 
3375 /**
3376 **  Get the effective resource demand for the player, given the current prices
3377 **
3378 **  @param resource  Resource.
3379 */
GetEffectiveResourceDemand(const int resource) const3380 int CPlayer::GetEffectiveResourceDemand(const int resource) const
3381 {
3382 	int resource_demand = this->ResourceDemand[resource];
3383 
3384 	if (this->Prices[resource]) {
3385 		resource_demand *= CResource::Resources[resource]->BasePrice;
3386 		resource_demand /= this->Prices[resource];
3387 	}
3388 
3389 	if (CResource::Resources[resource]->DemandElasticity != 100) {
3390 		resource_demand = this->ResourceDemand[resource] + ((resource_demand - this->ResourceDemand[resource]) * CResource::Resources[resource]->DemandElasticity / 100);
3391 	}
3392 
3393 	resource_demand = std::max(resource_demand, 0);
3394 
3395 	return resource_demand;
3396 }
3397 
3398 /**
3399 **  Get the effective sell price of a resource
3400 */
GetEffectiveResourceSellPrice(const int resource,int traded_quantity) const3401 int CPlayer::GetEffectiveResourceSellPrice(const int resource, int traded_quantity) const
3402 {
3403 	if (resource == CopperCost) {
3404 		return 100;
3405 	}
3406 
3407 	int price = traded_quantity * this->Prices[resource] / 100 * (100 - this->TradeCost) / 100;
3408 	price = std::max(1, price);
3409 	return price;
3410 }
3411 
3412 /**
3413 **  Get the effective buy quantity of a resource
3414 */
GetEffectiveResourceBuyPrice(const int resource,int traded_quantity) const3415 int CPlayer::GetEffectiveResourceBuyPrice(const int resource, int traded_quantity) const
3416 {
3417 	int price = traded_quantity * this->Prices[resource] / 100 * 100 / (100 - this->TradeCost);
3418 	price = std::max(1, price);
3419 	return price;
3420 }
3421 
3422 /**
3423 **  Get the total price difference between this player and another one
3424 */
GetTotalPriceDifferenceWith(const CPlayer & player) const3425 int CPlayer::GetTotalPriceDifferenceWith(const CPlayer &player) const
3426 {
3427 	int difference = 0;
3428 	for (int i = 1; i < MaxCosts; ++i) {
3429 		if (!CResource::Resources[i]->BasePrice) {
3430 			continue;
3431 		}
3432 		difference += abs(this->Prices[i] - player.Prices[i]);
3433 	}
3434 
3435 	return difference;
3436 }
3437 
3438 /**
3439 **  Get the trade potential between this player and another one
3440 */
GetTradePotentialWith(const CPlayer & player) const3441 int CPlayer::GetTradePotentialWith(const CPlayer &player) const
3442 {
3443 	int trade_potential = 0;
3444 	for (int i = 1; i < MaxCosts; ++i) {
3445 		if (!CResource::Resources[i]->BasePrice) {
3446 			continue;
3447 		}
3448 		int price_difference = abs(this->Prices[i] - player.Prices[i]);
3449 		trade_potential += price_difference * 100;
3450 	}
3451 
3452 	trade_potential = std::max(trade_potential, 10);
3453 
3454 	return trade_potential;
3455 }
3456 //Wyrmgus end
3457 
GetUnitTotalCount(const CUnitType & type) const3458 int CPlayer::GetUnitTotalCount(const CUnitType &type) const
3459 {
3460 	int count = this->GetUnitTypeCount(&type);
3461 	for (std::vector<CUnit *>::const_iterator it = this->UnitBegin(); it != this->UnitEnd(); ++it) {
3462 		//Wyrmgus start
3463 		if (*it == nullptr) {
3464 			fprintf(stderr, "Error in CPlayer::GetUnitTotalCount: unit of player %d is null.\n", this->Index);
3465 			continue;
3466 		}
3467 		//Wyrmgus end
3468 		CUnit &unit = **it;
3469 
3470 		if (unit.CurrentAction() == UnitActionUpgradeTo) {
3471 			COrder_UpgradeTo &order = dynamic_cast<COrder_UpgradeTo &>(*unit.CurrentOrder());
3472 			if (order.GetUnitType().Slot == type.Slot) {
3473 				++count;
3474 			}
3475 		}
3476 	}
3477 	return count;
3478 }
3479 
3480 /**
3481 **  Check if the unit-type didn't break any unit limits.
3482 **
3483 **  @param type    Type of unit.
3484 **
3485 **  @return        True if enough, negative on problem.
3486 **
3487 **  @note The return values of the PlayerCheck functions are inconsistent.
3488 */
CheckLimits(const CUnitType & type) const3489 int CPlayer::CheckLimits(const CUnitType &type) const
3490 {
3491 	//  Check game limits.
3492 	if (type.BoolFlag[BUILDING_INDEX].value && NumBuildings >= BuildingLimit) {
3493 		Notify("%s", _("Building Limit Reached"));
3494 		return -1;
3495 	}
3496 	if (!type.BoolFlag[BUILDING_INDEX].value && (this->GetUnitCount() - NumBuildings) >= UnitLimit) {
3497 		Notify("%s", _("Unit Limit Reached"));
3498 		return -2;
3499 	}
3500 	//Wyrmgus start
3501 //	if (this->Demand + type.Stats[this->Index].Variables[DEMAND_INDEX].Value > this->Supply && type.Stats[this->Index].Variables[DEMAND_INDEX].Value) {
3502 	if (this->Demand + (type.Stats[this->Index].Variables[DEMAND_INDEX].Value * (type.TrainQuantity ? type.TrainQuantity : 1)) > this->Supply && type.Stats[this->Index].Variables[DEMAND_INDEX].Value) {
3503 	//Wyrmgus end
3504 		//Wyrmgus start
3505 //		Notify("%s", _("Insufficient Supply, increase Supply."));
3506 		Notify("%s", _("Insufficient Food Supply, increase Food Supply."));
3507 		//Wyrmgus end
3508 		return -3;
3509 	}
3510 	if (this->GetUnitCount() >= TotalUnitLimit) {
3511 		Notify("%s", _("Total Unit Limit Reached"));
3512 		return -4;
3513 	}
3514 	if (GetUnitTotalCount(type) >= Allow.Units[type.Slot]) {
3515 		Notify(_("Limit of %d reached for this unit type"), Allow.Units[type.Slot]);
3516 		return -6;
3517 	}
3518 	return 1;
3519 }
3520 
3521 /**
3522 **  Check if enough resources for are available.
3523 **
3524 **  @param costs   How many costs.
3525 **
3526 **  @return        False if all enough, otherwise a bit mask.
3527 **
3528 **  @note The return values of the PlayerCheck functions are inconsistent.
3529 */
CheckCosts(const int * costs,bool notify) const3530 int CPlayer::CheckCosts(const int *costs, bool notify) const
3531 {
3532 	//Wyrmgus start
3533 	bool sound_played = false;
3534 	//Wyrmgus end
3535 	int err = 0;
3536 	for (int i = 1; i < MaxCosts; ++i) {
3537 		if (this->Resources[i] + this->StoredResources[i] >= costs[i]) {
3538 			continue;
3539 		}
3540 		if (notify) {
3541 			const char *name = DefaultResourceNames[i].c_str();
3542 			const char *actionName = CResource::Resources[i]->ActionName.c_str();
3543 
3544 			//Wyrmgus start
3545 //			Notify(_("Not enough %s...%s more %s."), _(name), _(actionName), _(name));
3546 			Notify(_("Not enough %s... %s more %s."), _(name), _(actionName), _(name)); //added extra space to look better
3547 			//Wyrmgus end
3548 
3549 			//Wyrmgus start
3550 //			if (this == ThisPlayer && GameSounds.NotEnoughRes[this->Race][i].Sound) {
3551 			if (this == ThisPlayer && GameSounds.NotEnoughRes[this->Race][i].Sound && !sound_played) {
3552 				sound_played = true;
3553 			//Wyrmgus end
3554 				PlayGameSound(GameSounds.NotEnoughRes[this->Race][i].Sound, MaxSampleVolume);
3555 			}
3556 		}
3557 		err |= 1 << i;
3558 	}
3559 	return err;
3560 }
3561 
3562 /**
3563 **  Check if enough resources for new unit is available.
3564 **
3565 **  @param type    Type of unit.
3566 **
3567 **  @return        False if all enough, otherwise a bit mask.
3568 */
3569 //Wyrmgus start
3570 //int CPlayer::CheckUnitType(const CUnitType &type) const
CheckUnitType(const CUnitType & type,bool hire) const3571 int CPlayer::CheckUnitType(const CUnitType &type, bool hire) const
3572 //Wyrmgus end
3573 {
3574 	//Wyrmgus start
3575 //	return this->CheckCosts(type.Stats[this->Index].Costs);
3576 	int type_costs[MaxCosts];
3577 	this->GetUnitTypeCosts(&type, type_costs, hire);
3578 	return this->CheckCosts(type_costs);
3579 	//Wyrmgus end
3580 }
3581 
3582 /**
3583 **  Add costs to the resources
3584 **
3585 **  @param costs   How many costs.
3586 */
AddCosts(const int * costs)3587 void CPlayer::AddCosts(const int *costs)
3588 {
3589 	for (int i = 1; i < MaxCosts; ++i) {
3590 		ChangeResource(i, costs[i], false);
3591 	}
3592 }
3593 
3594 /**
3595 **  Add the costs of an unit type to resources
3596 **
3597 **  @param type    Type of unit.
3598 */
3599 //Wyrmgus start
3600 //void CPlayer::AddUnitType(const CUnitType &type)
AddUnitType(const CUnitType & type,bool hire)3601 void CPlayer::AddUnitType(const CUnitType &type, bool hire)
3602 //Wyrmgus end
3603 {
3604 	//Wyrmgus start
3605 //	AddCosts(type.Stats[this->Index].Costs);
3606 	int type_costs[MaxCosts];
3607 	this->GetUnitTypeCosts(&type, type_costs, hire);
3608 	AddCostsFactor(type_costs, 100);
3609 	//Wyrmgus end
3610 }
3611 
3612 /**
3613 **  Add a factor of costs to the resources
3614 **
3615 **  @param costs   How many costs.
3616 **  @param factor  Factor of the costs to apply.
3617 */
AddCostsFactor(const int * costs,int factor)3618 void CPlayer::AddCostsFactor(const int *costs, int factor)
3619 {
3620 	if (!factor) {
3621 		return;
3622 	}
3623 
3624 	for (int i = 1; i < MaxCosts; ++i) {
3625 		ChangeResource(i, costs[i] * factor / 100, true);
3626 	}
3627 }
3628 
3629 /**
3630 **  Subtract costs from the resources
3631 **
3632 **  @param costs   How many costs.
3633 */
SubCosts(const int * costs)3634 void CPlayer::SubCosts(const int *costs)
3635 {
3636 	for (int i = 1; i < MaxCosts; ++i) {
3637 		ChangeResource(i, -costs[i], true);
3638 	}
3639 }
3640 
3641 /**
3642 **  Subtract the costs of new unit from resources
3643 **
3644 **  @param type    Type of unit.
3645 */
3646 //Wyrmgus start
3647 //void CPlayer::SubUnitType(const CUnitType &type)
SubUnitType(const CUnitType & type,bool hire)3648 void CPlayer::SubUnitType(const CUnitType &type, bool hire)
3649 //Wyrmgus end
3650 {
3651 	//Wyrmgus start
3652 //	this->SubCosts(type.Stats[this->Index].Costs);
3653 	int type_costs[MaxCosts];
3654 	this->GetUnitTypeCosts(&type, type_costs, hire);
3655 	this->SubCostsFactor(type_costs, 100);
3656 	//Wyrmgus end
3657 }
3658 
3659 /**
3660 **  Subtract a factor of costs from the resources
3661 **
3662 **  @param costs   How many costs.
3663 **  @param factor  Factor of the costs to apply.
3664 */
SubCostsFactor(const int * costs,int factor)3665 void CPlayer::SubCostsFactor(const int *costs, int factor)
3666 {
3667 	for (int i = 1; i < MaxCosts; ++i) {
3668 		ChangeResource(i, -costs[i] * 100 / factor);
3669 	}
3670 }
3671 
3672 //Wyrmgus start
3673 /**
3674 **  Gives the cost of a unit type for the player
3675 */
GetUnitTypeCosts(const CUnitType * type,int * type_costs,bool hire,bool ignore_one) const3676 void CPlayer::GetUnitTypeCosts(const CUnitType *type, int *type_costs, bool hire, bool ignore_one) const
3677 {
3678 	for (int i = 0; i < MaxCosts; ++i) {
3679 		type_costs[i] = 0;
3680 	}
3681 	if (hire) {
3682 		type_costs[CopperCost] = type->Stats[this->Index].GetPrice();
3683 	} else {
3684 		for (int i = 0; i < MaxCosts; ++i) {
3685 			type_costs[i] = type->Stats[this->Index].Costs[i];
3686 		}
3687 	}
3688 	for (int i = 0; i < MaxCosts; ++i) {
3689 		if (type->TrainQuantity) {
3690 			type_costs[i] *= type->TrainQuantity;
3691 		}
3692 		if (type->CostModifier) {
3693 			int type_count = this->GetUnitTypeCount(type) + this->GetUnitTypeUnderConstructionCount(type);
3694 			if (ignore_one) {
3695 				type_count--;
3696 			}
3697 			for (int j = 0; j < type_count; ++j) {
3698 				type_costs[i] *= 100 + type->CostModifier;
3699 				type_costs[i] /= 100;
3700 			}
3701 		}
3702 	}
3703 }
3704 
GetUnitTypeCostsMask(const CUnitType * type,bool hire) const3705 int CPlayer::GetUnitTypeCostsMask(const CUnitType *type, bool hire) const
3706 {
3707 	int costs_mask = 0;
3708 
3709 	int type_costs[MaxCosts];
3710 	AiPlayer->Player->GetUnitTypeCosts(type, type_costs, hire);
3711 
3712 	for (int i = 1; i < MaxCosts; ++i) {
3713 		if (type_costs[i] > 0) {
3714 			costs_mask |= 1 << i;
3715 		}
3716 	}
3717 
3718 	return costs_mask;
3719 }
3720 
3721 /**
3722 **  Gives the cost of an upgrade for the player
3723 */
GetUpgradeCosts(const CUpgrade * upgrade,int * upgrade_costs)3724 void CPlayer::GetUpgradeCosts(const CUpgrade *upgrade, int *upgrade_costs)
3725 {
3726 	for (int i = 0; i < MaxCosts; ++i) {
3727 		upgrade_costs[i] = upgrade->Costs[i];
3728 		for (size_t j = 0; j < upgrade->ScaledCostUnits.size(); ++j) {
3729 			upgrade_costs[i] += upgrade->ScaledCosts[i] * this->GetUnitTypeCount(upgrade->ScaledCostUnits[j]);
3730 		}
3731 	}
3732 }
3733 
GetUpgradeCostsMask(const CUpgrade * upgrade) const3734 int CPlayer::GetUpgradeCostsMask(const CUpgrade *upgrade) const
3735 {
3736 	int costs_mask = 0;
3737 
3738 	int upgrade_costs[MaxCosts];
3739 	AiPlayer->Player->GetUpgradeCosts(upgrade, upgrade_costs);
3740 
3741 	for (int i = 1; i < MaxCosts; ++i) {
3742 		if (upgrade_costs[i] > 0) {
3743 			costs_mask |= 1 << i;
3744 		}
3745 	}
3746 
3747 	return costs_mask;
3748 }
3749 
3750 //Wyrmgus end
3751 
SetUnitTypeCount(const CUnitType * type,int quantity)3752 void CPlayer::SetUnitTypeCount(const CUnitType *type, int quantity)
3753 {
3754 	if (!type) {
3755 		return;
3756 	}
3757 
3758 	if (quantity <= 0) {
3759 		if (this->UnitTypesCount.find(type) != this->UnitTypesCount.end()) {
3760 			this->UnitTypesCount.erase(type);
3761 		}
3762 	} else {
3763 		this->UnitTypesCount[type] = quantity;
3764 	}
3765 }
3766 
ChangeUnitTypeCount(const CUnitType * type,int quantity)3767 void CPlayer::ChangeUnitTypeCount(const CUnitType *type, int quantity)
3768 {
3769 	this->SetUnitTypeCount(type, this->GetUnitTypeCount(type) + quantity);
3770 }
3771 
GetUnitTypeCount(const CUnitType * type) const3772 int CPlayer::GetUnitTypeCount(const CUnitType *type) const
3773 {
3774 	if (type && this->UnitTypesCount.find(type) != this->UnitTypesCount.end()) {
3775 		return this->UnitTypesCount.find(type)->second;
3776 	} else {
3777 		return 0;
3778 	}
3779 }
3780 
SetUnitTypeUnderConstructionCount(const CUnitType * type,int quantity)3781 void CPlayer::SetUnitTypeUnderConstructionCount(const CUnitType *type, int quantity)
3782 {
3783 	if (!type) {
3784 		return;
3785 	}
3786 
3787 	if (quantity <= 0) {
3788 		if (this->UnitTypesUnderConstructionCount.find(type) != this->UnitTypesUnderConstructionCount.end()) {
3789 			this->UnitTypesUnderConstructionCount.erase(type);
3790 		}
3791 	} else {
3792 		this->UnitTypesUnderConstructionCount[type] = quantity;
3793 	}
3794 }
3795 
ChangeUnitTypeUnderConstructionCount(const CUnitType * type,int quantity)3796 void CPlayer::ChangeUnitTypeUnderConstructionCount(const CUnitType *type, int quantity)
3797 {
3798 	this->SetUnitTypeUnderConstructionCount(type, this->GetUnitTypeUnderConstructionCount(type) + quantity);
3799 }
3800 
GetUnitTypeUnderConstructionCount(const CUnitType * type) const3801 int CPlayer::GetUnitTypeUnderConstructionCount(const CUnitType *type) const
3802 {
3803 	if (type && this->UnitTypesUnderConstructionCount.find(type) != this->UnitTypesUnderConstructionCount.end()) {
3804 		return this->UnitTypesUnderConstructionCount.find(type)->second;
3805 	} else {
3806 		return 0;
3807 	}
3808 }
3809 
SetUnitTypeAiActiveCount(const CUnitType * type,int quantity)3810 void CPlayer::SetUnitTypeAiActiveCount(const CUnitType *type, int quantity)
3811 {
3812 	if (!type) {
3813 		return;
3814 	}
3815 
3816 	if (quantity <= 0) {
3817 		if (this->UnitTypesAiActiveCount.find(type) != this->UnitTypesAiActiveCount.end()) {
3818 			this->UnitTypesAiActiveCount.erase(type);
3819 		}
3820 	} else {
3821 		this->UnitTypesAiActiveCount[type] = quantity;
3822 	}
3823 }
3824 
ChangeUnitTypeAiActiveCount(const CUnitType * type,int quantity)3825 void CPlayer::ChangeUnitTypeAiActiveCount(const CUnitType *type, int quantity)
3826 {
3827 	this->SetUnitTypeAiActiveCount(type, this->GetUnitTypeAiActiveCount(type) + quantity);
3828 }
3829 
GetUnitTypeAiActiveCount(const CUnitType * type) const3830 int CPlayer::GetUnitTypeAiActiveCount(const CUnitType *type) const
3831 {
3832 	if (type && this->UnitTypesAiActiveCount.find(type) != this->UnitTypesAiActiveCount.end()) {
3833 		return this->UnitTypesAiActiveCount.find(type)->second;
3834 	} else {
3835 		return 0;
3836 	}
3837 }
3838 
IncreaseCountsForUnit(CUnit * unit,bool type_change)3839 void CPlayer::IncreaseCountsForUnit(CUnit *unit, bool type_change)
3840 {
3841 	const CUnitType *type = unit->Type;
3842 
3843 	this->ChangeUnitTypeCount(type, 1);
3844 	this->UnitsByType[type].push_back(unit);
3845 
3846 	if (unit->Active) {
3847 		this->ChangeUnitTypeAiActiveCount(type, 1);
3848 		this->AiActiveUnitsByType[type].push_back(unit);
3849 	}
3850 
3851 	if (type->BoolFlag[TOWNHALL_INDEX].value) {
3852 		this->NumTownHalls++;
3853 	}
3854 
3855 	for (int i = 0; i < MaxCosts; ++i) {
3856 		this->ResourceDemand[i] += type->Stats[this->Index].ResourceDemand[i];
3857 	}
3858 
3859 	if (this->AiEnabled && type->BoolFlag[COWARD_INDEX].value && !type->BoolFlag[HARVESTER_INDEX].value && !type->CanTransport() && type->Spells.size() == 0 && Map.Info.IsPointOnMap(unit->tilePos, unit->MapLayer) && unit->CanMove() && unit->Active && unit->GroupId != 0 && unit->Variable[SIGHTRANGE_INDEX].Value > 0) { //assign coward, non-worker, non-transporter, non-spellcaster units to be scouts
3860 		this->Ai->Scouts.push_back(unit);
3861 	}
3862 
3863 	if (!type_change) {
3864 		if (unit->Character != nullptr) {
3865 			this->Heroes.push_back(unit);
3866 		}
3867 	}
3868 }
3869 
DecreaseCountsForUnit(CUnit * unit,bool type_change)3870 void CPlayer::DecreaseCountsForUnit(CUnit *unit, bool type_change)
3871 {
3872 	const CUnitType *type = unit->Type;
3873 
3874 	this->ChangeUnitTypeCount(type, -1);
3875 
3876 	this->UnitsByType[type].erase(std::remove(this->UnitsByType[type].begin(), this->UnitsByType[type].end(), unit), this->UnitsByType[type].end());
3877 
3878 	if (this->UnitsByType[type].empty()) {
3879 		this->UnitsByType.erase(type);
3880 	}
3881 
3882 	if (unit->Active) {
3883 		this->ChangeUnitTypeAiActiveCount(type, -1);
3884 
3885 		this->AiActiveUnitsByType[type].erase(std::remove(this->AiActiveUnitsByType[type].begin(), this->AiActiveUnitsByType[type].end(), unit), this->AiActiveUnitsByType[type].end());
3886 
3887 		if (this->AiActiveUnitsByType[type].empty()) {
3888 			this->AiActiveUnitsByType.erase(type);
3889 		}
3890 	}
3891 
3892 	if (type->BoolFlag[TOWNHALL_INDEX].value) {
3893 		this->NumTownHalls--;
3894 	}
3895 
3896 	for (int i = 0; i < MaxCosts; ++i) {
3897 		this->ResourceDemand[i] -= type->Stats[this->Index].ResourceDemand[i];
3898 	}
3899 
3900 	if (this->AiEnabled && this->Ai && std::find(this->Ai->Scouts.begin(), this->Ai->Scouts.end(), unit) != this->Ai->Scouts.end()) {
3901 		this->Ai->Scouts.erase(std::remove(this->Ai->Scouts.begin(), this->Ai->Scouts.end(), unit), this->Ai->Scouts.end());
3902 	}
3903 
3904 	if (!type_change) {
3905 		if (unit->Character != nullptr) {
3906 			this->Heroes.erase(std::remove(this->Heroes.begin(), this->Heroes.end(), unit), this->Heroes.end());
3907 		}
3908 	}
3909 }
3910 
3911 /**
3912 **  Have unit of type.
3913 **
3914 **  @param type    Type of unit.
3915 **
3916 **  @return        How many exists, false otherwise.
3917 */
HaveUnitTypeByType(const CUnitType & type) const3918 int CPlayer::HaveUnitTypeByType(const CUnitType &type) const
3919 {
3920 	return this->GetUnitTypeCount(&type);
3921 }
3922 
3923 /**
3924 **  Have unit of type.
3925 **
3926 **  @param ident   Identifier of unit-type that should be lookuped.
3927 **
3928 **  @return        How many exists, false otherwise.
3929 **
3930 **  @note This function should not be used during run time.
3931 */
HaveUnitTypeByIdent(const std::string & ident) const3932 int CPlayer::HaveUnitTypeByIdent(const std::string &ident) const
3933 {
3934 	return this->GetUnitTypeCount(UnitTypeByIdent(ident));
3935 }
3936 
3937 /**
3938 **  Initialize the Ai for all players.
3939 */
PlayersInitAi()3940 void PlayersInitAi()
3941 {
3942 	for (int player = 0; player < NumPlayers; ++player) {
3943 		if (Players[player].AiEnabled) {
3944 			AiInit(Players[player]);
3945 		}
3946 	}
3947 }
3948 
3949 /**
3950 **  Handle AI of all players each game cycle.
3951 */
PlayersEachCycle()3952 void PlayersEachCycle()
3953 {
3954 	for (int player = 0; player < NumPlayers; ++player) {
3955 		CPlayer &p = Players[player];
3956 
3957 		//Wyrmgus start
3958 		if (p.LostTownHallTimer && !p.Revealed && p.LostTownHallTimer < ((int) GameCycle) && ThisPlayer->HasContactWith(p)) {
3959 			p.Revealed = true;
3960 			for (int j = 0; j < NumPlayers; ++j) {
3961 				if (player != j && Players[j].Type != PlayerNobody) {
3962 					Players[j].Notify(_("%s's units have been revealed!"), p.Name.c_str());
3963 				} else {
3964 					Players[j].Notify("%s", _("Your units have been revealed!"));
3965 				}
3966 			}
3967 		}
3968 
3969 
3970 		for (size_t i = 0; i < p.Modifiers.size(); ++i) { //if already has the modifier, make it have the greater duration of the new or old one
3971 			if ((unsigned long) p.Modifiers[i].second < GameCycle) {
3972 				p.RemoveModifier(p.Modifiers[i].first); //only remove one modifier per cycle, to prevent too many upgrade changes from happening at the same cycle (for performance reasons)
3973 				break;
3974 			}
3975 		}
3976 
3977 		if (p.HeroCooldownTimer) {
3978 			p.HeroCooldownTimer--;
3979 		}
3980 		//Wyrmgus end
3981 
3982 		if (p.AiEnabled) {
3983 			AiEachCycle(p);
3984 		}
3985 	}
3986 }
3987 
3988 /**
3989 **  Handle AI of a player each second.
3990 **
3991 **  @param playerIdx  the player to update AI
3992 */
PlayersEachSecond(int playerIdx)3993 void PlayersEachSecond(int playerIdx)
3994 {
3995 	CPlayer &player = Players[playerIdx];
3996 
3997 	if ((GameCycle / CYCLES_PER_SECOND) % 10 == 0) {
3998 		for (int res = 0; res < MaxCosts; ++res) {
3999 			player.Revenue[res] = player.Resources[res] + player.StoredResources[res] - player.LastResources[res];
4000 			player.Revenue[res] *= 6;  // estimate per minute
4001 			player.LastResources[res] = player.Resources[res] + player.StoredResources[res];
4002 		}
4003 	}
4004 	if (player.AiEnabled) {
4005 		AiEachSecond(player);
4006 	}
4007 
4008 	player.UpdateFreeWorkers();
4009 	//Wyrmgus start
4010 	player.PerformResourceTrade();
4011 	player.UpdateCurrentQuests();
4012 	//Wyrmgus end
4013 }
4014 
4015 /**
4016 **  Handle AI of a player each half minute.
4017 **
4018 **  @param playerIdx  the player to update AI
4019 */
PlayersEachHalfMinute(int playerIdx)4020 void PlayersEachHalfMinute(int playerIdx)
4021 {
4022 	CPlayer &player = Players[playerIdx];
4023 
4024 	if (player.AiEnabled) {
4025 		AiEachHalfMinute(player);
4026 	}
4027 
4028 	player.UpdateQuestPool(); // every half minute, update the quest pool
4029 }
4030 
4031 /**
4032 **  Handle AI of a player each minute.
4033 **
4034 **  @param playerIdx  the player to update AI
4035 */
PlayersEachMinute(int playerIdx)4036 void PlayersEachMinute(int playerIdx)
4037 {
4038 	CPlayer &player = Players[playerIdx];
4039 
4040 	if (player.AiEnabled) {
4041 		AiEachMinute(player);
4042 	}
4043 }
4044 
4045 /**
4046 **  Change current color set to new player.
4047 **
4048 **  FIXME: use function pointer here.
4049 **
4050 **  @param player  Pointer to player.
4051 **  @param sprite  The sprite in which the colors should be changed.
4052 */
4053 //Wyrmgus start
4054 //void GraphicPlayerPixels(CPlayer &player, const CGraphic &sprite)
GraphicPlayerPixels(int player,const CGraphic & sprite)4055 void GraphicPlayerPixels(int player, const CGraphic &sprite)
4056 //Wyrmgus end
4057 {
4058 	//Wyrmgus start
4059 	if (sprite.Grayscale) {
4060 		return;
4061 	}
4062 	//Wyrmgus end
4063 
4064 	Assert(PlayerColorIndexCount);
4065 
4066 	SDL_LockSurface(sprite.Surface);
4067 	//Wyrmgus start
4068 //	std::vector<SDL_Color> sdlColors(player.UnitColors.Colors.begin(), player.UnitColors.Colors.end());
4069 	std::vector<SDL_Color> sdlColors(PlayerColorsRGB[player].begin(), PlayerColorsRGB[player].end());
4070 
4071 	//convert colors according to time of day
4072 	int time_of_day_red = 0;
4073 	int time_of_day_green = 0;
4074 	int time_of_day_blue = 0;
4075 
4076 	if (sprite.TimeOfDay) {
4077 		if (sprite.TimeOfDay->Dawn) {
4078 			time_of_day_red = -20;
4079 			time_of_day_green = -20;
4080 			time_of_day_blue = 0;
4081 		} else if (sprite.TimeOfDay->Day) {
4082 			time_of_day_red = 0;
4083 			time_of_day_green = 0;
4084 			time_of_day_blue = 0;
4085 		} else if (sprite.TimeOfDay->Dusk) {
4086 			time_of_day_red = 0;
4087 			time_of_day_green = -20;
4088 			time_of_day_blue = -20;
4089 		} else if (sprite.TimeOfDay->Night) {
4090 			time_of_day_red = -45;
4091 			time_of_day_green = -35;
4092 			time_of_day_blue = -10;
4093 		}
4094 	}
4095 
4096 	if (sprite.TimeOfDay && (time_of_day_red != 0 || time_of_day_green != 0 || time_of_day_blue != 0)) {
4097 		for (int i = 0; i < PlayerColorIndexCount; ++i) {
4098 			sdlColors[i].r = std::max<int>(0,std::min<int>(255,int(sdlColors[i].r) + time_of_day_red));
4099 			sdlColors[i].g = std::max<int>(0,std::min<int>(255,int(sdlColors[i].g) + time_of_day_green));
4100 			sdlColors[i].b = std::max<int>(0,std::min<int>(255,int(sdlColors[i].b) + time_of_day_blue));
4101 		}
4102 	}
4103 	//Wyrmgus end
4104 	SDL_SetColors(sprite.Surface, &sdlColors[0], PlayerColorIndexStart, PlayerColorIndexCount);
4105 	if (sprite.SurfaceFlip) {
4106 		SDL_SetColors(sprite.SurfaceFlip, &sdlColors[0], PlayerColorIndexStart, PlayerColorIndexCount);
4107 	}
4108 	SDL_UnlockSurface(sprite.Surface);
4109 }
4110 
4111 /**
4112 **  Setup the player colors for the current palette.
4113 **
4114 **  @todo  FIXME: could be called before PixelsXX is setup.
4115 */
SetPlayersPalette()4116 void SetPlayersPalette()
4117 {
4118 	for (int i = 0; i < PlayerMax; ++i) {
4119 		//Wyrmgus start
4120 //		Players[i].UnitColors.Colors = PlayerColorsRGB[i];
4121 		if (Players[i].Faction == -1) {
4122 			Players[i].UnitColors.Colors = PlayerColorsRGB[i];
4123 		}
4124 		//Wyrmgus end
4125 	}
4126 }
4127 
4128 /**
4129 **  Output debug information for players.
4130 */
DebugPlayers()4131 void DebugPlayers()
4132 {
4133 #ifdef DEBUG
4134 	DebugPrint("Nr   Color   I Name     Type         Race    Ai\n");
4135 	DebugPrint("--  -------- - -------- ------------ ------- -----\n");
4136 	for (int i = 0; i < PlayerMax; ++i) {
4137 		if (Players[i].Type == PlayerNobody) {
4138 			continue;
4139 		}
4140 		const char *playertype;
4141 
4142 		switch (Players[i].Type) {
4143 			case 0: playertype = "Don't know 0"; break;
4144 			case 1: playertype = "Don't know 1"; break;
4145 			case 2: playertype = "neutral     "; break;
4146 			case 3: playertype = "nobody      "; break;
4147 			case 4: playertype = "computer    "; break;
4148 			case 5: playertype = "person      "; break;
4149 			case 6: playertype = "rescue pas. "; break;
4150 			case 7: playertype = "rescue akt. "; break;
4151 			default : playertype = "?unknown?   "; break;
4152 		}
4153 		DebugPrint("%2d: %8.8s %c %-8.8s %s %7s %s\n" _C_ i _C_ PlayerColorNames[i].c_str() _C_
4154 				   ThisPlayer == &Players[i] ? '*' :
4155 				   Players[i].AiEnabled ? '+' : ' ' _C_
4156 				   Players[i].Name.c_str() _C_ playertype _C_
4157 				   PlayerRaces.Name[Players[i].Race].c_str() _C_
4158 				   Players[i].AiName.c_str());
4159 	}
4160 #endif
4161 }
4162 
4163 /**
4164 **  Notify player about a problem.
4165 **
4166 **  @param type    Problem type
4167 **  @param pos     Map tile position
4168 **  @param fmt     Message format
4169 **  @param ...     Message varargs
4170 **
4171 **  @todo FIXME: We must also notfiy allied players.
4172 */
Notify(int type,const Vec2i & pos,int z,const char * fmt,...) const4173 void CPlayer::Notify(int type, const Vec2i &pos, int z, const char *fmt, ...) const
4174 {
4175 	Assert(Map.Info.IsPointOnMap(pos, z));
4176 	char temp[128];
4177 	Uint32 color;
4178 	va_list va;
4179 
4180 	// Notify me, and my TEAM members
4181 	if (this != ThisPlayer && !IsTeamed(*ThisPlayer)) {
4182 		return;
4183 	}
4184 
4185 	va_start(va, fmt);
4186 	temp[sizeof(temp) - 1] = '\0';
4187 	vsnprintf(temp, sizeof(temp) - 1, fmt, va);
4188 	va_end(va);
4189 	switch (type) {
4190 		case NotifyRed:
4191 			color = ColorRed;
4192 			break;
4193 		case NotifyYellow:
4194 			color = ColorYellow;
4195 			break;
4196 		case NotifyGreen:
4197 			color = ColorGreen;
4198 			break;
4199 		default: color = ColorWhite;
4200 	}
4201 	//Wyrmgus start
4202 //	UI.Minimap.AddEvent(pos, color);
4203 	UI.Minimap.AddEvent(pos, z, color);
4204 	//Wyrmgus end
4205 	if (this == ThisPlayer) {
4206 		//Wyrmgus start
4207 //		SetMessageEvent(pos, "%s", temp);
4208 		SetMessageEvent(pos, z, "%s", temp);
4209 		//Wyrmgus end
4210 	} else {
4211 		//Wyrmgus start
4212 //		SetMessageEvent(pos, "(%s): %s", Name.c_str(), temp);
4213 		SetMessageEvent(pos, z, "(%s): %s", Name.c_str(), temp);
4214 		//Wyrmgus end
4215 	}
4216 }
4217 
4218 /**
4219 **  Notify player about a problem.
4220 **
4221 **  @param type    Problem type
4222 **  @param pos     Map tile position
4223 **  @param fmt     Message format
4224 **  @param ...     Message varargs
4225 **
4226 **  @todo FIXME: We must also notfiy allied players.
4227 */
Notify(const char * fmt,...) const4228 void CPlayer::Notify(const char *fmt, ...) const
4229 {
4230 	// Notify me, and my TEAM members
4231 	if (this != ThisPlayer && !IsTeamed(*ThisPlayer)) {
4232 		return;
4233 	}
4234 	char temp[128];
4235 	va_list va;
4236 
4237 	va_start(va, fmt);
4238 	temp[sizeof(temp) - 1] = '\0';
4239 	vsnprintf(temp, sizeof(temp) - 1, fmt, va);
4240 	va_end(va);
4241 	if (this == ThisPlayer) {
4242 		SetMessage("%s", temp);
4243 	} else {
4244 		SetMessage("(%s): %s", Name.c_str(), temp);
4245 	}
4246 }
4247 
SetDiplomacyNeutralWith(const CPlayer & player)4248 void CPlayer::SetDiplomacyNeutralWith(const CPlayer &player)
4249 {
4250 	this->Enemy &= ~(1 << player.Index);
4251 	this->Allied &= ~(1 << player.Index);
4252 
4253 	//Wyrmgus start
4254 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4255 		ThisPlayer->Notify(_("%s changed their diplomatic stance with us to Neutral"), _(this->Name.c_str()));
4256 	}
4257 	//Wyrmgus end
4258 }
4259 
SetDiplomacyAlliedWith(const CPlayer & player)4260 void CPlayer::SetDiplomacyAlliedWith(const CPlayer &player)
4261 {
4262 	this->Enemy &= ~(1 << player.Index);
4263 	this->Allied |= 1 << player.Index;
4264 
4265 	//Wyrmgus start
4266 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4267 		ThisPlayer->Notify(_("%s changed their diplomatic stance with us to Ally"), _(this->Name.c_str()));
4268 	}
4269 	//Wyrmgus end
4270 }
4271 
4272 //Wyrmgus start
4273 //void CPlayer::SetDiplomacyEnemyWith(const CPlayer &player)
SetDiplomacyEnemyWith(CPlayer & player)4274 void CPlayer::SetDiplomacyEnemyWith(CPlayer &player)
4275 //Wyrmgus end
4276 {
4277 	this->Enemy |= 1 << player.Index;
4278 	this->Allied &= ~(1 << player.Index);
4279 
4280 	//Wyrmgus start
4281 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4282 		ThisPlayer->Notify(_("%s changed their diplomatic stance with us to Enemy"), _(this->Name.c_str()));
4283 	}
4284 
4285 	// if either player is the overlord of another (indirect or otherwise), break the vassalage bond after the declaration of war
4286 	if (this->IsOverlordOf(player, true)) {
4287 		player.SetOverlord(nullptr);
4288 	} else if (player.IsOverlordOf(*this, true)) {
4289 		this->SetOverlord(nullptr);
4290 	}
4291 	//Wyrmgus end
4292 }
4293 
SetDiplomacyCrazyWith(const CPlayer & player)4294 void CPlayer::SetDiplomacyCrazyWith(const CPlayer &player)
4295 {
4296 	this->Enemy |= 1 << player.Index;
4297 	this->Allied |= 1 << player.Index;
4298 
4299 	//Wyrmgus start
4300 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4301 		ThisPlayer->Notify(_("%s changed their diplomatic stance with us to Crazy"), _(this->Name.c_str()));
4302 	}
4303 	//Wyrmgus end
4304 }
4305 
ShareVisionWith(const CPlayer & player)4306 void CPlayer::ShareVisionWith(const CPlayer &player)
4307 {
4308 	this->SharedVision |= (1 << player.Index);
4309 
4310 	//Wyrmgus start
4311 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4312 		ThisPlayer->Notify(_("%s is now sharing vision with us"), _(this->Name.c_str()));
4313 	}
4314 	//Wyrmgus end
4315 }
4316 
UnshareVisionWith(const CPlayer & player)4317 void CPlayer::UnshareVisionWith(const CPlayer &player)
4318 {
4319 	this->SharedVision &= ~(1 << player.Index);
4320 
4321 	//Wyrmgus start
4322 	if (GameCycle > 0 && player.Index == ThisPlayer->Index) {
4323 		ThisPlayer->Notify(_("%s is no longer sharing vision with us"), _(this->Name.c_str()));
4324 	}
4325 	//Wyrmgus end
4326 }
4327 
4328 //Wyrmgus start
SetOverlord(CPlayer * player)4329 void CPlayer::SetOverlord(CPlayer *player)
4330 {
4331 	if (this->Overlord) {
4332 		this->Overlord->Vassals.erase(std::remove(this->Overlord->Vassals.begin(), this->Overlord->Vassals.end(), this), this->Overlord->Vassals.end());
4333 	}
4334 
4335 	this->Overlord = player;
4336 
4337 	if (this->Overlord) {
4338 		this->Overlord->Vassals.push_back(this);
4339 		if (!SaveGameLoading) {
4340 			this->SetDiplomacyAlliedWith(*this->Overlord);
4341 			this->Overlord->SetDiplomacyAlliedWith(*this);
4342 			CommandDiplomacy(this->Index, DiplomacyAllied, this->Overlord->Index);
4343 			CommandDiplomacy(this->Overlord->Index, DiplomacyAllied, this->Index);
4344 			CommandSharedVision(this->Index, true, this->Overlord->Index);
4345 			CommandSharedVision(this->Overlord->Index, true, this->Index);
4346 		}
4347 	}
4348 }
4349 //Wyrmgus end
4350 
4351 /**
4352 **  Check if the player is an enemy
4353 */
IsEnemy(const CPlayer & player) const4354 bool CPlayer::IsEnemy(const CPlayer &player) const
4355 {
4356 	//Wyrmgus start
4357 //	return IsEnemy(player.Index);
4358 	return IsEnemy(player.Index) || player.IsEnemy(this->Index); // be hostile to the other player if they are hostile, even if the diplomatic stance hasn't been changed
4359 	//Wyrmgus end
4360 }
4361 
4362 /**
4363 **  Check if the unit is an enemy
4364 */
IsEnemy(const CUnit & unit) const4365 bool CPlayer::IsEnemy(const CUnit &unit) const
4366 {
4367 	//Wyrmgus start
4368 	if (
4369 		unit.Player->Type == PlayerNeutral
4370 		&& unit.Type->BoolFlag[PREDATOR_INDEX].value
4371 		&& this->Type != PlayerNeutral
4372 	) {
4373 		return true;
4374 	}
4375 
4376 	if (
4377 		this != unit.Player
4378 		&& this->Type != PlayerNeutral
4379 		&& unit.CurrentAction() == UnitActionAttack
4380 		&& unit.CurrentOrder()->HasGoal()
4381 		&& unit.CurrentOrder()->GetGoal()->Player == this
4382 		&& !unit.CurrentOrder()->GetGoal()->Type->BoolFlag[HIDDENOWNERSHIP_INDEX].value
4383 	) {
4384 		return true;
4385 	}
4386 
4387 	if (unit.Player->Index != this->Index && this->Type != PlayerNeutral && unit.Type->BoolFlag[HIDDENOWNERSHIP_INDEX].value && unit.IsAgressive() && !this->HasNeutralFactionType()) {
4388 		return true;
4389 	}
4390 	//Wyrmgus end
4391 
4392 	return IsEnemy(*unit.Player);
4393 }
4394 
4395 /**
4396 **  Check if the player is an ally
4397 */
IsAllied(const CPlayer & player) const4398 bool CPlayer::IsAllied(const CPlayer &player) const
4399 {
4400 	return (Allied & (1 << player.Index)) != 0;
4401 }
4402 
4403 /**
4404 **  Check if the unit is an ally
4405 */
IsAllied(const CUnit & unit) const4406 bool CPlayer::IsAllied(const CUnit &unit) const
4407 {
4408 	return IsAllied(*unit.Player);
4409 }
4410 
4411 
IsVisionSharing() const4412 bool CPlayer::IsVisionSharing() const
4413 {
4414 	return SharedVision != 0;
4415 }
4416 
4417 /**
4418 **  Check if the player shares vision with the player
4419 */
IsSharedVision(const CPlayer & player) const4420 bool CPlayer::IsSharedVision(const CPlayer &player) const
4421 {
4422 	return (SharedVision & (1 << player.Index)) != 0;
4423 }
4424 
4425 /**
4426 **  Check if the player shares vision with the unit
4427 */
IsSharedVision(const CUnit & unit) const4428 bool CPlayer::IsSharedVision(const CUnit &unit) const
4429 {
4430 	return IsSharedVision(*unit.Player);
4431 }
4432 
4433 /**
4434 **  Check if the both players share vision
4435 */
IsBothSharedVision(const CPlayer & player) const4436 bool CPlayer::IsBothSharedVision(const CPlayer &player) const
4437 {
4438 	return (SharedVision & (1 << player.Index)) != 0
4439 		   && (player.SharedVision & (1 << Index)) != 0;
4440 }
4441 
4442 /**
4443 **  Check if the player and the unit share vision
4444 */
IsBothSharedVision(const CUnit & unit) const4445 bool CPlayer::IsBothSharedVision(const CUnit &unit) const
4446 {
4447 	return IsBothSharedVision(*unit.Player);
4448 }
4449 
4450 /**
4451 **  Check if the player is teamed
4452 */
IsTeamed(const CPlayer & player) const4453 bool CPlayer::IsTeamed(const CPlayer &player) const
4454 {
4455 	return Team == player.Team;
4456 }
4457 
4458 /**
4459 **  Check if the unit is teamed
4460 */
IsTeamed(const CUnit & unit) const4461 bool CPlayer::IsTeamed(const CUnit &unit) const
4462 {
4463 	return IsTeamed(*unit.Player);
4464 }
4465 
4466 //Wyrmgus start
4467 /**
4468 **  Check if the player is the overlord of another
4469 */
IsOverlordOf(const CPlayer & player,bool include_indirect) const4470 bool CPlayer::IsOverlordOf(const CPlayer &player, bool include_indirect) const
4471 {
4472 	if (!player.Overlord) {
4473 		return false;
4474 	}
4475 
4476 	if (this == player.Overlord) {
4477 		return true;
4478 	}
4479 
4480 	if (include_indirect) { //if include_indirect is true, search this player's other vassals to see if the player is an indirect overlord of the other
4481 		for (size_t i = 0; i < this->Vassals.size(); ++i) {
4482 			if (this->Vassals[i]->IsOverlordOf(player, include_indirect)) {
4483 				return true;
4484 			}
4485 		}
4486 	}
4487 
4488 	return false;
4489 }
4490 
4491 /**
4492 **  Check if the player is the vassal of another
4493 */
IsVassalOf(const CPlayer & player,bool include_indirect) const4494 bool CPlayer::IsVassalOf(const CPlayer &player, bool include_indirect) const
4495 {
4496 	if (!this->Overlord) {
4497 		return false;
4498 	}
4499 
4500 	if (this->Overlord == &player) {
4501 		return true;
4502 	}
4503 
4504 	if (include_indirect) { //if include_indirect is true, search this player's other vassals to see if the player is an indirect overlord of the other
4505 		if (this->Overlord->IsVassalOf(player, include_indirect)) {
4506 			return true;
4507 		}
4508 	}
4509 
4510 	return false;
4511 }
4512 
4513 /**
4514 **  Check if the player has contact with another (used for determining which players show up in the player list and etc.)
4515 */
HasContactWith(const CPlayer & player) const4516 bool CPlayer::HasContactWith(const CPlayer &player) const
4517 {
4518 	return player.StartMapLayer == this->StartMapLayer || (player.StartMapLayer < (int) Map.MapLayers.size() && this->StartMapLayer < (int) Map.MapLayers.size() && Map.MapLayers[player.StartMapLayer]->World == Map.MapLayers[this->StartMapLayer]->World && Map.MapLayers[player.StartMapLayer]->Plane == Map.MapLayers[this->StartMapLayer]->Plane);
4519 }
4520 
4521 /**
4522 **  Check if the player's faction type is a neutral one
4523 */
HasNeutralFactionType() const4524 bool CPlayer::HasNeutralFactionType() const
4525 {
4526 	if (
4527 		this->Race != -1
4528 		&& this->Faction != -1
4529 		&& (PlayerRaces.Factions[this->Faction]->Type == FactionTypeMercenaryCompany || PlayerRaces.Factions[this->Faction]->Type == FactionTypeHolyOrder || PlayerRaces.Factions[this->Faction]->Type == FactionTypeTradingCompany)
4530 	) {
4531 		return true;
4532 	}
4533 
4534 	return false;
4535 }
4536 
4537 /**
4538 **  Check if the player can use the buildings of another, for neutral building functions (i.e. unit training)
4539 */
HasBuildingAccess(const CPlayer & player,int button_action) const4540 bool CPlayer::HasBuildingAccess(const CPlayer &player, int button_action) const
4541 {
4542 	if (player.IsEnemy(*this)) {
4543 		return false;
4544 	}
4545 
4546 	if (player.Type == PlayerNeutral) {
4547 		return true;
4548 	}
4549 
4550 	if (
4551 		player.HasNeutralFactionType()
4552 		&& (player.Overlord == nullptr || this->IsOverlordOf(player, true) || player.Overlord->IsAllied(*this))
4553 	) {
4554 		if (PlayerRaces.Factions[player.Faction]->Type != FactionTypeHolyOrder || (button_action != ButtonTrain && button_action != ButtonBuy) || std::find(this->Deities.begin(), this->Deities.end(), PlayerRaces.Factions[player.Faction]->HolyOrderDeity) != this->Deities.end()) { //if the faction is a holy order, the player must have chosen its respective deity
4555 			return true;
4556 		}
4557 	}
4558 
4559 	return false;
4560 }
4561 
HasHero(const CCharacter * hero) const4562 bool CPlayer::HasHero(const CCharacter *hero) const
4563 {
4564 	if (!hero) {
4565 		return false;
4566 	}
4567 
4568 	for (const CUnit *hero_unit : this->Heroes) {
4569 		if (hero_unit->Character == hero) {
4570 			return true;
4571 		}
4572 	}
4573 
4574 	return false;
4575 }
4576 
SetFactionStringToIndex(const std::string & faction_name,int faction_id)4577 void SetFactionStringToIndex(const std::string &faction_name, int faction_id)
4578 {
4579 	FactionStringToIndex[faction_name] = faction_id;
4580 }
4581 
NetworkSetFaction(int player,const std::string & faction_name)4582 void NetworkSetFaction(int player, const std::string &faction_name)
4583 {
4584 	int faction = PlayerRaces.GetFactionIndexByName(faction_name);
4585 	SendCommandSetFaction(player, faction);
4586 }
4587 
GetPlayerColorIndexByName(const std::string & player_color_name)4588 int GetPlayerColorIndexByName(const std::string &player_color_name)
4589 {
4590 	for (int c = 0; c < PlayerColorMax; ++c) {
4591 		if (PlayerColorNames[c] == player_color_name) {
4592 			return c;
4593 		}
4594 	}
4595 	return -1;
4596 }
4597 
GetFactionTypeNameById(int faction_type)4598 std::string GetFactionTypeNameById(int faction_type)
4599 {
4600 	if (faction_type == FactionTypeNoFactionType) {
4601 		return "no-faction-type";
4602 	} else if (faction_type == FactionTypeTribe) {
4603 		return "tribe";
4604 	} else if (faction_type == FactionTypePolity) {
4605 		return "polity";
4606 	} else if (faction_type == FactionTypeMercenaryCompany) {
4607 		return "mercenary-company";
4608 	} else if (faction_type == FactionTypeHolyOrder) {
4609 		return "holy-order";
4610 	} else if (faction_type == FactionTypeTradingCompany) {
4611 		return "trading-company";
4612 	}
4613 
4614 	return "";
4615 }
4616 
GetFactionTypeIdByName(const std::string & faction_type)4617 int GetFactionTypeIdByName(const std::string &faction_type)
4618 {
4619 	if (faction_type == "no-faction-type") {
4620 		return FactionTypeNoFactionType;
4621 	} else if (faction_type == "tribe") {
4622 		return FactionTypeTribe;
4623 	} else if (faction_type == "polity") {
4624 		return FactionTypePolity;
4625 	} else if (faction_type == "mercenary-company") {
4626 		return FactionTypeMercenaryCompany;
4627 	} else if (faction_type == "holy-order") {
4628 		return FactionTypeHolyOrder;
4629 	} else if (faction_type == "trading-company") {
4630 		return FactionTypeTradingCompany;
4631 	}
4632 
4633 	return -1;
4634 }
4635 
GetGovernmentTypeNameById(int government_type)4636 std::string GetGovernmentTypeNameById(int government_type)
4637 {
4638 	if (government_type == GovernmentTypeNoGovernmentType) {
4639 		return "no-government-type";
4640 	} else if (government_type == GovernmentTypeMonarchy) {
4641 		return "monarchy";
4642 	} else if (government_type == GovernmentTypeRepublic) {
4643 		return "republic";
4644 	} else if (government_type == GovernmentTypeTheocracy) {
4645 		return "theocracy";
4646 	}
4647 
4648 	return "";
4649 }
4650 
GetGovernmentTypeIdByName(const std::string & government_type)4651 int GetGovernmentTypeIdByName(const std::string &government_type)
4652 {
4653 	if (government_type == "no-government-type") {
4654 		return GovernmentTypeNoGovernmentType;
4655 	} else if (government_type == "monarchy") {
4656 		return GovernmentTypeMonarchy;
4657 	} else if (government_type == "republic") {
4658 		return GovernmentTypeRepublic;
4659 	} else if (government_type == "theocracy") {
4660 		return GovernmentTypeTheocracy;
4661 	}
4662 
4663 	return -1;
4664 }
4665 
GetForceTypeNameById(int force_type)4666 std::string GetForceTypeNameById(int force_type)
4667 {
4668 	if (force_type == LandForceType) {
4669 		return "land-force";
4670 	} else if (force_type == NavalForceType) {
4671 		return "naval-force";
4672 	} else if (force_type == AirForceType) {
4673 		return "air-force";
4674 	}
4675 
4676 	return "";
4677 }
4678 
GetForceTypeIdByName(const std::string & force_type)4679 int GetForceTypeIdByName(const std::string &force_type)
4680 {
4681 	if (force_type == "land-force") {
4682 		return LandForceType;
4683 	} else if (force_type == "naval-force") {
4684 		return NavalForceType;
4685 	} else if (force_type == "air-force") {
4686 		return AirForceType;
4687 	}
4688 
4689 	return -1;
4690 }
4691 
GetWordTypeNameById(int word_type)4692 std::string GetWordTypeNameById(int word_type)
4693 {
4694 	if (word_type == WordTypeNoun) {
4695 		return "noun";
4696 	} else if (word_type == WordTypeVerb) {
4697 		return "verb";
4698 	} else if (word_type == WordTypeAdjective) {
4699 		return "adjective";
4700 	} else if (word_type == WordTypePronoun) {
4701 		return "pronoun";
4702 	} else if (word_type == WordTypeAdverb) {
4703 		return "adverb";
4704 	} else if (word_type == WordTypeConjunction) {
4705 		return "conjunction";
4706 	} else if (word_type == WordTypeAdposition) {
4707 		return "adposition";
4708 	} else if (word_type == WordTypeArticle) {
4709 		return "article";
4710 	} else if (word_type == WordTypeNumeral) {
4711 		return "numeral";
4712 	} else if (word_type == WordTypeAffix) {
4713 		return "affix";
4714 	}
4715 
4716 	return "";
4717 }
4718 
GetWordTypeIdByName(const std::string & word_type)4719 int GetWordTypeIdByName(const std::string &word_type)
4720 {
4721 	if (word_type == "noun") {
4722 		return WordTypeNoun;
4723 	} else if (word_type == "verb") {
4724 		return WordTypeVerb;
4725 	} else if (word_type == "adjective") {
4726 		return WordTypeAdjective;
4727 	} else if (word_type == "pronoun") {
4728 		return WordTypePronoun;
4729 	} else if (word_type == "adverb") {
4730 		return WordTypeAdverb;
4731 	} else if (word_type == "conjunction") {
4732 		return WordTypeConjunction;
4733 	} else if (word_type == "adposition") {
4734 		return WordTypeAdposition;
4735 	} else if (word_type == "article") {
4736 		return WordTypeArticle;
4737 	} else if (word_type == "numeral") {
4738 		return WordTypeNumeral;
4739 	} else if (word_type == "affix") {
4740 		return WordTypeAffix;
4741 	}
4742 
4743 	return -1;
4744 }
4745 
GetArticleTypeNameById(int article_type)4746 std::string GetArticleTypeNameById(int article_type)
4747 {
4748 	if (article_type == ArticleTypeNoArticle) {
4749 		return "no-article";
4750 	} else if (article_type == ArticleTypeDefinite) {
4751 		return "definite";
4752 	} else if (article_type == ArticleTypeIndefinite) {
4753 		return "indefinite";
4754 	}
4755 
4756 	return "";
4757 }
4758 
GetArticleTypeIdByName(const std::string & article_type)4759 int GetArticleTypeIdByName(const std::string &article_type)
4760 {
4761 	if (article_type == "no-article") {
4762 		return ArticleTypeNoArticle;
4763 	} else if (article_type == "definite") {
4764 		return ArticleTypeDefinite;
4765 	} else if (article_type == "indefinite") {
4766 		return ArticleTypeIndefinite;
4767 	}
4768 
4769 	return -1;
4770 }
4771 
GetGrammaticalCaseNameById(int grammatical_case)4772 std::string GetGrammaticalCaseNameById(int grammatical_case)
4773 {
4774 	if (grammatical_case == GrammaticalCaseNoCase) {
4775 		return "no-case";
4776 	} else if (grammatical_case == GrammaticalCaseNominative) {
4777 		return "nominative";
4778 	} else if (grammatical_case == GrammaticalCaseAccusative) {
4779 		return "accusative";
4780 	} else if (grammatical_case == GrammaticalCaseDative) {
4781 		return "dative";
4782 	} else if (grammatical_case == GrammaticalCaseGenitive) {
4783 		return "genitive";
4784 	}
4785 
4786 	return "";
4787 }
4788 
GetGrammaticalCaseIdByName(const std::string & grammatical_case)4789 int GetGrammaticalCaseIdByName(const std::string &grammatical_case)
4790 {
4791 	if (grammatical_case == "no-case") {
4792 		return GrammaticalCaseNoCase;
4793 	} else if (grammatical_case == "nominative") {
4794 		return GrammaticalCaseNominative;
4795 	} else if (grammatical_case == "accusative") {
4796 		return GrammaticalCaseAccusative;
4797 	} else if (grammatical_case == "dative") {
4798 		return GrammaticalCaseDative;
4799 	} else if (grammatical_case == "genitive") {
4800 		return GrammaticalCaseGenitive;
4801 	}
4802 
4803 	return -1;
4804 }
4805 
GetGrammaticalNumberNameById(int grammatical_number)4806 std::string GetGrammaticalNumberNameById(int grammatical_number)
4807 {
4808 	if (grammatical_number == GrammaticalNumberNoNumber) {
4809 		return "no-number";
4810 	} else if (grammatical_number == GrammaticalNumberSingular) {
4811 		return "singular";
4812 	} else if (grammatical_number == GrammaticalNumberPlural) {
4813 		return "plural";
4814 	}
4815 
4816 	return "";
4817 }
4818 
GetGrammaticalNumberIdByName(const std::string & grammatical_number)4819 int GetGrammaticalNumberIdByName(const std::string &grammatical_number)
4820 {
4821 	if (grammatical_number == "no-number") {
4822 		return GrammaticalNumberNoNumber;
4823 	} else if (grammatical_number == "singular") {
4824 		return GrammaticalNumberSingular;
4825 	} else if (grammatical_number == "plural") {
4826 		return GrammaticalNumberPlural;
4827 	}
4828 
4829 	return -1;
4830 }
4831 
GetGrammaticalPersonNameById(int grammatical_person)4832 std::string GetGrammaticalPersonNameById(int grammatical_person)
4833 {
4834 	if (grammatical_person == GrammaticalPersonFirstPerson) {
4835 		return "first-person";
4836 	} else if (grammatical_person == GrammaticalPersonSecondPerson) {
4837 		return "second-person";
4838 	} else if (grammatical_person == GrammaticalPersonThirdPerson) {
4839 		return "third-person";
4840 	}
4841 
4842 	return "";
4843 }
4844 
GetGrammaticalPersonIdByName(const std::string & grammatical_person)4845 int GetGrammaticalPersonIdByName(const std::string &grammatical_person)
4846 {
4847 	if (grammatical_person == "first-person") {
4848 		return GrammaticalPersonFirstPerson;
4849 	} else if (grammatical_person == "second-person") {
4850 		return GrammaticalPersonSecondPerson;
4851 	} else if (grammatical_person == "third-person") {
4852 		return GrammaticalPersonThirdPerson;
4853 	}
4854 
4855 	return -1;
4856 }
4857 
GetGrammaticalGenderNameById(int grammatical_gender)4858 std::string GetGrammaticalGenderNameById(int grammatical_gender)
4859 {
4860 	if (grammatical_gender == GrammaticalGenderNoGender) {
4861 		return "no-gender";
4862 	} else if (grammatical_gender == GrammaticalGenderMasculine) {
4863 		return "masculine";
4864 	} else if (grammatical_gender == GrammaticalGenderFeminine) {
4865 		return "feminine";
4866 	} else if (grammatical_gender == GrammaticalGenderNeuter) {
4867 		return "neuter";
4868 	}
4869 
4870 	return "";
4871 }
4872 
GetGrammaticalGenderIdByName(const std::string & grammatical_gender)4873 int GetGrammaticalGenderIdByName(const std::string &grammatical_gender)
4874 {
4875 	if (grammatical_gender == "no-gender") {
4876 		return GrammaticalGenderNoGender;
4877 	} else if (grammatical_gender == "masculine") {
4878 		return GrammaticalGenderMasculine;
4879 	} else if (grammatical_gender == "feminine") {
4880 		return GrammaticalGenderFeminine;
4881 	} else if (grammatical_gender == "neuter") {
4882 		return GrammaticalGenderNeuter;
4883 	}
4884 
4885 	return -1;
4886 }
4887 
GetGrammaticalTenseNameById(int grammatical_tense)4888 std::string GetGrammaticalTenseNameById(int grammatical_tense)
4889 {
4890 	if (grammatical_tense == GrammaticalTenseNoTense) {
4891 		return "no-tense";
4892 	} else if (grammatical_tense == GrammaticalTensePresent) {
4893 		return "present";
4894 	} else if (grammatical_tense == GrammaticalTensePast) {
4895 		return "past";
4896 	} else if (grammatical_tense == GrammaticalTenseFuture) {
4897 		return "future";
4898 	}
4899 
4900 	return "";
4901 }
4902 
GetGrammaticalTenseIdByName(const std::string & grammatical_tense)4903 int GetGrammaticalTenseIdByName(const std::string &grammatical_tense)
4904 {
4905 	if (grammatical_tense == "no-tense") {
4906 		return GrammaticalTenseNoTense;
4907 	} else if (grammatical_tense == "present") {
4908 		return GrammaticalTensePresent;
4909 	} else if (grammatical_tense == "past") {
4910 		return GrammaticalTensePast;
4911 	} else if (grammatical_tense == "future") {
4912 		return GrammaticalTenseFuture;
4913 	}
4914 
4915 	return -1;
4916 }
4917 
GetGrammaticalMoodNameById(int grammatical_mood)4918 std::string GetGrammaticalMoodNameById(int grammatical_mood)
4919 {
4920 	if (grammatical_mood == GrammaticalMoodIndicative) {
4921 		return "indicative";
4922 	} else if (grammatical_mood == GrammaticalMoodSubjunctive) {
4923 		return "subjunctive";
4924 	}
4925 
4926 	return "";
4927 }
4928 
GetGrammaticalMoodIdByName(const std::string & grammatical_mood)4929 int GetGrammaticalMoodIdByName(const std::string &grammatical_mood)
4930 {
4931 	if (grammatical_mood == "indicative") {
4932 		return GrammaticalMoodIndicative;
4933 	} else if (grammatical_mood == "subjunctive") {
4934 		return GrammaticalMoodSubjunctive;
4935 	}
4936 
4937 	return -1;
4938 }
4939 
GetComparisonDegreeNameById(int comparison_degree)4940 std::string GetComparisonDegreeNameById(int comparison_degree)
4941 {
4942 	if (comparison_degree == ComparisonDegreePositive) {
4943 		return "positive";
4944 	} else if (comparison_degree == ComparisonDegreeComparative) {
4945 		return "comparative";
4946 	} else if (comparison_degree == ComparisonDegreeSuperlative) {
4947 		return "superlative";
4948 	}
4949 
4950 	return "";
4951 }
4952 
GetComparisonDegreeIdByName(const std::string & comparison_degree)4953 int GetComparisonDegreeIdByName(const std::string &comparison_degree)
4954 {
4955 	if (comparison_degree == "positive") {
4956 		return ComparisonDegreePositive;
4957 	} else if (comparison_degree == "comparative") {
4958 		return ComparisonDegreeComparative;
4959 	} else if (comparison_degree == "superlative") {
4960 		return ComparisonDegreeSuperlative;
4961 	}
4962 
4963 	return -1;
4964 }
4965 
GetAffixTypeNameById(int affix_type)4966 std::string GetAffixTypeNameById(int affix_type)
4967 {
4968 	if (affix_type == AffixTypePrefix) {
4969 		return "prefix";
4970 	} else if (affix_type == AffixTypeSuffix) {
4971 		return "suffix";
4972 	} else if (affix_type == AffixTypeInfix) {
4973 		return "infix";
4974 	}
4975 
4976 	return "";
4977 }
4978 
GetAffixTypeIdByName(const std::string & affix_type)4979 int GetAffixTypeIdByName(const std::string &affix_type)
4980 {
4981 	if (affix_type == "prefix") {
4982 		return AffixTypePrefix;
4983 	} else if (affix_type == "suffix") {
4984 		return AffixTypeSuffix;
4985 	} else if (affix_type == "infix") {
4986 		return AffixTypeInfix;
4987 	}
4988 
4989 	return -1;
4990 }
4991 
GetWordJunctionTypeNameById(int word_junction_type)4992 std::string GetWordJunctionTypeNameById(int word_junction_type)
4993 {
4994 	if (word_junction_type == WordJunctionTypeNoWordJunction) {
4995 		return "no-word-junction";
4996 	} else if (word_junction_type == WordJunctionTypeCompound) {
4997 		return "compound";
4998 	} else if (word_junction_type == WordJunctionTypeSeparate) {
4999 		return "separate";
5000 	}
5001 
5002 	return "";
5003 }
5004 
GetWordJunctionTypeIdByName(const std::string & word_junction_type)5005 int GetWordJunctionTypeIdByName(const std::string &word_junction_type)
5006 {
5007 	if (word_junction_type == "no-word-junction") {
5008 		return WordJunctionTypeNoWordJunction;
5009 	} else if (word_junction_type == "compound") {
5010 		return WordJunctionTypeCompound;
5011 	} else if (word_junction_type == "separate") {
5012 		return WordJunctionTypeSeparate;
5013 	}
5014 
5015 	return -1;
5016 }
5017 
GetWord(const std::string word,int word_type,std::vector<std::string> & word_meanings) const5018 LanguageWord *CLanguage::GetWord(const std::string word, int word_type, std::vector<std::string>& word_meanings) const
5019 {
5020 	for (size_t i = 0; i < this->LanguageWords.size(); ++i) {
5021 		if (
5022 			this->LanguageWords[i]->Word == word
5023 			&& (word_type == -1 || this->LanguageWords[i]->Type == word_type)
5024 			&& (word_meanings.size() == 0 || this->LanguageWords[i]->Meanings == word_meanings)
5025 		) {
5026 			return this->LanguageWords[i];
5027 		}
5028 	}
5029 
5030 	return nullptr;
5031 }
5032 
GetArticle(int gender,int grammatical_case,int article_type,int grammatical_number)5033 std::string CLanguage::GetArticle(int gender, int grammatical_case, int article_type, int grammatical_number)
5034 {
5035 	for (size_t i = 0; i < this->LanguageWords.size(); ++i) {
5036 		if (this->LanguageWords[i]->Type != WordTypeArticle || this->LanguageWords[i]->ArticleType != article_type) {
5037 			continue;
5038 		}
5039 
5040 		if (grammatical_number != -1 && this->LanguageWords[i]->GrammaticalNumber != -1 && this->LanguageWords[i]->GrammaticalNumber != grammatical_number) {
5041 			continue;
5042 		}
5043 
5044 		if (gender == -1 || this->LanguageWords[i]->Gender == -1 || gender == this->LanguageWords[i]->Gender) {
5045 			if (grammatical_case == GrammaticalCaseNominative && !this->LanguageWords[i]->Nominative.empty()) {
5046 				return this->LanguageWords[i]->Nominative;
5047 			} else if (grammatical_case == GrammaticalCaseAccusative && !this->LanguageWords[i]->Accusative.empty()) {
5048 				return this->LanguageWords[i]->Accusative;
5049 			} else if (grammatical_case == GrammaticalCaseDative && !this->LanguageWords[i]->Dative.empty()) {
5050 				return this->LanguageWords[i]->Dative;
5051 			} else if (grammatical_case == GrammaticalCaseGenitive && !this->LanguageWords[i]->Genitive.empty()) {
5052 				return this->LanguageWords[i]->Genitive;
5053 			}
5054 		}
5055 	}
5056 	return "";
5057 }
5058 
GetNounEnding(int grammatical_number,int grammatical_case,int word_junction_type)5059 std::string CLanguage::GetNounEnding(int grammatical_number, int grammatical_case, int word_junction_type)
5060 {
5061 	if (word_junction_type == -1) {
5062 		word_junction_type = WordJunctionTypeNoWordJunction;
5063 	}
5064 
5065 	if (!this->NounEndings[grammatical_number][grammatical_case][word_junction_type].empty()) {
5066 		return this->NounEndings[grammatical_number][grammatical_case][word_junction_type];
5067 	} else if (!this->NounEndings[grammatical_number][grammatical_case][WordJunctionTypeNoWordJunction].empty()) {
5068 		return this->NounEndings[grammatical_number][grammatical_case][WordJunctionTypeNoWordJunction];
5069 	}
5070 
5071 	return "";
5072 }
5073 
GetAdjectiveEnding(int article_type,int grammatical_case,int grammatical_number,int grammatical_gender)5074 std::string CLanguage::GetAdjectiveEnding(int article_type, int grammatical_case, int grammatical_number, int grammatical_gender)
5075 {
5076 	if (grammatical_number == -1) {
5077 		grammatical_number = GrammaticalNumberNoNumber;
5078 	}
5079 
5080 	if (grammatical_gender == -1) {
5081 		grammatical_gender = GrammaticalGenderNoGender;
5082 	}
5083 
5084 	if (!this->AdjectiveEndings[article_type][grammatical_case][grammatical_number][grammatical_gender].empty()) {
5085 		return this->AdjectiveEndings[article_type][grammatical_case][grammatical_number][grammatical_gender];
5086 	} else if (!this->AdjectiveEndings[article_type][grammatical_case][grammatical_number][GrammaticalGenderNoGender].empty()) {
5087 		return this->AdjectiveEndings[article_type][grammatical_case][grammatical_number][GrammaticalGenderNoGender];
5088 	} else if (!this->AdjectiveEndings[article_type][grammatical_case][GrammaticalNumberNoNumber][GrammaticalGenderNoGender].empty()) {
5089 		return this->AdjectiveEndings[article_type][grammatical_case][GrammaticalNumberNoNumber][GrammaticalGenderNoGender];
5090 	}
5091 
5092 	return "";
5093 }
5094 
RemoveWord(LanguageWord * word)5095 void CLanguage::RemoveWord(LanguageWord *word)
5096 {
5097 	if (std::find(this->LanguageWords.begin(), this->LanguageWords.end(), word) != this->LanguageWords.end()) {
5098 		this->LanguageWords.erase(std::remove(this->LanguageWords.begin(), this->LanguageWords.end(), word), this->LanguageWords.end());
5099 	}
5100 }
5101 
HasMeaning(const std::string & meaning)5102 bool LanguageWord::HasMeaning(const std::string &meaning)
5103 {
5104 	return std::find(this->Meanings.begin(), this->Meanings.end(), meaning) != this->Meanings.end();
5105 }
5106 
GetNounInflection(int grammatical_number,int grammatical_case,int word_junction_type)5107 std::string LanguageWord::GetNounInflection(int grammatical_number, int grammatical_case, int word_junction_type)
5108 {
5109 	if (this->NumberCaseInflections.find(std::tuple<int, int>(grammatical_number, grammatical_case)) != this->NumberCaseInflections.end()) {
5110 		return this->NumberCaseInflections.find(std::tuple<int, int>(grammatical_number, grammatical_case))->second;
5111 	}
5112 
5113 	return this->Word + this->Language->GetNounEnding(grammatical_number, grammatical_case, word_junction_type);
5114 }
5115 
GetVerbInflection(int grammatical_number,int grammatical_person,int grammatical_tense,int grammatical_mood)5116 std::string LanguageWord::GetVerbInflection(int grammatical_number, int grammatical_person, int grammatical_tense, int grammatical_mood)
5117 {
5118 	if (this->NumberPersonTenseMoodInflections.find(std::tuple<int, int, int, int>(grammatical_number, grammatical_person, grammatical_tense, grammatical_mood)) != this->NumberPersonTenseMoodInflections.end()) {
5119 		return this->NumberPersonTenseMoodInflections.find(std::tuple<int, int, int, int>(grammatical_number, grammatical_person, grammatical_tense, grammatical_mood))->second;
5120 	}
5121 
5122 	return this->Word;
5123 }
5124 
GetAdjectiveInflection(int comparison_degree,int article_type,int grammatical_case,int grammatical_number,int grammatical_gender)5125 std::string LanguageWord::GetAdjectiveInflection(int comparison_degree, int article_type, int grammatical_case, int grammatical_number, int grammatical_gender)
5126 {
5127 	std::string inflected_word;
5128 
5129 	if (grammatical_case == -1) {
5130 		grammatical_case = GrammaticalCaseNoCase;
5131 	}
5132 
5133 	if (!this->ComparisonDegreeCaseInflections[comparison_degree][grammatical_case].empty()) {
5134 		inflected_word = this->ComparisonDegreeCaseInflections[comparison_degree][grammatical_case];
5135 	} else if (!this->ComparisonDegreeCaseInflections[comparison_degree][GrammaticalCaseNoCase].empty()) {
5136 		inflected_word = this->ComparisonDegreeCaseInflections[comparison_degree][GrammaticalCaseNoCase];
5137 	} else {
5138 		inflected_word = this->Word;
5139 	}
5140 
5141 	if (article_type != -1 && grammatical_case != GrammaticalCaseNoCase && this->ComparisonDegreeCaseInflections[comparison_degree][grammatical_case].empty()) {
5142 		inflected_word += this->Language->GetAdjectiveEnding(article_type, grammatical_case, grammatical_number, grammatical_gender);
5143 	}
5144 
5145 	return inflected_word;
5146 }
5147 
GetParticiple(int grammatical_tense)5148 std::string LanguageWord::GetParticiple(int grammatical_tense)
5149 {
5150 	if (!this->Participles[grammatical_tense].empty()) {
5151 		return this->Participles[grammatical_tense];
5152 	}
5153 
5154 	return this->Word;
5155 }
5156 
RemoveFromVector(std::vector<LanguageWord * > & word_vector)5157 void LanguageWord::RemoveFromVector(std::vector<LanguageWord *>& word_vector)
5158 {
5159 	std::vector<LanguageWord *> word_vector_copy = word_vector;
5160 
5161 	if (std::find(word_vector.begin(), word_vector.end(), this) != word_vector.end()) {
5162 		word_vector.erase(std::remove(word_vector.begin(), word_vector.end(), this), word_vector.end());
5163 	}
5164 
5165 	if (word_vector.size() == 0) { // if removing the word from the vector left it empty, undo the removal
5166 		word_vector = word_vector_copy;
5167 	}
5168 }
5169 
IsNameValidForWord(const std::string & word_name)5170 bool IsNameValidForWord(const std::string &word_name)
5171 {
5172 	if (word_name.empty()) {
5173 		return false;
5174 	}
5175 
5176 	if (
5177 		word_name.find('\n') != -1
5178 		|| word_name.find('\\') != -1
5179 		|| word_name.find('/') != -1
5180 		|| word_name.find('.') != -1
5181 		|| word_name.find('*') != -1
5182 		|| word_name.find('[') != -1
5183 		|| word_name.find(']') != -1
5184 		|| word_name.find(':') != -1
5185 		|| word_name.find(';') != -1
5186 		|| word_name.find('=') != -1
5187 		|| word_name.find(',') != -1
5188 		|| word_name.find('<') != -1
5189 		|| word_name.find('>') != -1
5190 		|| word_name.find('?') != -1
5191 		|| word_name.find('|') != -1
5192 	) {
5193 		return false;
5194 	}
5195 
5196 	if (word_name.find_first_not_of(' ') == std::string::npos) {
5197 		return false; //name contains only spaces
5198 	}
5199 
5200 	return true;
5201 }
5202 //Wyrmgus end
5203 
5204 //@}
5205