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 deity.cpp - The deity source file. */
12 //
13 //      (c) Copyright 2018-2019 by Andrettin
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 /*----------------------------------------------------------------------------
31 --  Includes
32 ----------------------------------------------------------------------------*/
33 
34 #include "stratagus.h"
35 
36 #include "religion/deity.h"
37 
38 #include "civilization.h"
39 #include "config.h"
40 #include "plane.h"
41 #include "player.h"
42 #include "province.h"
43 #include "religion/deity_domain.h"
44 #include "religion/pantheon.h"
45 #include "religion/religion.h"
46 #include "upgrade/upgrade.h"
47 
48 #include <algorithm>
49 
50 /*----------------------------------------------------------------------------
51 --  Variables
52 ----------------------------------------------------------------------------*/
53 
54 std::vector<CDeity *> CDeity::Deities;
55 std::map<std::string, CDeity *> CDeity::DeitiesByIdent;
56 std::map<const CUpgrade *, CDeity *> CDeity::DeitiesByUpgrade;
57 
58 /*----------------------------------------------------------------------------
59 --  Functions
60 ----------------------------------------------------------------------------*/
61 
62 /**
63 **	@brief	Get a deity
64 **
65 **	@param	ident		The deity's string identifier
66 **	@param	should_find	Whether it is an error if the deity could not be found; this is true by default
67 **
68 **	@return	The deity if found, or null otherwise
69 */
GetDeity(const std::string & ident,const bool should_find)70 CDeity *CDeity::GetDeity(const std::string &ident, const bool should_find)
71 {
72 	std::map<std::string, CDeity *>::const_iterator find_iterator = DeitiesByIdent.find(ident);
73 
74 	if (find_iterator != DeitiesByIdent.end()) {
75 		return find_iterator->second;
76 	}
77 
78 	if (should_find) {
79 		fprintf(stderr, "Invalid deity: \"%s\".\n", ident.c_str());
80 	}
81 
82 	return nullptr;
83 }
84 
85 /**
86 **	@brief	Get or add a deity
87 **
88 **	@param	ident	The deity's string identifier
89 **
90 **	@return	The deity if found, or a newly-created one otherwise
91 */
GetOrAddDeity(const std::string & ident)92 CDeity *CDeity::GetOrAddDeity(const std::string &ident)
93 {
94 	CDeity *deity = GetDeity(ident, false);
95 
96 	if (!deity) {
97 		deity = new CDeity;
98 		deity->Ident = ident;
99 		Deities.push_back(deity);
100 		DeitiesByIdent[ident] = deity;
101 	}
102 
103 	return deity;
104 }
105 
106 /**
107 **	@brief	Get a deity by its respective upgrade
108 **
109 **	@param	upgrade	The deity's upgrade
110 **	@param	should_find	Whether it is an error if the deity could not be found; this is true by default
111 **
112 **	@return	The upgrade's deity, if any
113 */
GetDeityByUpgrade(const CUpgrade * upgrade,const bool should_find)114 CDeity *CDeity::GetDeityByUpgrade(const CUpgrade *upgrade, const bool should_find)
115 {
116 	if (DeitiesByUpgrade.find(upgrade) != DeitiesByUpgrade.end()) {
117 		return DeitiesByUpgrade.find(upgrade)->second;
118 	}
119 
120 	if (should_find) {
121 		fprintf(stderr, "No deity found for upgrade: \"%s\".\n", upgrade->Ident.c_str());
122 	}
123 
124 	return nullptr;
125 }
126 
127 /**
128 **	@brief	Remove the existing deities
129 */
ClearDeities()130 void CDeity::ClearDeities()
131 {
132 	for (size_t i = 0; i < Deities.size(); ++i) {
133 		delete Deities[i];
134 	}
135 	Deities.clear();
136 }
137 
138 /**
139 **	@brief	Process data provided by a configuration file
140 **
141 **	@param	config_data	The configuration data
142 */
ProcessConfigData(const CConfigData * config_data)143 void CDeity::ProcessConfigData(const CConfigData *config_data)
144 {
145 	for (size_t i = 0; i < config_data->Properties.size(); ++i) {
146 		std::string key = config_data->Properties[i].first;
147 		std::string value = config_data->Properties[i].second;
148 
149 		if (key == "name") {
150 			this->Name = value;
151 		} else if (key == "pantheon") {
152 			value = FindAndReplaceString(value, "_", "-");
153 			this->Pantheon = CPantheon::GetPantheon(value);
154 		} else if (key == "gender") {
155 			this->Gender = GetGenderIdByName(value);
156 		} else if (key == "major") {
157 			this->Major = StringToBool(value);
158 		} else if (key == "civilization") {
159 			value = FindAndReplaceString(value, "_", "-");
160 			CCivilization *civilization = CCivilization::GetCivilization(value);
161 			if (civilization != nullptr) {
162 				this->Civilizations.push_back(civilization);
163 				civilization->Deities.push_back(this);
164 			}
165 		} else if (key == "religion") {
166 			value = FindAndReplaceString(value, "_", "-");
167 			CReligion *religion = CReligion::GetReligion(value.c_str());
168 			if (religion) {
169 				this->Religions.push_back(religion);
170 			}
171 		} else if (key == "domain") {
172 			value = FindAndReplaceString(value, "_", "-");
173 			CDeityDomain *deity_domain = CDeityDomain::GetDeityDomain(value.c_str());
174 			if (deity_domain) {
175 				this->Domains.push_back(deity_domain);
176 			}
177 		} else if (key == "description") {
178 			this->Description = value;
179 		} else if (key == "background") {
180 			this->Background = value;
181 		} else if (key == "quote") {
182 			this->Quote = value;
183 		} else if (key == "icon") {
184 			value = FindAndReplaceString(value, "_", "-");
185 			this->Icon.Name = value;
186 			this->Icon.Icon = nullptr;
187 			this->Icon.Load();
188 			this->Icon.Icon->Load();
189 		} else if (key == "home_plane") {
190 			value = FindAndReplaceString(value, "_", "-");
191 			CPlane *plane = CPlane::GetPlane(value);
192 			if (plane) {
193 				this->HomePlane = plane;
194 			}
195 		} else if (key == "deity_upgrade") {
196 			value = FindAndReplaceString(value, "_", "-");
197 			CUpgrade *upgrade = CUpgrade::Get(value);
198 			if (upgrade) {
199 				this->DeityUpgrade = upgrade;
200 				CDeity::DeitiesByUpgrade[upgrade] = this;
201 			} else {
202 				fprintf(stderr, "Invalid upgrade: \"%s\".\n", value.c_str());
203 			}
204 		} else if (key == "character_upgrade") {
205 			value = FindAndReplaceString(value, "_", "-");
206 			CUpgrade *upgrade = CUpgrade::Get(value);
207 			if (upgrade) {
208 				this->CharacterUpgrade = upgrade;
209 			} else {
210 				fprintf(stderr, "Invalid upgrade: \"%s\".\n", value.c_str());
211 			}
212 		} else if (key == "holy_order") {
213 			value = FindAndReplaceString(value, "_", "-");
214 			CFaction *holy_order = PlayerRaces.GetFaction(value);
215 			if (holy_order) {
216 				this->HolyOrders.push_back(holy_order);
217 				holy_order->HolyOrderDeity = this;
218 			} else {
219 				fprintf(stderr, "Invalid faction: \"%s\".\n", value.c_str());
220 			}
221 		} else {
222 			fprintf(stderr, "Invalid deity property: \"%s\".\n", key.c_str());
223 		}
224 	}
225 
226 	for (const CConfigData *child_config_data : config_data->Children) {
227 		if (child_config_data->Tag == "cultural_names") {
228 			for (size_t j = 0; j < child_config_data->Properties.size(); ++j) {
229 				std::string key = child_config_data->Properties[j].first;
230 				std::string value = child_config_data->Properties[j].second;
231 
232 				key = FindAndReplaceString(key, "_", "-");
233 
234 				const CCivilization *civilization = CCivilization::GetCivilization(key);
235 
236 				if (civilization) {
237 					this->CulturalNames[civilization] = value;
238 				}
239 			}
240 		} else {
241 			fprintf(stderr, "Invalid deity property: \"%s\".\n", child_config_data->Tag.c_str());
242 		}
243 	}
244 
245 	if (this->Major && this->Domains.size() > MAJOR_DEITY_DOMAIN_MAX) { // major deities can only have up to three domains
246 		this->Domains.resize(MAJOR_DEITY_DOMAIN_MAX);
247 	} else if (!this->Major && this->Domains.size() > MINOR_DEITY_DOMAIN_MAX) { // minor deities can only have one domain
248 		this->Domains.resize(MINOR_DEITY_DOMAIN_MAX);
249 	}
250 
251 	for (CDeityDomain *domain : this->Domains) {
252 		for (CUpgrade *ability : domain->Abilities) {
253 			if (std::find(this->Abilities.begin(), this->Abilities.end(), ability) == this->Abilities.end()) {
254 				this->Abilities.push_back(ability);
255 			}
256 		}
257 	}
258 }
259 
260 /**
261 **	@brief	Get the cultural name for a given civilization
262 **
263 **	@param	civilization	The civilization
264 **
265 **	@return	The name if present, or an empty string otherwise
266 */
GetCulturalName(const CCivilization * civilization) const267 std::string CDeity::GetCulturalName(const CCivilization *civilization) const
268 {
269 	std::map<const CCivilization *, std::string>::const_iterator find_iterator = this->CulturalNames.find(civilization);
270 
271 	if (find_iterator != this->CulturalNames.end()) {
272 		return find_iterator->second;
273 	}
274 
275 	return std::string();
276 }