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 script_player.cpp - The player ccl functions. */
12 //
13 //      (c) Copyright 2001-2019 by Lutz Sammer, Jimmy Salmon and 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 "player.h"
37 
38 #include "actions.h"
39 #include "age.h"
40 #include "ai.h"
41 #include "character.h"
42 #include "civilization.h"
43 #include "commands.h"
44 #include "currency.h"
45 //Wyrmgus start
46 #include "editor.h"
47 #include "font.h"
48 #include "grand_strategy.h"
49 #include "item.h"
50 #include "luacallback.h"
51 //Wyrmgus end
52 #include "map/map.h"
53 #include "map/site.h"
54 #include "plane.h"
55 #include "province.h"
56 #include "quest.h"
57 #include "religion/deity.h"
58 #include "religion/deity_domain.h"
59 #include "religion/pantheon.h"
60 #include "religion/religion.h"
61 #include "script.h"
62 #include "time/calendar.h"
63 #include "ui/button_action.h"
64 #include "unit/unit.h"
65 #include "unit/unit_find.h"
66 #include "unit/unittype.h"
67 #include "video.h"
68 #include "upgrade/upgrade.h"
69 //Wyrmgus start
70 #include "ui/ui.h"
71 #include "util.h"
72 //Wyrmgus end
73 
74 /*----------------------------------------------------------------------------
75 --  Variables
76 ----------------------------------------------------------------------------*/
77 
78 /*----------------------------------------------------------------------------
79 --  Functions
80 ----------------------------------------------------------------------------*/
81 
82 extern CUnit *CclGetUnitFromRef(lua_State *l);
83 
84 /**
85 **  Get a player pointer
86 **
87 **  @param l  Lua state.
88 **
89 **  @return   The player pointer
90 */
CclGetPlayer(lua_State * l)91 static CPlayer *CclGetPlayer(lua_State *l)
92 {
93 	return &Players[LuaToNumber(l, -1)];
94 }
95 
96 /**
97 **  Parse the player configuration.
98 **
99 **  @param l  Lua state.
100 */
CclPlayer(lua_State * l)101 static int CclPlayer(lua_State *l)
102 {
103 	int i = LuaToNumber(l, 1);
104 
105 	CPlayer &player = Players[i];
106 	player.Index = i;
107 
108 	if (NumPlayers <= i) {
109 		NumPlayers = i + 1;
110 	}
111 
112 	player.Load(l);
113 	return 0;
114 }
115 
Load(lua_State * l)116 void CPlayer::Load(lua_State *l)
117 {
118 	const int args = lua_gettop(l);
119 
120 	this->Units.resize(0);
121 	this->FreeWorkers.resize(0);
122 	//Wyrmgus start
123 	this->LevelUpUnits.resize(0);
124 	//Wyrmgus end
125 
126 	// j = 0 represent player Index.
127 	for (int j = 1; j < args; ++j) {
128 		const char *value = LuaToString(l, j + 1);
129 		++j;
130 
131 		if (!strcmp(value, "name")) {
132 			this->SetName(LuaToString(l, j + 1));
133 		} else if (!strcmp(value, "type")) {
134 			value = LuaToString(l, j + 1);
135 			if (!strcmp(value, "neutral")) {
136 				this->Type = PlayerNeutral;
137 			} else if (!strcmp(value, "nobody")) {
138 				this->Type = PlayerNobody;
139 			} else if (!strcmp(value, "computer")) {
140 				this->Type = PlayerComputer;
141 			} else if (!strcmp(value, "person")) {
142 				this->Type = PlayerPerson;
143 			} else if (!strcmp(value, "rescue-passive")) {
144 				this->Type = PlayerRescuePassive;
145 			} else if (!strcmp(value, "rescue-active")) {
146 				this->Type = PlayerRescueActive;
147 			} else {
148 				LuaError(l, "Unsupported tag: %s" _C_ value);
149 			}
150 		} else if (!strcmp(value, "race")) {
151 			const char *civilization_ident = LuaToString(l, j + 1);
152 			CCivilization *civilization = CCivilization::GetCivilization(civilization_ident);
153 			if (civilization) {
154 				this->Race = civilization->ID;
155 			}
156 		//Wyrmgus start
157 		} else if (!strcmp(value, "faction")) {
158 			this->Faction = LuaToNumber(l, j + 1);
159 		} else if (!strcmp(value, "dynasty")) {
160 			this->Dynasty = PlayerRaces.GetDynasty(LuaToString(l, j + 1));
161 		} else if (!strcmp(value, "age")) {
162 			this->Age = CAge::GetAge(LuaToString(l, j + 1));
163 		} else if (!strcmp(value, "color")) {
164 			int color_id = LuaToNumber(l, j + 1);
165 			this->Color = PlayerColors[color_id][0];
166 			this->UnitColors.Colors = PlayerColorsRGB[color_id];
167 		//Wyrmgus end
168 		} else if (!strcmp(value, "ai-name")) {
169 			this->AiName = LuaToString(l, j + 1);
170 		} else if (!strcmp(value, "team")) {
171 			this->Team = LuaToNumber(l, j + 1);
172 		} else if (!strcmp(value, "enemy")) {
173 			value = LuaToString(l, j + 1);
174 			for (int i = 0; i < PlayerMax && *value; ++i, ++value) {
175 				if (*value == '-' || *value == '_' || *value == ' ') {
176 					this->Enemy &= ~(1 << i);
177 				} else {
178 					this->Enemy |= (1 << i);
179 				}
180 			}
181 		} else if (!strcmp(value, "allied")) {
182 			value = LuaToString(l, j + 1);
183 			for (int i = 0; i < PlayerMax && *value; ++i, ++value) {
184 				if (*value == '-' || *value == '_' || *value == ' ') {
185 					this->Allied &= ~(1 << i);
186 				} else {
187 					this->Allied |= (1 << i);
188 				}
189 			}
190 		} else if (!strcmp(value, "shared-vision")) {
191 			value = LuaToString(l, j + 1);
192 			for (int i = 0; i < PlayerMax && *value; ++i, ++value) {
193 				if (*value == '-' || *value == '_' || *value == ' ') {
194 					this->SharedVision &= ~(1 << i);
195 				} else {
196 					this->SharedVision |= (1 << i);
197 				}
198 			}
199 		} else if (!strcmp(value, "start")) {
200 			CclGetPos(l, &this->StartPos.x, &this->StartPos.y, j + 1);
201 		//Wyrmgus start
202 		} else if (!strcmp(value, "start-map-layer")) {
203 			this->StartMapLayer = LuaToNumber(l, j + 1);
204 		} else if (!strcmp(value, "overlord")) {
205 			int overlord_id = LuaToNumber(l, j + 1);
206 			this->SetOverlord(&Players[overlord_id]);
207 		//Wyrmgus end
208 		} else if (!strcmp(value, "resources")) {
209 			if (!lua_istable(l, j + 1)) {
210 				LuaError(l, "incorrect argument");
211 			}
212 			const int subargs = lua_rawlen(l, j + 1);
213 			for (int k = 0; k < subargs; ++k) {
214 				value = LuaToString(l, j + 1, k + 1);
215 				++k;
216 				const int resId = GetResourceIdByName(l, value);
217 				this->Resources[resId] = LuaToNumber(l, j + 1, k + 1);
218 			}
219 		} else if (!strcmp(value, "stored-resources")) {
220 			if (!lua_istable(l, j + 1)) {
221 				LuaError(l, "incorrect argument");
222 			}
223 			const int subargs = lua_rawlen(l, j + 1);
224 			for (int k = 0; k < subargs; ++k) {
225 				value = LuaToString(l, j + 1, k + 1);
226 				++k;
227 
228 				const int resId = GetResourceIdByName(l, value);
229 				this->StoredResources[resId] = LuaToNumber(l, j + 1, k + 1);
230 			}
231 		} else if (!strcmp(value, "max-resources")) {
232 			if (!lua_istable(l, j + 1)) {
233 				LuaError(l, "incorrect argument");
234 			}
235 			const int subargs = lua_rawlen(l, j + 1);
236 			for (int k = 0; k < subargs; ++k) {
237 				value = LuaToString(l, j + 1, k + 1);
238 				++k;
239 				const int resId = GetResourceIdByName(l, value);
240 				this->MaxResources[resId] = LuaToNumber(l, j + 1, k + 1);
241 			}
242 		} else if (!strcmp(value, "last-resources")) {
243 			if (!lua_istable(l, j + 1)) {
244 				LuaError(l, "incorrect argument");
245 			}
246 			const int subargs = lua_rawlen(l, j + 1);
247 			for (int k = 0; k < subargs; ++k) {
248 				value = LuaToString(l, j + 1, k + 1);
249 				++k;
250 				const int resId = GetResourceIdByName(l, value);
251 				this->LastResources[resId] = LuaToNumber(l, j + 1, k + 1);
252 			}
253 		} else if (!strcmp(value, "incomes")) {
254 			if (!lua_istable(l, j + 1)) {
255 				LuaError(l, "incorrect argument");
256 			}
257 			const int subargs = lua_rawlen(l, j + 1);
258 			for (int k = 0; k < subargs; ++k) {
259 				value = LuaToString(l, j + 1, k + 1);
260 				++k;
261 
262 				const int resId = GetResourceIdByName(l, value);
263 				this->Incomes[resId] = LuaToNumber(l, j + 1, k + 1);
264 			}
265 		} else if (!strcmp(value, "revenue")) {
266 			if (!lua_istable(l, j + 1)) {
267 				LuaError(l, "incorrect argument");
268 			}
269 			const int subargs = lua_rawlen(l, j + 1);
270 			for (int k = 0; k < subargs; ++k) {
271 				value = LuaToString(l, j + 1, k + 1);
272 				++k;
273 
274 				const int resId = GetResourceIdByName(l, value);
275 				this->Revenue[resId] = LuaToNumber(l, j + 1, k + 1);
276 			}
277 		//Wyrmgus start
278 		} else if (!strcmp(value, "prices")) {
279 			if (!lua_istable(l, j + 1)) {
280 				LuaError(l, "incorrect argument");
281 			}
282 			const int subargs = lua_rawlen(l, j + 1);
283 			for (int k = 0; k < subargs; ++k) {
284 				value = LuaToString(l, j + 1, k + 1);
285 				++k;
286 
287 				const int resId = GetResourceIdByName(l, value);
288 				this->Prices[resId] = LuaToNumber(l, j + 1, k + 1);
289 			}
290 		//Wyrmgus end
291 		} else if (!strcmp(value, "ai-enabled")) {
292 			this->AiEnabled = true;
293 			--j;
294 		} else if (!strcmp(value, "ai-disabled")) {
295 			this->AiEnabled = false;
296 			--j;
297 		//Wyrmgus start
298 		} else if (!strcmp(value, "revealed")) {
299 			this->Revealed = true;
300 			--j;
301 		//Wyrmgus end
302 		} else if (!strcmp(value, "supply")) {
303 			this->Supply = LuaToNumber(l, j + 1);
304 		} else if (!strcmp(value, "demand")) {
305 			this->Demand = LuaToNumber(l, j + 1);
306 		} else if (!strcmp(value, "trade-cost")) {
307 			this->TradeCost = LuaToNumber(l, j + 1);
308 		} else if (!strcmp(value, "unit-limit")) {
309 			this->UnitLimit = LuaToNumber(l, j + 1);
310 		} else if (!strcmp(value, "building-limit")) {
311 			this->BuildingLimit = LuaToNumber(l, j + 1);
312 		} else if (!strcmp(value, "total-unit-limit")) {
313 			this->TotalUnitLimit = LuaToNumber(l, j + 1);
314 		} else if (!strcmp(value, "score")) {
315 			this->Score = LuaToNumber(l, j + 1);
316 		} else if (!strcmp(value, "total-units")) {
317 			this->TotalUnits = LuaToNumber(l, j + 1);
318 		} else if (!strcmp(value, "total-buildings")) {
319 			this->TotalBuildings = LuaToNumber(l, j + 1);
320 		} else if (!strcmp(value, "total-razings")) {
321 			this->TotalRazings = LuaToNumber(l, j + 1);
322 		} else if (!strcmp(value, "total-kills")) {
323 			this->TotalKills = LuaToNumber(l, j + 1);
324 		//Wyrmgus start
325 		} else if (!strcmp(value, "unit-type-kills")) {
326 			if (!lua_istable(l, j + 1)) {
327 				LuaError(l, "incorrect argument");
328 			}
329 			const int subargs = lua_rawlen(l, j + 1);
330 			for (int k = 0; k < subargs; ++k) {
331 				CUnitType *unit_type = UnitTypeByIdent(LuaToString(l, j + 1, k + 1));
332 				++k;
333 				if (unit_type) {
334 					this->UnitTypeKills[unit_type->Slot] = LuaToNumber(l, j + 1, k + 1);
335 				}
336 			}
337 		} else if (!strcmp(value, "lost-town-hall-timer")) {
338 			this->LostTownHallTimer = LuaToNumber(l, j + 1);
339 		} else if (!strcmp(value, "hero-cooldown-timer")) {
340 			this->HeroCooldownTimer = LuaToNumber(l, j + 1);
341 		//Wyrmgus end
342 		} else if (!strcmp(value, "total-resources")) {
343 			if (!lua_istable(l, j + 1)) {
344 				LuaError(l, "incorrect argument");
345 			}
346 			const int subargs = lua_rawlen(l, j + 1);
347 			//Wyrmgus start
348 //			if (subargs != MaxCosts) {
349 //				LuaError(l, "Wrong number of total-resources: %d" _C_ subargs);
350 //			}
351 			if (subargs != MaxCosts) {
352 				fprintf(stderr, "Wrong number of total-resources: %d.\n", subargs);
353 			}
354 			//Wyrmgus end
355 			for (int k = 0; k < subargs; ++k) {
356 				this->TotalResources[k] = LuaToNumber(l, j + 1, k + 1);
357 			}
358 		} else if (!strcmp(value, "speed-resource-harvest")) {
359 			if (!lua_istable(l, j + 1)) {
360 				LuaError(l, "incorrect argument");
361 			}
362 			const int subargs = lua_rawlen(l, j + 1);
363 			//Wyrmgus start
364 //			if (subargs != MaxCosts) {
365 //				LuaError(l, "Wrong number of speed-resource-harvest: %d" _C_ subargs);
366 //			}
367 			if (subargs != MaxCosts) {
368 				fprintf(stderr, "Wrong number of speed-resource-harvest: %d.\n", subargs);
369 			}
370 			//Wyrmgus end
371 			for (int k = 0; k < subargs; ++k) {
372 				this->SpeedResourcesHarvest[k] = LuaToNumber(l, j + 1, k + 1);
373 			}
374 		} else if (!strcmp(value, "speed-resource-return")) {
375 			if (!lua_istable(l, j + 1)) {
376 				LuaError(l, "incorrect argument");
377 			}
378 			const int subargs = lua_rawlen(l, j + 1);
379 			//Wyrmgus start
380 //			if (subargs != MaxCosts) {
381 //				LuaError(l, "Wrong number of speed-resource-harvest: %d" _C_ subargs);
382 //			}
383 			if (subargs != MaxCosts) {
384 				fprintf(stderr, "Wrong number of speed-resource-return: %d.\n", subargs);
385 			}
386 			//Wyrmgus end
387 			for (int k = 0; k < subargs; ++k) {
388 				this->SpeedResourcesReturn[k] = LuaToNumber(l, j + 1, k + 1);
389 			}
390 		} else if (!strcmp(value, "speed-build")) {
391 			this->SpeedBuild = LuaToNumber(l, j + 1);
392 		} else if (!strcmp(value, "speed-train")) {
393 			this->SpeedTrain = LuaToNumber(l, j + 1);
394 		} else if (!strcmp(value, "speed-upgrade")) {
395 			this->SpeedUpgrade = LuaToNumber(l, j + 1);
396 		} else if (!strcmp(value, "speed-research")) {
397 			this->SpeedResearch = LuaToNumber(l, j + 1);
398 		//Wyrmgus start
399 		/*
400 		} else if (!strcmp(value, "color")) {
401 			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 3) {
402 				LuaError(l, "incorrect argument");
403 			}
404 			const int r = LuaToNumber(l, j + 1, 1);
405 			const int g = LuaToNumber(l, j + 1, 2);
406 			const int b = LuaToNumber(l, j + 1, 3);
407 			this->Color = Video.MapRGB(TheScreen->format, r, g, b);
408 		*/
409 		//Wyrmgus end
410 		//Wyrmgus start
411 		} else if (!strcmp(value, "current-quests")) {
412 			if (!lua_istable(l, j + 1)) {
413 				LuaError(l, "incorrect argument");
414 			}
415 			const int subargs = lua_rawlen(l, j + 1);
416 			for (int k = 0; k < subargs; ++k) {
417 				CQuest *quest = GetQuest(LuaToString(l, j + 1, k + 1));
418 				if (quest) {
419 					this->CurrentQuests.push_back(quest);
420 				}
421 			}
422 		} else if (!strcmp(value, "completed-quests")) {
423 			if (!lua_istable(l, j + 1)) {
424 				LuaError(l, "incorrect argument");
425 			}
426 			const int subargs = lua_rawlen(l, j + 1);
427 			for (int k = 0; k < subargs; ++k) {
428 				CQuest *quest = GetQuest(LuaToString(l, j + 1, k + 1));
429 				if (quest) {
430 					this->CompletedQuests.push_back(quest);
431 					if (quest->Competitive) {
432 						quest->CurrentCompleted = true;
433 					}
434 				}
435 			}
436 		} else if (!strcmp(value, "quest-objectives")) {
437 			if (!lua_istable(l, j + 1)) {
438 				LuaError(l, "incorrect argument");
439 			}
440 			const int subargs = lua_rawlen(l, j + 1);
441 			for (int k = 0; k < subargs; ++k) {
442 				lua_rawgeti(l, j + 1, k + 1);
443 				CPlayerQuestObjective *objective = new CPlayerQuestObjective;
444 				this->QuestObjectives.push_back(objective);
445 				if (!lua_istable(l, -1)) {
446 					LuaError(l, "incorrect argument (expected table for quest objectives)");
447 				}
448 				const int subsubargs = lua_rawlen(l, -1);
449 				for (int n = 0; n < subsubargs; ++n) {
450 					value = LuaToString(l, -1, n + 1);
451 					++n;
452 					if (!strcmp(value, "quest")) {
453 						objective->Quest = GetQuest(LuaToString(l, -1, n + 1));
454 						if (!objective->Quest) {
455 							LuaError(l, "Quest doesn't exist.");
456 						}
457 					} else if (!strcmp(value, "objective-type")) {
458 						objective->ObjectiveType = GetQuestObjectiveTypeIdByName(LuaToString(l, -1, n + 1));
459 						if (objective->ObjectiveType == -1) {
460 							LuaError(l, "Objective type doesn't exist.");
461 						}
462 					} else if (!strcmp(value, "objective-string")) {
463 						objective->ObjectiveString = LuaToString(l, -1, n + 1);
464 					} else if (!strcmp(value, "quantity")) {
465 						objective->Quantity = LuaToNumber(l, -1, n + 1);
466 					} else if (!strcmp(value, "counter")) {
467 						objective->Counter = LuaToNumber(l, -1, n + 1);
468 					} else if (!strcmp(value, "resource")) {
469 						int resource = GetResourceIdByName(LuaToString(l, -1, n + 1));
470 						if (resource == -1) {
471 							LuaError(l, "Resource doesn't exist.");
472 						}
473 						objective->Resource = resource;
474 					} else if (!strcmp(value, "unit-class")) {
475 						int unit_class = GetUnitTypeClassIndexByName(LuaToString(l, -1, n + 1));
476 						if (unit_class == -1) {
477 							LuaError(l, "Unit class doesn't exist.");
478 						}
479 						objective->UnitClass = unit_class;
480 					} else if (!strcmp(value, "unit-type")) {
481 						CUnitType *unit_type = UnitTypeByIdent(LuaToString(l, -1, n + 1));
482 						if (!unit_type) {
483 							LuaError(l, "Unit type doesn't exist.");
484 						}
485 						objective->UnitTypes.push_back(unit_type);
486 					} else if (!strcmp(value, "upgrade")) {
487 						CUpgrade *upgrade = CUpgrade::Get(LuaToString(l, -1, n + 1));
488 						if (!upgrade) {
489 							LuaError(l, "Upgrade doesn't exist.");
490 						}
491 						objective->Upgrade = upgrade;
492 					} else if (!strcmp(value, "character")) {
493 						CCharacter *character = CCharacter::GetCharacter(LuaToString(l, -1, n + 1));
494 						if (!character) {
495 							LuaError(l, "Character doesn't exist.");
496 						}
497 						objective->Character = character;
498 					} else if (!strcmp(value, "unique")) {
499 						CUniqueItem *unique = GetUniqueItem(LuaToString(l, -1, n + 1));
500 						if (!unique) {
501 							LuaError(l, "Unique doesn't exist.");
502 						}
503 						objective->Unique = unique;
504 					} else if (!strcmp(value, "settlement")) {
505 						CSite *site = CSite::GetSite(LuaToString(l, -1, n + 1));
506 						if (!site) {
507 							LuaError(l, "Site doesn't exist.");
508 						}
509 						objective->Settlement = site;
510 					} else if (!strcmp(value, "faction")) {
511 						CFaction *faction = PlayerRaces.GetFaction(LuaToString(l, -1, n + 1));
512 						if (!faction) {
513 							LuaError(l, "Faction doesn't exist.");
514 						}
515 						objective->Faction = faction;
516 					} else {
517 						LuaError(l, "Invalid quest objective property.");
518 					}
519 				}
520 				lua_pop(l, 1);
521 			}
522 		} else if (!strcmp(value, "modifiers")) {
523 			if (!lua_istable(l, j + 1)) {
524 				LuaError(l, "incorrect argument");
525 			}
526 			const int subargs = lua_rawlen(l, j + 1);
527 			for (int k = 0; k < subargs; ++k) {
528 				CUpgrade *modifier_upgrade = CUpgrade::Get(LuaToString(l, j + 1, k + 1));
529 				++k;
530 				int end_cycle = LuaToNumber(l, j + 1, k + 1);
531 				if (modifier_upgrade) {
532 					this->Modifiers.push_back(std::pair<CUpgrade *, int>(modifier_upgrade, end_cycle));
533 				}
534 			}
535 		//Wyrmgus end
536 		} else if (!strcmp(value, "autosell-resources")) {
537 			if (!lua_istable(l, j + 1)) {
538 				LuaError(l, "incorrect argument");
539 			}
540 			const int subargs = lua_rawlen(l, j + 1);
541 			for (int k = 0; k < subargs; ++k) {
542 				const int res = GetResourceIdByName(LuaToString(l, j + 1, k + 1));
543 				if (res != -1) {
544 					this->AutosellResources.push_back(res);
545 				}
546 			}
547 		} else if (!strcmp(value, "timers")) {
548 			if (!lua_istable(l, j + 1)) {
549 				LuaError(l, "incorrect argument");
550 			}
551 			const int subargs = lua_rawlen(l, j + 1);
552 			//Wyrmgus start
553 //			if (subargs != UpgradeMax) {
554 //				LuaError(l, "Wrong upgrade timer length: %d" _C_ subargs);
555 //			}
556 			//Wyrmgus end
557 			for (int k = 0; k < subargs; ++k) {
558 				//Wyrmgus start
559 //				this->UpgradeTimers.Upgrades[k] = LuaToNumber(l, j + 1, k + 1);
560 				CUpgrade *timer_upgrade = CUpgrade::Get(LuaToString(l, j + 1, k + 1));
561 				++k;
562 				if (timer_upgrade) {
563 					this->UpgradeTimers.Upgrades[timer_upgrade->ID] = LuaToNumber(l, j + 1, k + 1);
564 				}
565 				//Wyrmgus end
566 			}
567 		} else {
568 			LuaError(l, "Unsupported tag: %s" _C_ value);
569 		}
570 	}
571 	// Manage max
572 	for (int i = 0; i < MaxCosts; ++i) {
573 		if (this->MaxResources[i] != -1) {
574 			this->SetResource(i, this->Resources[i] + this->StoredResources[i], STORE_BOTH);
575 		}
576 	}
577 }
578 
579 /**
580 **  Change unit owner
581 **
582 **  @param l  Lua state.
583 */
CclChangeUnitsOwner(lua_State * l)584 static int CclChangeUnitsOwner(lua_State *l)
585 {
586 	LuaCheckArgs(l, 4);
587 
588 	Vec2i pos1;
589 	Vec2i pos2;
590 	CclGetPos(l, &pos1.x, &pos1.y, 1);
591 	CclGetPos(l, &pos2.x, &pos2.y, 2);
592 	const int oldp = LuaToNumber(l, 3);
593 	const int newp = LuaToNumber(l, 4);
594 	std::vector<CUnit *> table;
595 
596 	//Wyrmgus start
597 //	Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
598 	Select(pos1, pos2, table, 0, HasSamePlayerAs(Players[oldp]));
599 	//Wyrmgus end
600 	for (size_t i = 0; i != table.size(); ++i) {
601 		table[i]->ChangeOwner(Players[newp]);
602 	}
603 	return 0;
604 }
605 
606 /**
607 **  Get ThisPlayer.
608 **
609 **  @param l  Lua state.
610 */
CclGetThisPlayer(lua_State * l)611 static int CclGetThisPlayer(lua_State *l)
612 {
613 	LuaCheckArgs(l, 0);
614 	if (ThisPlayer) {
615 		lua_pushnumber(l, ThisPlayer - Players);
616 	} else {
617 		lua_pushnumber(l, 0);
618 	}
619 	return 1;
620 }
621 
622 /**
623 **  Set ThisPlayer.
624 **
625 **  @param l  Lua state.
626 */
CclSetThisPlayer(lua_State * l)627 static int CclSetThisPlayer(lua_State *l)
628 {
629 	LuaCheckArgs(l, 1);
630 	int plynr = LuaToNumber(l, 1);
631 
632 	ThisPlayer = &Players[plynr];
633 
634 	//Wyrmgus start
635 	UI.Load();
636 	//Wyrmgus end
637 
638 	lua_pushnumber(l, plynr);
639 	return 1;
640 }
641 
642 /**
643 **  Set MaxSelectable
644 **
645 **  @param l  Lua state.
646 */
CclSetMaxSelectable(lua_State * l)647 static int CclSetMaxSelectable(lua_State *l)
648 {
649 	LuaCheckArgs(l, 1);
650 	MaxSelectable = LuaToNumber(l, 1);
651 
652 	lua_pushnumber(l, MaxSelectable);
653 	return 1;
654 }
655 
656 /**
657 **  Set player unit limit.
658 **
659 **  @param l  Lua state.
660 */
CclSetAllPlayersUnitLimit(lua_State * l)661 static int CclSetAllPlayersUnitLimit(lua_State *l)
662 {
663 	LuaCheckArgs(l, 1);
664 	for (int i = 0; i < PlayerMax; ++i) {
665 		Players[i].UnitLimit = LuaToNumber(l, 1);
666 	}
667 
668 	lua_pushnumber(l, lua_tonumber(l, 1));
669 	return 1;
670 }
671 
672 /**
673 **  Set player unit limit.
674 **
675 **  @param l  Lua state.
676 */
CclSetAllPlayersBuildingLimit(lua_State * l)677 static int CclSetAllPlayersBuildingLimit(lua_State *l)
678 {
679 	LuaCheckArgs(l, 1);
680 	for (int i = 0; i < PlayerMax; ++i) {
681 		Players[i].BuildingLimit = LuaToNumber(l, 1);
682 	}
683 
684 	lua_pushnumber(l, lua_tonumber(l, 1));
685 	return 1;
686 }
687 
688 /**
689 **  Set player unit limit.
690 **
691 **  @param l  Lua state.
692 */
CclSetAllPlayersTotalUnitLimit(lua_State * l)693 static int CclSetAllPlayersTotalUnitLimit(lua_State *l)
694 {
695 	LuaCheckArgs(l, 1);
696 	for (int i = 0; i < PlayerMax; ++i) {
697 		Players[i].TotalUnitLimit = LuaToNumber(l, 1);
698 	}
699 
700 	lua_pushnumber(l, lua_tonumber(l, 1));
701 	return 1;
702 }
703 
704 /**
705 **  Change the diplomacy from player to another player.
706 **
707 **  @param l  Lua state.
708 **
709 **  @return          FIXME: should return old state.
710 */
CclSetDiplomacy(lua_State * l)711 static int CclSetDiplomacy(lua_State *l)
712 {
713 	LuaCheckArgs(l, 3);
714 	const int base = LuaToNumber(l, 1);
715 	const int plynr = LuaToNumber(l, 3);
716 	const char *state = LuaToString(l, 2);
717 
718 	if (!strcmp(state, "allied")) {
719 		SendCommandDiplomacy(base, DiplomacyAllied, plynr);
720 	} else if (!strcmp(state, "neutral")) {
721 		SendCommandDiplomacy(base, DiplomacyNeutral, plynr);
722 	} else if (!strcmp(state, "crazy")) {
723 		SendCommandDiplomacy(base, DiplomacyCrazy, plynr);
724 	} else if (!strcmp(state, "enemy")) {
725 		SendCommandDiplomacy(base, DiplomacyEnemy, plynr);
726 	//Wyrmgus start
727 	} else if (!strcmp(state, "overlord")) {
728 		SendCommandDiplomacy(base, DiplomacyOverlord, plynr);
729 	} else if (!strcmp(state, "vassal")) {
730 		SendCommandDiplomacy(base, DiplomacyVassal, plynr);
731 	//Wyrmgus end
732 	}
733 	return 0;
734 }
735 
736 /**
737 **  Change the diplomacy from ThisPlayer to another player.
738 **
739 **  @param l  Lua state.
740 */
CclDiplomacy(lua_State * l)741 static int CclDiplomacy(lua_State *l)
742 {
743 	lua_pushnumber(l, ThisPlayer->Index);
744 	lua_insert(l, 1);
745 	return CclSetDiplomacy(l);
746 }
747 
748 /**
749 **  Change the shared vision from player to another player.
750 **
751 **  @param l  Lua state.
752 **
753 **  @return   FIXME: should return old state.
754 */
CclSetSharedVision(lua_State * l)755 static int CclSetSharedVision(lua_State *l)
756 {
757 	LuaCheckArgs(l, 3);
758 
759 	const int base = LuaToNumber(l, 1);
760 	const bool shared = LuaToBoolean(l, 2);
761 	const int plynr = LuaToNumber(l, 3);
762 
763 	SendCommandSharedVision(base, shared, plynr);
764 
765 	return 0;
766 }
767 
768 /**
769 **  Change the shared vision from ThisPlayer to another player.
770 **
771 **  @param l  Lua state.
772 */
CclSharedVision(lua_State * l)773 static int CclSharedVision(lua_State *l)
774 {
775 	lua_pushnumber(l, ThisPlayer->Index);
776 	lua_insert(l, 1);
777 	return CclSetSharedVision(l);
778 }
779 
780 //Wyrmgus start
781 /**
782 **  Define a civilization.
783 **
784 **  @param l  Lua state.
785 */
CclDefineCivilization(lua_State * l)786 static int CclDefineCivilization(lua_State *l)
787 {
788 	LuaCheckArgs(l, 2);
789 	if (!lua_istable(l, 2)) {
790 		LuaError(l, "incorrect argument (expected table)");
791 	}
792 
793 	std::string civilization_name = LuaToString(l, 1);
794 	CCivilization *civilization = CCivilization::GetOrAddCivilization(civilization_name);
795 	int civilization_id = civilization->ID;
796 
797 	//  Parse the list:
798 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
799 		const char *value = LuaToString(l, -2);
800 		if (!strcmp(value, "Display")) {
801 			PlayerRaces.Display[civilization_id] = LuaToString(l, -1);
802 		} else if (!strcmp(value, "Description")) {
803 			civilization->Description = LuaToString(l, -1);
804 		} else if (!strcmp(value, "Quote")) {
805 			civilization->Quote = LuaToString(l, -1);
806 		} else if (!strcmp(value, "Background")) {
807 			civilization->Background = LuaToString(l, -1);
808 		} else if (!strcmp(value, "Adjective")) {
809 			civilization->Adjective = LuaToString(l, -1);
810 		} else if (!strcmp(value, "Visible")) {
811 			PlayerRaces.Visible[civilization_id] = LuaToBoolean(l, -1);
812 		} else if (!strcmp(value, "Playable")) {
813 			PlayerRaces.Playable[civilization_id] = LuaToBoolean(l, -1);
814 		} else if (!strcmp(value, "Species")) {
815 			PlayerRaces.Species[civilization_id] = LuaToString(l, -1);
816 		} else if (!strcmp(value, "ParentCivilization")) {
817 			civilization->ParentCivilization = CCivilization::GetCivilization(LuaToString(l, -1));
818 		} else if (!strcmp(value, "Language")) {
819 			CLanguage *language = PlayerRaces.GetLanguage(LuaToString(l, -1));
820 			if (language) {
821 				civilization->Language = language;
822 				language->UsedByCivilizationOrFaction = true;
823 			} else {
824 				LuaError(l, "Language not found.");
825 			}
826 		} else if (!strcmp(value, "Calendar")) {
827 			CCalendar *calendar = CCalendar::GetCalendar(LuaToString(l, -1));
828 			civilization->Calendar = calendar;
829 		} else if (!strcmp(value, "Currency")) {
830 			CCurrency *currency = CCurrency::GetCurrency(LuaToString(l, -1));
831 			civilization->Currency = currency;
832 		} else if (!strcmp(value, "DefaultColor")) {
833 			PlayerRaces.DefaultColor[civilization_id] = LuaToString(l, -1);
834 		} else if (!strcmp(value, "CivilizationUpgrade")) {
835 			PlayerRaces.CivilizationUpgrades[civilization_id] = LuaToString(l, -1);
836 		} else if (!strcmp(value, "DevelopsFrom")) {
837 			if (!lua_istable(l, -1)) {
838 				LuaError(l, "incorrect argument");
839 			}
840 
841 			const int subargs = lua_rawlen(l, -1);
842 			for (int j = 0; j < subargs; ++j) {
843 				std::string originary_civilization_name = LuaToString(l, -1, j + 1);
844 				CCivilization *originary_civilization = CCivilization::GetCivilization(originary_civilization_name);
845 				if (originary_civilization) {
846 					PlayerRaces.DevelopsFrom[civilization_id].push_back(originary_civilization->ID);
847 					PlayerRaces.DevelopsTo[originary_civilization->ID].push_back(civilization_id);
848 				}
849 			}
850 		} else if (!strcmp(value, "ButtonIcons")) {
851 			if (!lua_istable(l, -1)) {
852 				LuaError(l, "incorrect argument");
853 			}
854 			const int subargs = lua_rawlen(l, -1);
855 			for (int j = 0; j < subargs; ++j) {
856 				std::string button_action_name = LuaToString(l, -1, j + 1);
857 				int button_action = GetButtonActionIdByName(button_action_name);
858 				if (button_action != -1) {
859 					++j;
860 					PlayerRaces.ButtonIcons[civilization_id][button_action].Name = LuaToString(l, -1, j + 1);
861 					PlayerRaces.ButtonIcons[civilization_id][button_action].Icon = nullptr;
862 					PlayerRaces.ButtonIcons[civilization_id][button_action].Load();
863 				} else {
864 					LuaError(l, "Button action \"%s\" doesn't exist." _C_ button_action_name.c_str());
865 				}
866 			}
867 		} else if (!strcmp(value, "ForceTypeWeights")) {
868 			if (!lua_istable(l, -1)) {
869 				LuaError(l, "incorrect argument");
870 			}
871 
872 			civilization->ForceTypeWeights.clear();
873 
874 			const int subargs = lua_rawlen(l, -1);
875 			for (int j = 0; j < subargs; ++j) {
876 				int force_type = GetForceTypeIdByName(LuaToString(l, -1, j + 1));
877 				++j;
878 				civilization->ForceTypeWeights[force_type] = LuaToNumber(l, -1, j + 1);
879 			}
880 		} else if (!strcmp(value, "ForceTemplates")) {
881 			const int args = lua_rawlen(l, -1);
882 			for (int j = 0; j < args; ++j) {
883 				lua_rawgeti(l, -1, j + 1);
884 				CForceTemplate *force = new CForceTemplate;
885 				if (!lua_istable(l, -1)) {
886 					LuaError(l, "incorrect argument (expected table for force templates)");
887 				}
888 				const int subargs = lua_rawlen(l, -1);
889 				for (int k = 0; k < subargs; ++k) {
890 					value = LuaToString(l, -1, k + 1);
891 					++k;
892 					if (!strcmp(value, "force-type")) {
893 						force->ForceType = GetForceTypeIdByName(LuaToString(l, -1, k + 1));
894 						if (force->ForceType == -1) {
895 							LuaError(l, "Force type doesn't exist.");
896 						}
897 						civilization->ForceTemplates[force->ForceType].push_back(force);
898 					} else if (!strcmp(value, "priority")) {
899 						force->Priority = LuaToNumber(l, -1, k + 1);
900 					} else if (!strcmp(value, "weight")) {
901 						force->Weight = LuaToNumber(l, -1, k + 1);
902 					} else if (!strcmp(value, "unit-class")) {
903 						int unit_class = GetOrAddUnitTypeClassIndexByName(LuaToString(l, -1, k + 1));
904 						++k;
905 						int unit_quantity = LuaToNumber(l, -1, k + 1);
906 						force->Units.push_back(std::pair<int, int>(unit_class, unit_quantity));
907 					} else {
908 						printf("\n%s\n", civilization->Ident.c_str());
909 						LuaError(l, "Unsupported tag: %s" _C_ value);
910 					}
911 				}
912 				lua_pop(l, 1);
913 			}
914 			for (std::map<int, std::vector<CForceTemplate *>>::iterator iterator = civilization->ForceTemplates.begin(); iterator != civilization->ForceTemplates.end(); ++iterator) {
915 				std::sort(iterator->second.begin(), iterator->second.end(), [](CForceTemplate *a, CForceTemplate *b) {
916 					return a->Priority > b->Priority;
917 				});
918 			}
919 		} else if (!strcmp(value, "AiBuildingTemplates")) {
920 			const int args = lua_rawlen(l, -1);
921 			for (int j = 0; j < args; ++j) {
922 				lua_rawgeti(l, -1, j + 1);
923 				CAiBuildingTemplate *building_template = new CAiBuildingTemplate;
924 				if (!lua_istable(l, -1)) {
925 					LuaError(l, "incorrect argument (expected table for force templates)");
926 				}
927 				const int subargs = lua_rawlen(l, -1);
928 				for (int k = 0; k < subargs; ++k) {
929 					value = LuaToString(l, -1, k + 1);
930 					++k;
931 					if (!strcmp(value, "unit-class")) {
932 						int unit_class = GetOrAddUnitTypeClassIndexByName(LuaToString(l, -1, k + 1));
933 						building_template->UnitClass = unit_class;
934 						civilization->AiBuildingTemplates.push_back(building_template);
935 					} else if (!strcmp(value, "priority")) {
936 						building_template->Priority = LuaToNumber(l, -1, k + 1);
937 					} else if (!strcmp(value, "per-settlement")) {
938 						building_template->PerSettlement = LuaToBoolean(l, -1, k + 1);
939 					} else {
940 						printf("\n%s\n", civilization->Ident.c_str());
941 						LuaError(l, "Unsupported tag: %s" _C_ value);
942 					}
943 				}
944 				lua_pop(l, 1);
945 			}
946 			std::sort(civilization->AiBuildingTemplates.begin(), civilization->AiBuildingTemplates.end(), [](CAiBuildingTemplate *a, CAiBuildingTemplate *b) {
947 				return a->Priority > b->Priority;
948 			});
949 		} else if (!strcmp(value, "UIFillers")) {
950 			if (!lua_istable(l, -1)) {
951 				LuaError(l, "incorrect argument");
952 			}
953 
954 			PlayerRaces.CivilizationUIFillers[civilization_id].clear();
955 
956 			const int subargs = lua_rawlen(l, -1);
957 			for (int j = 0; j < subargs; ++j) {
958 				CFiller filler = CFiller();
959 				std::string filler_file = LuaToString(l, -1, j + 1);
960 				if (filler_file.empty()) {
961 					LuaError(l, "Filler graphic file is empty.");
962 				}
963 				filler.G = CGraphic::New(filler_file);
964 				++j;
965 				filler.X = LuaToNumber(l, -1, j + 1);
966 				++j;
967 				filler.Y = LuaToNumber(l, -1, j + 1);
968 				PlayerRaces.CivilizationUIFillers[civilization_id].push_back(filler);
969 			}
970 		} else if (!strcmp(value, "UnitSounds")) {
971 			if (!lua_istable(l, -1)) {
972 				LuaError(l, "incorrect argument");
973 			}
974 			const int subargs = lua_rawlen(l, -1);
975 			for (int k = 0; k < subargs; ++k) {
976 				value = LuaToString(l, -1, k + 1);
977 				++k;
978 
979 				if (!strcmp(value, "selected")) {
980 					civilization->UnitSounds.Selected.Name = LuaToString(l, -1, k + 1);
981 				} else if (!strcmp(value, "acknowledge")) {
982 					civilization->UnitSounds.Acknowledgement.Name = LuaToString(l, -1, k + 1);
983 				} else if (!strcmp(value, "attack")) {
984 					civilization->UnitSounds.Attack.Name = LuaToString(l, -1, k + 1);
985 				} else if (!strcmp(value, "idle")) {
986 					civilization->UnitSounds.Idle.Name = LuaToString(l, -1, k + 1);
987 				} else if (!strcmp(value, "build")) {
988 					civilization->UnitSounds.Build.Name = LuaToString(l, -1, k + 1);
989 				} else if (!strcmp(value, "ready")) {
990 					civilization->UnitSounds.Ready.Name = LuaToString(l, -1, k + 1);
991 				} else if (!strcmp(value, "repair")) {
992 					civilization->UnitSounds.Repair.Name = LuaToString(l, -1, k + 1);
993 				} else if (!strcmp(value, "harvest")) {
994 					const std::string name = LuaToString(l, -1, k + 1);
995 					++k;
996 					const int resId = GetResourceIdByName(l, name.c_str());
997 					civilization->UnitSounds.Harvest[resId].Name = LuaToString(l, -1, k + 1);
998 				} else if (!strcmp(value, "help")) {
999 					civilization->UnitSounds.Help.Name = LuaToString(l, -1, k + 1);
1000 				} else if (!strcmp(value, "help-town")) {
1001 					civilization->UnitSounds.HelpTown.Name = LuaToString(l, -1, k + 1);
1002 				} else {
1003 					LuaError(l, "Unsupported sound tag: %s" _C_ value);
1004 				}
1005 			}
1006 		} else if (!strcmp(value, "PersonalNames")) {
1007 			const int args = lua_rawlen(l, -1);
1008 			for (int j = 0; j < args; ++j) {
1009 				int gender_id = GetGenderIdByName(LuaToString(l, -1, j + 1));
1010 				if (gender_id == -1) {
1011 					gender_id = NoGender;
1012 				} else {
1013 					++j;
1014 				}
1015 
1016 				civilization->PersonalNames[gender_id].push_back(LuaToString(l, -1, j + 1));
1017 			}
1018 		} else if (!strcmp(value, "UnitClassNames")) {
1019 			const int args = lua_rawlen(l, -1);
1020 			for (int j = 0; j < args; ++j) {
1021 				std::string class_name = LuaToString(l, -1, j + 1);
1022 				if (class_name.empty()) {
1023 					LuaError(l, "Class is given as a blank string.");
1024 				}
1025 				int class_id = GetOrAddUnitTypeClassIndexByName(class_name);
1026 				++j;
1027 
1028 				civilization->UnitClassNames[class_id].push_back(LuaToString(l, -1, j + 1));
1029 			}
1030 		} else if (!strcmp(value, "FamilyNames")) {
1031 			const int args = lua_rawlen(l, -1);
1032 			for (int j = 0; j < args; ++j) {
1033 				civilization->FamilyNames.push_back(LuaToString(l, -1, j + 1));
1034 			}
1035 		} else if (!strcmp(value, "ProvinceNames")) {
1036 			const int args = lua_rawlen(l, -1);
1037 			for (int j = 0; j < args; ++j) {
1038 				civilization->ProvinceNames.push_back(LuaToString(l, -1, j + 1));
1039 			}
1040 		} else if (!strcmp(value, "ShipNames")) {
1041 			const int args = lua_rawlen(l, -1);
1042 			for (int j = 0; j < args; ++j) {
1043 				civilization->ShipNames.push_back(LuaToString(l, -1, j + 1));
1044 			}
1045 		} else if (!strcmp(value, "MinisterTitles")) {
1046 			if (!lua_istable(l, -1)) {
1047 				LuaError(l, "incorrect argument");
1048 			}
1049 			const int subargs = lua_rawlen(l, -1);
1050 			for (int k = 0; k < subargs; ++k) {
1051 				int title = GetCharacterTitleIdByName(LuaToString(l, -1, k + 1));
1052 				++k;
1053 				int gender = GetGenderIdByName(LuaToString(l, -1, k + 1));
1054 				++k;
1055 				int government_type = GetGovernmentTypeIdByName(LuaToString(l, -1, k + 1));
1056 				++k;
1057 				int faction_tier = GetFactionTierIdByName(LuaToString(l, -1, k + 1));
1058 				++k;
1059 				civilization->MinisterTitles[title][gender][government_type][faction_tier] = LuaToString(l, -1, k + 1);
1060 			}
1061 		} else if (!strcmp(value, "HistoricalUpgrades")) {
1062 			if (!lua_istable(l, -1)) {
1063 				LuaError(l, "incorrect argument");
1064 			}
1065 			const int subargs = lua_rawlen(l, -1);
1066 			for (int j = 0; j < subargs; ++j) {
1067 				CDate date;
1068 				lua_rawgeti(l, -1, j + 1);
1069 				CclGetDate(l, &date);
1070 				lua_pop(l, 1);
1071 				++j;
1072 
1073 				std::string technology_ident = LuaToString(l, -1, j + 1);
1074 				++j;
1075 
1076 				bool has_upgrade = LuaToBoolean(l, -1, j + 1);
1077 
1078 				civilization->HistoricalUpgrades[technology_ident][date] = has_upgrade;
1079 			}
1080 		} else {
1081 			LuaError(l, "Unsupported tag: %s" _C_ value);
1082 		}
1083 	}
1084 
1085 	if (civilization->ParentCivilization) {
1086 		const CCivilization *parent_civilization = civilization->ParentCivilization;
1087 		int parent_civilization_id = parent_civilization->ID;
1088 
1089 		if (PlayerRaces.CivilizationUpgrades[civilization_id].empty() && !PlayerRaces.CivilizationUpgrades[parent_civilization_id].empty()) { //if the civilization has no civilization upgrade, inherit that of its parent civilization
1090 			PlayerRaces.CivilizationUpgrades[civilization_id] = PlayerRaces.CivilizationUpgrades[parent_civilization_id];
1091 		}
1092 
1093 		//inherit button icons from the parent civilization, for button actions which none are specified
1094 		for (std::map<int, IconConfig>::iterator iterator = PlayerRaces.ButtonIcons[parent_civilization_id].begin(); iterator != PlayerRaces.ButtonIcons[parent_civilization_id].end(); ++iterator) {
1095 			if (PlayerRaces.ButtonIcons[civilization_id].find(iterator->first) == PlayerRaces.ButtonIcons[civilization_id].end()) {
1096 				PlayerRaces.ButtonIcons[civilization_id][iterator->first] = iterator->second;
1097 			}
1098 		}
1099 
1100 		//inherit historical upgrades from the parent civilization, if no historical data is given for that upgrade for this civilization
1101 		for (std::map<std::string, std::map<CDate, bool>>::const_iterator iterator = parent_civilization->HistoricalUpgrades.begin(); iterator != parent_civilization->HistoricalUpgrades.end(); ++iterator) {
1102 			if (civilization->HistoricalUpgrades.find(iterator->first) == civilization->HistoricalUpgrades.end()) {
1103 				civilization->HistoricalUpgrades[iterator->first] = iterator->second;
1104 			}
1105 		}
1106 
1107 		//unit sounds
1108 		if (civilization->UnitSounds.Selected.Name.empty()) {
1109 			civilization->UnitSounds.Selected = parent_civilization->UnitSounds.Selected;
1110 		}
1111 		if (civilization->UnitSounds.Acknowledgement.Name.empty()) {
1112 			civilization->UnitSounds.Acknowledgement = parent_civilization->UnitSounds.Acknowledgement;
1113 		}
1114 		if (civilization->UnitSounds.Attack.Name.empty()) {
1115 			civilization->UnitSounds.Attack = parent_civilization->UnitSounds.Attack;
1116 		}
1117 		if (civilization->UnitSounds.Idle.Name.empty()) {
1118 			civilization->UnitSounds.Idle = parent_civilization->UnitSounds.Idle;
1119 		}
1120 		if (civilization->UnitSounds.Hit.Name.empty()) {
1121 			civilization->UnitSounds.Hit = parent_civilization->UnitSounds.Hit;
1122 		}
1123 		if (civilization->UnitSounds.Miss.Name.empty()) {
1124 			civilization->UnitSounds.Miss = parent_civilization->UnitSounds.Miss;
1125 		}
1126 		if (civilization->UnitSounds.FireMissile.Name.empty()) {
1127 			civilization->UnitSounds.FireMissile = parent_civilization->UnitSounds.FireMissile;
1128 		}
1129 		if (civilization->UnitSounds.Step.Name.empty()) {
1130 			civilization->UnitSounds.Step = parent_civilization->UnitSounds.Step;
1131 		}
1132 		if (civilization->UnitSounds.StepDirt.Name.empty()) {
1133 			civilization->UnitSounds.StepDirt = parent_civilization->UnitSounds.StepDirt;
1134 		}
1135 		if (civilization->UnitSounds.StepGrass.Name.empty()) {
1136 			civilization->UnitSounds.StepGrass = parent_civilization->UnitSounds.StepGrass;
1137 		}
1138 		if (civilization->UnitSounds.StepGravel.Name.empty()) {
1139 			civilization->UnitSounds.StepGravel = parent_civilization->UnitSounds.StepGravel;
1140 		}
1141 		if (civilization->UnitSounds.StepMud.Name.empty()) {
1142 			civilization->UnitSounds.StepMud = parent_civilization->UnitSounds.StepMud;
1143 		}
1144 		if (civilization->UnitSounds.StepStone.Name.empty()) {
1145 			civilization->UnitSounds.StepStone = parent_civilization->UnitSounds.StepStone;
1146 		}
1147 		if (civilization->UnitSounds.Used.Name.empty()) {
1148 			civilization->UnitSounds.Used = parent_civilization->UnitSounds.Used;
1149 		}
1150 		if (civilization->UnitSounds.Build.Name.empty()) {
1151 			civilization->UnitSounds.Build = parent_civilization->UnitSounds.Build;
1152 		}
1153 		if (civilization->UnitSounds.Ready.Name.empty()) {
1154 			civilization->UnitSounds.Ready = parent_civilization->UnitSounds.Ready;
1155 		}
1156 		if (civilization->UnitSounds.Repair.Name.empty()) {
1157 			civilization->UnitSounds.Repair = parent_civilization->UnitSounds.Repair;
1158 		}
1159 		for (unsigned int j = 0; j < MaxCosts; ++j) {
1160 			if (civilization->UnitSounds.Harvest[j].Name.empty()) {
1161 				civilization->UnitSounds.Harvest[j] = parent_civilization->UnitSounds.Harvest[j];
1162 			}
1163 		}
1164 		if (civilization->UnitSounds.Help.Name.empty()) {
1165 			civilization->UnitSounds.Help = parent_civilization->UnitSounds.Help;
1166 		}
1167 		if (civilization->UnitSounds.HelpTown.Name.empty()) {
1168 			civilization->UnitSounds.HelpTown = parent_civilization->UnitSounds.HelpTown;
1169 		}
1170 	}
1171 
1172 	if (PlayerRaces.ButtonIcons[civilization_id].find(ButtonMove) != PlayerRaces.ButtonIcons[civilization_id].end()) {
1173 		std::string button_definition = "DefineButton({\n";
1174 		button_definition += "\tPos = 1,\n";
1175 		button_definition += "\tAction = \"move\",\n";
1176 		button_definition += "\tPopup = \"popup-commands\",\n";
1177 		button_definition += "\tKey = \"m\",\n";
1178 		button_definition += "\tHint = _(\"~!Move\"),\n";
1179 		button_definition += "\tForUnit = {\"" + PlayerRaces.Name[civilization_id] + "-group\"},\n";
1180 		button_definition += "})";
1181 		CclCommand(button_definition);
1182 	}
1183 
1184 	if (PlayerRaces.ButtonIcons[civilization_id].find(ButtonStop) != PlayerRaces.ButtonIcons[civilization_id].end()) {
1185 		std::string button_definition = "DefineButton({\n";
1186 		button_definition += "\tPos = 2,\n";
1187 		button_definition += "\tAction = \"stop\",\n";
1188 		button_definition += "\tPopup = \"popup-commands\",\n";
1189 		button_definition += "\tKey = \"s\",\n";
1190 		button_definition += "\tHint = _(\"~!Stop\"),\n";
1191 		button_definition += "\tForUnit = {\"" + PlayerRaces.Name[civilization_id] + "-group\"},\n";
1192 		button_definition += "})";
1193 		CclCommand(button_definition);
1194 	}
1195 
1196 	if (PlayerRaces.ButtonIcons[civilization_id].find(ButtonAttack) != PlayerRaces.ButtonIcons[civilization_id].end()) {
1197 		std::string button_definition = "DefineButton({\n";
1198 		button_definition += "\tPos = 3,\n";
1199 		button_definition += "\tAction = \"attack\",\n";
1200 		button_definition += "\tPopup = \"popup-commands\",\n";
1201 		button_definition += "\tKey = \"a\",\n";
1202 		button_definition += "\tHint = _(\"~!Attack\"),\n";
1203 		button_definition += "\tForUnit = {\"" + PlayerRaces.Name[civilization_id] + "-group\"},\n";
1204 		button_definition += "})";
1205 		CclCommand(button_definition);
1206 	}
1207 
1208 	if (PlayerRaces.ButtonIcons[civilization_id].find(ButtonPatrol) != PlayerRaces.ButtonIcons[civilization_id].end()) {
1209 		std::string button_definition = "DefineButton({\n";
1210 		button_definition += "\tPos = 4,\n";
1211 		button_definition += "\tAction = \"patrol\",\n";
1212 		button_definition += "\tPopup = \"popup-commands\",\n";
1213 		button_definition += "\tKey = \"p\",\n";
1214 		button_definition += "\tHint = _(\"~!Patrol\"),\n";
1215 		button_definition += "\tForUnit = {\"" + PlayerRaces.Name[civilization_id] + "-group\"},\n";
1216 		button_definition += "})";
1217 		CclCommand(button_definition);
1218 	}
1219 
1220 	if (PlayerRaces.ButtonIcons[civilization_id].find(ButtonStandGround) != PlayerRaces.ButtonIcons[civilization_id].end()) {
1221 		std::string button_definition = "DefineButton({\n";
1222 		button_definition += "\tPos = 5,\n";
1223 		button_definition += "\tAction = \"stand-ground\",\n";
1224 		button_definition += "\tPopup = \"popup-commands\",\n";
1225 		button_definition += "\tKey = \"t\",\n";
1226 		button_definition += "\tHint = _(\"S~!tand Ground\"),\n";
1227 		button_definition += "\tForUnit = {\"" + PlayerRaces.Name[civilization_id] + "-group\"},\n";
1228 		button_definition += "})";
1229 		CclCommand(button_definition);
1230 	}
1231 
1232 	return 0;
1233 }
1234 
1235 /**
1236 **  Define a word for a particular language.
1237 **
1238 **  @param l  Lua state.
1239 */
CclDefineLanguageWord(lua_State * l)1240 static int CclDefineLanguageWord(lua_State *l)
1241 {
1242 	LuaCheckArgs(l, 2);
1243 	if (!lua_istable(l, 2)) {
1244 		LuaError(l, "incorrect argument (expected table)");
1245 	}
1246 
1247 	LanguageWord *word = new LanguageWord;
1248 	word->Word = LuaToString(l, 1);
1249 
1250 	LanguageWord *replaces = nullptr;
1251 
1252 	//  Parse the list:
1253 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
1254 		const char *value = LuaToString(l, -2);
1255 
1256 		if (!strcmp(value, "Language")) {
1257 			CLanguage *language = PlayerRaces.GetLanguage(LuaToString(l, -1));
1258 
1259 			if (language) {
1260 				language->LanguageWords.push_back(word);
1261 				word->Language = language;
1262 
1263 				for (size_t i = 0; i < language->Dialects.size(); ++i) { //copy the word over for dialects
1264 					language->Dialects[i]->LanguageWords.push_back(word);
1265 				}
1266 			} else {
1267 				LuaError(l, "Language not found.");
1268 			}
1269 		} else if (!strcmp(value, "Meanings")) {
1270 			if (!lua_istable(l, -1)) {
1271 				LuaError(l, "incorrect argument");
1272 			}
1273 			const int subargs = lua_rawlen(l, -1);
1274 			for (int j = 0; j < subargs; ++j) {
1275 				word->Meanings.push_back(LuaToString(l, -1, j + 1));
1276 			}
1277 		} else if (!strcmp(value, "Type")) {
1278 			std::string word_type_name = LuaToString(l, -1);
1279 			int word_type = GetWordTypeIdByName(word_type_name);
1280 			if (word_type != -1) {
1281 				word->Type = word_type;
1282 			} else {
1283 				LuaError(l, "Word type \"%s\" doesn't exist." _C_ word_type_name.c_str());
1284 			}
1285 		} else if (!strcmp(value, "DerivesFrom")) {
1286 			if (!lua_istable(l, -1)) {
1287 				LuaError(l, "incorrect argument");
1288 			}
1289 			int j = 0;
1290 			CLanguage *derives_from_language = PlayerRaces.GetLanguage(LuaToString(l, -1, j + 1));
1291 			++j;
1292 			int derives_from_word_type = GetWordTypeIdByName(LuaToString(l, -1, j + 1));
1293 			++j;
1294 
1295 			std::vector<std::string> word_meanings;
1296 			lua_rawgeti(l, -1, j + 1);
1297 			if (lua_istable(l, -1)) {
1298 				const int subargs = lua_rawlen(l, -1);
1299 				for (int k = 0; k < subargs; ++k) {
1300 					word_meanings.push_back(LuaToString(l, -1, k + 1));
1301 				}
1302 
1303 				++j;
1304 			}
1305 			lua_pop(l, 1);
1306 
1307 			if (derives_from_language && derives_from_word_type != -1) {
1308 				std::string derives_from_word = LuaToString(l, -1, j + 1);
1309 				word->DerivesFrom = derives_from_language->GetWord(derives_from_word, derives_from_word_type, word_meanings);
1310 
1311 				if (word->DerivesFrom != nullptr) {
1312 					word->DerivesFrom->DerivesTo.push_back(word);
1313 				} else {
1314 					LuaError(l, "Word \"%s\" is set to derive from \"%s\" (%s, %s), but the latter doesn't exist" _C_ word->Word.c_str() _C_ derives_from_word.c_str() _C_ derives_from_language->Ident.c_str() _C_ GetWordTypeNameById(derives_from_word_type).c_str());
1315 				}
1316 			} else {
1317 				LuaError(l, "Word \"%s\"'s derives from is incorrectly set, as either the language or the word type set for the original word given is incorrect" _C_ word->Word.c_str());
1318 			}
1319 		} else if (!strcmp(value, "Replaces")) {
1320 			if (!lua_istable(l, -1)) {
1321 				LuaError(l, "incorrect argument");
1322 			}
1323 			int j = 0;
1324 			CLanguage *replaces_language = PlayerRaces.GetLanguage(LuaToString(l, -1, j + 1));
1325 			++j;
1326 			int replaces_word_type = GetWordTypeIdByName(LuaToString(l, -1, j + 1));
1327 			++j;
1328 
1329 			std::vector<std::string> word_meanings;
1330 			lua_rawgeti(l, -1, j + 1);
1331 			if (lua_istable(l, -1)) {
1332 				const int subargs = lua_rawlen(l, -1);
1333 				for (int k = 0; k < subargs; ++k) {
1334 					word_meanings.push_back(LuaToString(l, -1, k + 1));
1335 				}
1336 
1337 				++j;
1338 			}
1339 			lua_pop(l, 1);
1340 
1341 			if (replaces_language && replaces_word_type != -1) {
1342 				std::string replaces_word = LuaToString(l, -1, j + 1);
1343 				replaces = replaces_language->GetWord(replaces_word, replaces_word_type, word_meanings);
1344 
1345 				if (replaces == nullptr) {
1346 					LuaError(l, "Word \"%s\" is set to replace \"%s\" (%s, %s), but the latter doesn't exist" _C_ word->Word.c_str() _C_ replaces_word.c_str() _C_ replaces_language->Ident.c_str() _C_ GetWordTypeNameById(replaces_word_type).c_str());
1347 				}
1348 			} else {
1349 				LuaError(l, "Word \"%s\"'s replace is incorrectly set, as either the language or the word type set for the original word given is incorrect" _C_ word->Word.c_str());
1350 			}
1351 		} else if (!strcmp(value, "CompoundElements")) {
1352 			if (!lua_istable(l, -1)) {
1353 				LuaError(l, "incorrect argument");
1354 			}
1355 			const int subargs = lua_rawlen(l, -1);
1356 			for (int j = 0; j < subargs; ++j) {
1357 				std::string affix_type_name = LuaToString(l, -1, j + 1);
1358 				int affix_type = GetAffixTypeIdByName(affix_type_name);
1359 				if (affix_type == -1) {
1360 					LuaError(l, "Affix type \"%s\" doesn't exist." _C_ affix_type_name.c_str());
1361 				}
1362 				++j;
1363 
1364 				CLanguage *affix_language = PlayerRaces.GetLanguage(LuaToString(l, -1, j + 1)); // should be the same language as that of the word, but needs to be specified since the word's language may not have been set yet
1365 				++j;
1366 				int affix_word_type = GetWordTypeIdByName(LuaToString(l, -1, j + 1));
1367 				++j;
1368 
1369 				std::vector<std::string> word_meanings;
1370 				lua_rawgeti(l, -1, j + 1);
1371 				if (lua_istable(l, -1)) {
1372 					const int subargs = lua_rawlen(l, -1);
1373 					for (int k = 0; k < subargs; ++k) {
1374 						word_meanings.push_back(LuaToString(l, -1, k + 1));
1375 					}
1376 
1377 					++j;
1378 				}
1379 				lua_pop(l, 1);
1380 
1381 				if (affix_language && affix_word_type != -1) {
1382 					std::string affix_word = LuaToString(l, -1, j + 1);
1383 					word->CompoundElements[affix_type] = affix_language->GetWord(affix_word, affix_word_type, word_meanings);
1384 
1385 					if (word->CompoundElements[affix_type] != nullptr) {
1386 						word->CompoundElements[affix_type]->CompoundElementOf[affix_type].push_back(word);
1387 					} else {
1388 						LuaError(l, "Word \"%s\" is set to be a compound formed by \"%s\" (%s, %s), but the latter doesn't exist" _C_ word->Word.c_str() _C_ affix_word.c_str() _C_ affix_language->Ident.c_str() _C_ GetWordTypeNameById(affix_word_type).c_str());
1389 					}
1390 				} else {
1391 					LuaError(l, "Word \"%s\"'s compound elements are incorrectly set, as either the language or the word type set for one of the element words given is incorrect" _C_ word->Word.c_str());
1392 				}
1393 			}
1394 		} else if (!strcmp(value, "Gender")) {
1395 			std::string grammatical_gender_name = LuaToString(l, -1);
1396 			int grammatical_gender = GetGrammaticalGenderIdByName(grammatical_gender_name);
1397 			if (grammatical_gender != -1) {
1398 				word->Gender = grammatical_gender;
1399 			} else {
1400 				LuaError(l, "Grammatical gender \"%s\" doesn't exist." _C_ grammatical_gender_name.c_str());
1401 			}
1402 		} else if (!strcmp(value, "GrammaticalNumber")) {
1403 			std::string grammatical_number_name = LuaToString(l, -1);
1404 			int grammatical_number = GetGrammaticalNumberIdByName(grammatical_number_name);
1405 			if (grammatical_number != -1) {
1406 				word->GrammaticalNumber = grammatical_number;
1407 			} else {
1408 				LuaError(l, "Grammatical number \"%s\" doesn't exist." _C_ grammatical_number_name.c_str());
1409 			}
1410 		} else if (!strcmp(value, "Archaic")) {
1411 			word->Archaic = LuaToBoolean(l, -1);
1412 		} else if (!strcmp(value, "NumberCaseInflections")) {
1413 			if (!lua_istable(l, -1)) {
1414 				LuaError(l, "incorrect argument");
1415 			}
1416 			const int subargs = lua_rawlen(l, -1);
1417 			for (int j = 0; j < subargs; ++j) {
1418 				std::string grammatical_number_name = LuaToString(l, -1, j + 1);
1419 				int grammatical_number = GetGrammaticalNumberIdByName(grammatical_number_name);
1420 				if (grammatical_number == -1) {
1421 					LuaError(l, "Grammatical number \"%s\" doesn't exist." _C_ grammatical_number_name.c_str());
1422 				}
1423 				++j;
1424 
1425 				std::string grammatical_case_name = LuaToString(l, -1, j + 1);
1426 				int grammatical_case = GetGrammaticalCaseIdByName(grammatical_case_name);
1427 				if (grammatical_case == -1) {
1428 					LuaError(l, "Grammatical case \"%s\" doesn't exist." _C_ grammatical_case_name.c_str());
1429 				}
1430 				++j;
1431 
1432 				word->NumberCaseInflections[std::tuple<int, int>(grammatical_number, grammatical_case)] = LuaToString(l, -1, j + 1);
1433 			}
1434 		} else if (!strcmp(value, "NumberPersonTenseMoodInflections")) {
1435 			if (!lua_istable(l, -1)) {
1436 				LuaError(l, "incorrect argument");
1437 			}
1438 			const int subargs = lua_rawlen(l, -1);
1439 			for (int j = 0; j < subargs; ++j) {
1440 				std::string grammatical_number_name = LuaToString(l, -1, j + 1);
1441 				int grammatical_number = GetGrammaticalNumberIdByName(grammatical_number_name);
1442 				if (grammatical_number == -1) {
1443 					LuaError(l, "Grammatical number \"%s\" doesn't exist." _C_ grammatical_number_name.c_str());
1444 				}
1445 				++j;
1446 
1447 				std::string grammatical_person_name = LuaToString(l, -1, j + 1);
1448 				int grammatical_person = GetGrammaticalPersonIdByName(grammatical_person_name);
1449 				if (grammatical_person == -1) {
1450 					LuaError(l, "Grammatical person \"%s\" doesn't exist." _C_ grammatical_person_name.c_str());
1451 				}
1452 				++j;
1453 
1454 				std::string grammatical_tense_name = LuaToString(l, -1, j + 1);
1455 				int grammatical_tense = GetGrammaticalTenseIdByName(grammatical_tense_name);
1456 				if (grammatical_tense == -1) {
1457 					LuaError(l, "Grammatical tense \"%s\" doesn't exist." _C_ grammatical_tense_name.c_str());
1458 				}
1459 				++j;
1460 
1461 				std::string grammatical_mood_name = LuaToString(l, -1, j + 1);
1462 				int grammatical_mood = GetGrammaticalMoodIdByName(grammatical_mood_name);
1463 				if (grammatical_mood == -1) {
1464 					LuaError(l, "Grammatical mood \"%s\" doesn't exist." _C_ grammatical_mood_name.c_str());
1465 				}
1466 				++j;
1467 
1468 				word->NumberPersonTenseMoodInflections[std::tuple<int, int, int, int>(grammatical_number, grammatical_person, grammatical_tense, grammatical_mood)] = LuaToString(l, -1, j + 1);
1469 			}
1470 		} else if (!strcmp(value, "ComparisonDegreeCaseInflections")) {
1471 			if (!lua_istable(l, -1)) {
1472 				LuaError(l, "incorrect argument");
1473 			}
1474 			const int subargs = lua_rawlen(l, -1);
1475 			for (int j = 0; j < subargs; ++j) {
1476 				std::string comparison_degree_name = LuaToString(l, -1, j + 1);
1477 				int comparison_degree = GetComparisonDegreeIdByName(comparison_degree_name);
1478 				if (comparison_degree == -1) {
1479 					LuaError(l, "Comparison degree \"%s\" doesn't exist." _C_ comparison_degree_name.c_str());
1480 				}
1481 				++j;
1482 
1483 				int grammatical_case = GrammaticalCaseNoCase;
1484 				if (GetGrammaticalCaseIdByName(LuaToString(l, -1, j + 1)) != -1) {
1485 					std::string grammatical_case_name = LuaToString(l, -1, j + 1);
1486 					grammatical_case = GetGrammaticalCaseIdByName(grammatical_case_name);
1487 					if (grammatical_case == -1) {
1488 						LuaError(l, "Grammatical case \"%s\" doesn't exist." _C_ grammatical_case_name.c_str());
1489 					}
1490 					++j;
1491 				}
1492 
1493 				word->ComparisonDegreeCaseInflections[comparison_degree][grammatical_case] = LuaToString(l, -1, j + 1);
1494 			}
1495 		} else if (!strcmp(value, "Participles")) {
1496 			if (!lua_istable(l, -1)) {
1497 				LuaError(l, "incorrect argument");
1498 			}
1499 			const int subargs = lua_rawlen(l, -1);
1500 			for (int j = 0; j < subargs; ++j) {
1501 				std::string grammatical_tense_name = LuaToString(l, -1, j + 1);
1502 				int grammatical_tense = GetGrammaticalTenseIdByName(grammatical_tense_name);
1503 				if (grammatical_tense == -1) {
1504 					LuaError(l, "Grammatical tense \"%s\" doesn't exist." _C_ grammatical_tense_name.c_str());
1505 				}
1506 				++j;
1507 
1508 				word->Participles[grammatical_tense] = LuaToString(l, -1, j + 1);
1509 			}
1510 		//noun-specific variables
1511 		} else if (!strcmp(value, "Uncountable")) {
1512 			word->Uncountable = LuaToBoolean(l, -1);
1513 		//pronoun and article-specific variables
1514 		} else if (!strcmp(value, "Nominative")) {
1515 			word->Nominative = LuaToString(l, -1);
1516 		} else if (!strcmp(value, "Accusative")) {
1517 			word->Accusative = LuaToString(l, -1);
1518 		} else if (!strcmp(value, "Dative")) {
1519 			word->Dative = LuaToString(l, -1);
1520 		} else if (!strcmp(value, "Genitive")) {
1521 			word->Genitive = LuaToString(l, -1);
1522 		//article-specific variables
1523 		} else if (!strcmp(value, "ArticleType")) {
1524 			std::string article_type_name = LuaToString(l, -1);
1525 			int article_type = GetArticleTypeIdByName(article_type_name);
1526 			if (article_type != -1) {
1527 				word->ArticleType = article_type;
1528 			} else {
1529 				LuaError(l, "Article type \"%s\" doesn't exist." _C_ article_type_name.c_str());
1530 			}
1531 		//numeral-specific variables
1532 		} else if (!strcmp(value, "Number")) {
1533 			word->Number = LuaToNumber(l, -1);
1534 		//type name variables
1535 		} else if (!strcmp(value, "Mod")) {
1536 			word->Mod = LuaToString(l, -1);
1537 		} else if (!strcmp(value, "MapWord")) { //to keep backwards compatibility
1538 			word->Mod = Map.Info.Filename;
1539 		} else {
1540 			LuaError(l, "Unsupported tag: %s" _C_ value);
1541 		}
1542 	}
1543 
1544 	if (!word->Language) {
1545 		LuaError(l, "Word \"%s\" has not been assigned to any language" _C_ word->Word.c_str());
1546 	}
1547 
1548 	if (word->Type == -1) {
1549 		LuaError(l, "Word \"%s\" has no type" _C_ word->Word.c_str());
1550 	}
1551 
1552 	if (replaces != nullptr) {
1553 		word->Language->RemoveWord(replaces);
1554 	}
1555 
1556 	return 0;
1557 }
1558 
1559 /**
1560 **  Get a civilization's data.
1561 **
1562 **  @param l  Lua state.
1563 */
CclGetCivilizationData(lua_State * l)1564 static int CclGetCivilizationData(lua_State *l)
1565 {
1566 	if (lua_gettop(l) < 2) {
1567 		LuaError(l, "incorrect argument");
1568 	}
1569 	std::string civilization_name = LuaToString(l, 1);
1570 	CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1571 	if (!civilization) {
1572 		return 0;
1573 	}
1574 	int civilization_id = civilization->ID;
1575 
1576 	const char *data = LuaToString(l, 2);
1577 
1578 	if (!strcmp(data, "Display")) {
1579 		lua_pushstring(l, PlayerRaces.Display[civilization_id].c_str());
1580 		return 1;
1581 	} else if (!strcmp(data, "Description")) {
1582 		lua_pushstring(l, civilization->Description.c_str());
1583 		return 1;
1584 	} else if (!strcmp(data, "Quote")) {
1585 		lua_pushstring(l, civilization->Quote.c_str());
1586 		return 1;
1587 	} else if (!strcmp(data, "Background")) {
1588 		lua_pushstring(l, civilization->Background.c_str());
1589 		return 1;
1590 	} else if (!strcmp(data, "Adjective")) {
1591 		if (!civilization->Adjective.empty()) {
1592 			lua_pushstring(l, civilization->Adjective.c_str());
1593 		} else {
1594 			lua_pushstring(l, PlayerRaces.Display[civilization_id].c_str());
1595 		}
1596 		return 1;
1597 	} else if (!strcmp(data, "Playable")) {
1598 		lua_pushboolean(l, PlayerRaces.Playable[civilization_id]);
1599 		return 1;
1600 	} else if (!strcmp(data, "Species")) {
1601 		lua_pushstring(l, PlayerRaces.Species[civilization_id].c_str());
1602 		return 1;
1603 	} else if (!strcmp(data, "ParentCivilization")) {
1604 		if (civilization->ParentCivilization) {
1605 			lua_pushstring(l, PlayerRaces.Name[civilization->ParentCivilization->ID].c_str());
1606 		} else {
1607 			lua_pushstring(l, "");
1608 		}
1609 		return 1;
1610 	} else if (!strcmp(data, "Language")) {
1611 		CLanguage *language = PlayerRaces.GetCivilizationLanguage(civilization_id);
1612 		if (language) {
1613 			lua_pushstring(l, language->Ident.c_str());
1614 		} else {
1615 			lua_pushstring(l, "");
1616 		}
1617 		return 1;
1618 	} else if (!strcmp(data, "DefaultColor")) {
1619 		lua_pushstring(l, PlayerRaces.DefaultColor[civilization_id].c_str());
1620 		return 1;
1621 	} else if (!strcmp(data, "CivilizationUpgrade")) {
1622 		lua_pushstring(l, PlayerRaces.CivilizationUpgrades[civilization_id].c_str());
1623 		return 1;
1624 	} else if (!strcmp(data, "DevelopsFrom")) {
1625 		lua_createtable(l, PlayerRaces.DevelopsFrom[civilization_id].size(), 0);
1626 		for (size_t i = 1; i <= PlayerRaces.DevelopsFrom[civilization_id].size(); ++i)
1627 		{
1628 			lua_pushstring(l, PlayerRaces.Name[PlayerRaces.DevelopsFrom[civilization_id][i-1]].c_str());
1629 			lua_rawseti(l, -2, i);
1630 		}
1631 		return 1;
1632 	} else if (!strcmp(data, "DevelopsTo")) {
1633 		lua_createtable(l, PlayerRaces.DevelopsTo[civilization_id].size(), 0);
1634 		for (size_t i = 1; i <= PlayerRaces.DevelopsTo[civilization_id].size(); ++i)
1635 		{
1636 			lua_pushstring(l, PlayerRaces.Name[PlayerRaces.DevelopsTo[civilization_id][i-1]].c_str());
1637 			lua_rawseti(l, -2, i);
1638 		}
1639 		return 1;
1640 	} else if (!strcmp(data, "Factions")) {
1641 		bool is_mod = false;
1642 		if (lua_gettop(l) >= 3) {
1643 			is_mod = true;
1644 		}
1645 
1646 		std::string mod_file;
1647 
1648 		if (is_mod) {
1649 			mod_file = LuaToString(l, 3);
1650 		}
1651 
1652 		std::vector<std::string> factions;
1653 		for (size_t i = 0; i < PlayerRaces.Factions.size(); ++i)
1654 		{
1655 			if (PlayerRaces.Factions[i]->Civilization != civilization) {
1656 				continue;
1657 			}
1658 
1659 			if (!is_mod || PlayerRaces.Factions[i]->Mod == mod_file) {
1660 				factions.push_back(PlayerRaces.Factions[i]->Ident);
1661 			}
1662 		}
1663 
1664 		lua_createtable(l, factions.size(), 0);
1665 		for (size_t i = 1; i <= factions.size(); ++i)
1666 		{
1667 			lua_pushstring(l, factions[i-1].c_str());
1668 			lua_rawseti(l, -2, i);
1669 		}
1670 		return 1;
1671 	} else if (!strcmp(data, "Quests")) {
1672 		lua_createtable(l, civilization->Quests.size(), 0);
1673 		for (size_t i = 1; i <= civilization->Quests.size(); ++i)
1674 		{
1675 			lua_pushstring(l, civilization->Quests[i-1]->Ident.c_str());
1676 			lua_rawseti(l, -2, i);
1677 		}
1678 		return 1;
1679 	} else if (!strcmp(data, "ShipNames")) {
1680 		lua_createtable(l, civilization->ShipNames.size(), 0);
1681 		for (size_t i = 1; i <= civilization->ShipNames.size(); ++i)
1682 		{
1683 			lua_pushstring(l, civilization->ShipNames[i-1].c_str());
1684 			lua_rawseti(l, -2, i);
1685 		}
1686 		return 1;
1687 	} else {
1688 		LuaError(l, "Invalid field: %s" _C_ data);
1689 	}
1690 
1691 	return 0;
1692 }
1693 
1694 /**
1695 **  Get a civilization's unit type/upgrade of a certain class.
1696 **
1697 **  @param l  Lua state.
1698 */
CclGetCivilizationClassUnitType(lua_State * l)1699 static int CclGetCivilizationClassUnitType(lua_State *l)
1700 {
1701 	LuaCheckArgs(l, 2);
1702 	std::string class_name = LuaToString(l, 1);
1703 	int class_id = GetUnitTypeClassIndexByName(class_name);
1704 	CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, 2));
1705 	std::string unit_type_ident;
1706 	if (civilization && class_id != -1) {
1707 		int unit_type_id = PlayerRaces.GetCivilizationClassUnitType(civilization->ID, class_id);
1708 		if (unit_type_id != -1) {
1709 			unit_type_ident = UnitTypes[unit_type_id]->Ident;
1710 		}
1711 	}
1712 
1713 	if (unit_type_ident.empty()) { //if wasn't found, see if it is an upgrade class instead
1714 		class_id = GetUpgradeClassIndexByName(class_name);
1715 		if (civilization && class_id != -1) {
1716 			int upgrade_id = PlayerRaces.GetCivilizationClassUpgrade(civilization->ID, class_id);
1717 			if (upgrade_id != -1) {
1718 				unit_type_ident = AllUpgrades[upgrade_id]->Ident;
1719 			}
1720 		}
1721 	}
1722 
1723 	if (!unit_type_ident.empty()) {
1724 		lua_pushstring(l, unit_type_ident.c_str());
1725 	} else {
1726 		lua_pushnil(l);
1727 	}
1728 
1729 	return 1;
1730 }
1731 
1732 
1733 /**
1734 **  Get a faction's unit type/upgrade of a certain class.
1735 **
1736 **  @param l  Lua state.
1737 */
CclGetFactionClassUnitType(lua_State * l)1738 static int CclGetFactionClassUnitType(lua_State *l)
1739 {
1740 	std::string class_name = LuaToString(l, 1);
1741 	int class_id = GetUnitTypeClassIndexByName(class_name);
1742 	int faction_id = -1;
1743 	CFaction *faction = nullptr;
1744 	const int nargs = lua_gettop(l);
1745 	if (nargs == 2) {
1746 		faction = PlayerRaces.GetFaction(LuaToString(l, 2));
1747 		if (faction) {
1748 			faction_id = faction->ID;
1749 		}
1750 	} else if (nargs == 3) {
1751 		//the civilization was the second argument, but it isn't needed anymore
1752 		faction = PlayerRaces.GetFaction(LuaToString(l, 3));
1753 		if (faction) {
1754 			faction_id = faction->ID;
1755 		}
1756 	}
1757 	std::string unit_type_ident;
1758 	if (class_id != -1) {
1759 		int unit_type_id = PlayerRaces.GetFactionClassUnitType(faction_id, class_id);
1760 		if (unit_type_id != -1) {
1761 			unit_type_ident = UnitTypes[unit_type_id]->Ident;
1762 		}
1763 	}
1764 
1765 	if (unit_type_ident.empty()) { //if wasn't found, see if it is an upgrade class instead
1766 		class_id = GetUpgradeClassIndexByName(class_name);
1767 		if (class_id != -1) {
1768 			int upgrade_id = PlayerRaces.GetFactionClassUpgrade(faction_id, class_id);
1769 			if (upgrade_id != -1) {
1770 				unit_type_ident = AllUpgrades[upgrade_id]->Ident;
1771 			}
1772 		}
1773 	}
1774 
1775 	if (!unit_type_ident.empty()) {
1776 		lua_pushstring(l, unit_type_ident.c_str());
1777 	} else {
1778 		lua_pushnil(l);
1779 	}
1780 
1781 	return 1;
1782 }
1783 
1784 /**
1785 **  Define a faction.
1786 **
1787 **  @param l  Lua state.
1788 */
CclDefineFaction(lua_State * l)1789 static int CclDefineFaction(lua_State *l)
1790 {
1791 	LuaCheckArgs(l, 2);
1792 	if (!lua_istable(l, 2)) {
1793 		LuaError(l, "incorrect argument (expected table)");
1794 	}
1795 
1796 	std::string faction_name = LuaToString(l, 1);
1797 	std::string parent_faction;
1798 
1799 	CFaction *faction = PlayerRaces.GetFaction(faction_name);
1800 	if (faction) { // redefinition
1801 		if (faction->ParentFaction != -1) {
1802 			parent_faction = PlayerRaces.Factions[faction->ParentFaction]->Ident;
1803 		}
1804 	} else {
1805 		faction = new CFaction;
1806 		faction->Ident = faction_name;
1807 		faction->ID = PlayerRaces.Factions.size();
1808 		PlayerRaces.Factions.push_back(faction);
1809 		SetFactionStringToIndex(faction->Ident, faction->ID);
1810 	}
1811 
1812 	//  Parse the list:
1813 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
1814 		const char *value = LuaToString(l, -2);
1815 
1816 		if (!strcmp(value, "Civilization")) {
1817 			CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, -1));
1818 			if (civilization) {
1819 				faction->Civilization = civilization;
1820 			}
1821 		} else if (!strcmp(value, "Name")) {
1822 			faction->Name = LuaToString(l, -1);
1823 		} else if (!strcmp(value, "Description")) {
1824 			faction->Description = LuaToString(l, -1);
1825 		} else if (!strcmp(value, "Quote")) {
1826 			faction->Quote = LuaToString(l, -1);
1827 		} else if (!strcmp(value, "Background")) {
1828 			faction->Background = LuaToString(l, -1);
1829 		} else if (!strcmp(value, "Adjective")) {
1830 			faction->Adjective = LuaToString(l, -1);
1831 		} else if (!strcmp(value, "Type")) {
1832 			std::string faction_type_name = LuaToString(l, -1);
1833 			int faction_type = GetFactionTypeIdByName(faction_type_name);
1834 			if (faction_type != -1) {
1835 				faction->Type = faction_type;
1836 			} else {
1837 				LuaError(l, "Faction type \"%s\" doesn't exist." _C_ faction_type_name.c_str());
1838 			}
1839 		} else if (!strcmp(value, "Colors")) {
1840 			if (!lua_istable(l, -1)) {
1841 				LuaError(l, "incorrect argument");
1842 			}
1843 			faction->Colors.clear(); //remove previously defined colors
1844 			const int subargs = lua_rawlen(l, -1);
1845 			for (int k = 0; k < subargs; ++k) {
1846 				std::string color_name = LuaToString(l, -1, k + 1);
1847 				int color = GetPlayerColorIndexByName(color_name);
1848 				if (color != -1) {
1849 					faction->Colors.push_back(color);
1850 				} else {
1851 					LuaError(l, "Player color \"%s\" doesn't exist." _C_ color_name.c_str());
1852 				}
1853 			}
1854 		} else if (!strcmp(value, "DefaultTier")) {
1855 			std::string faction_tier_name = LuaToString(l, -1);
1856 			int faction_tier = GetFactionTierIdByName(faction_tier_name);
1857 			if (faction_tier != -1) {
1858 				faction->DefaultTier = faction_tier;
1859 			} else {
1860 				LuaError(l, "Faction tier \"%s\" doesn't exist." _C_ faction_tier_name.c_str());
1861 			}
1862 		} else if (!strcmp(value, "DefaultGovernmentType")) {
1863 			std::string government_type_name = LuaToString(l, -1);
1864 			int government_type = GetGovernmentTypeIdByName(government_type_name);
1865 			if (government_type != -1) {
1866 				faction->DefaultGovernmentType = government_type;
1867 			} else {
1868 				LuaError(l, "Government type \"%s\" doesn't exist." _C_ government_type_name.c_str());
1869 			}
1870 		} else if (!strcmp(value, "DefaultAI")) {
1871 			faction->DefaultAI = LuaToString(l, -1);
1872 		} else if (!strcmp(value, "ParentFaction")) {
1873 			parent_faction = LuaToString(l, -1);
1874 		} else if (!strcmp(value, "Playable")) {
1875 			faction->Playable = LuaToBoolean(l, -1);
1876 		} else if (!strcmp(value, "DefiniteArticle")) {
1877 			faction->DefiniteArticle = LuaToBoolean(l, -1);
1878 		} else if (!strcmp(value, "Icon")) {
1879 			faction->Icon.Name = LuaToString(l, -1);
1880 			faction->Icon.Icon = nullptr;
1881 			faction->Icon.Load();
1882 			faction->Icon.Icon->Load();
1883 		} else if (!strcmp(value, "Currency")) {
1884 			CCurrency *currency = CCurrency::GetCurrency(LuaToString(l, -1));
1885 			faction->Currency = currency;
1886 		} else if (!strcmp(value, "DevelopsFrom")) {
1887 			if (!lua_istable(l, -1)) {
1888 				LuaError(l, "incorrect argument");
1889 			}
1890 			const int subargs = lua_rawlen(l, -1);
1891 			for (int k = 0; k < subargs; ++k) {
1892 				CFaction *second_faction = PlayerRaces.GetFaction(LuaToString(l, -1, k + 1));
1893 				if (!second_faction) {
1894 					LuaError(l, "Faction doesn't exist.");
1895 				}
1896 				faction->DevelopsFrom.push_back(second_faction);
1897 				second_faction->DevelopsTo.push_back(faction);
1898 			}
1899 		} else if (!strcmp(value, "DevelopsTo")) {
1900 			if (!lua_istable(l, -1)) {
1901 				LuaError(l, "incorrect argument");
1902 			}
1903 			const int subargs = lua_rawlen(l, -1);
1904 			for (int k = 0; k < subargs; ++k) {
1905 				CFaction *second_faction = PlayerRaces.GetFaction(LuaToString(l, -1, k + 1));
1906 				if (!second_faction) {
1907 					LuaError(l, "Faction doesn't exist.");
1908 				}
1909 				faction->DevelopsTo.push_back(second_faction);
1910 				second_faction->DevelopsFrom.push_back(faction);
1911 			}
1912 		} else if (!strcmp(value, "Titles")) {
1913 			if (!lua_istable(l, -1)) {
1914 				LuaError(l, "incorrect argument");
1915 			}
1916 			const int subargs = lua_rawlen(l, -1);
1917 			for (int k = 0; k < subargs; ++k) {
1918 				int government_type = GetGovernmentTypeIdByName(LuaToString(l, -1, k + 1));
1919 				++k;
1920 				int faction_tier = GetFactionTierIdByName(LuaToString(l, -1, k + 1));
1921 				++k;
1922 				faction->Titles[government_type][faction_tier] = LuaToString(l, -1, k + 1);
1923 			}
1924 		} else if (!strcmp(value, "MinisterTitles")) {
1925 			if (!lua_istable(l, -1)) {
1926 				LuaError(l, "incorrect argument");
1927 			}
1928 			const int subargs = lua_rawlen(l, -1);
1929 			for (int k = 0; k < subargs; ++k) {
1930 				int title = GetCharacterTitleIdByName(LuaToString(l, -1, k + 1));
1931 				++k;
1932 				int gender = GetGenderIdByName(LuaToString(l, -1, k + 1));
1933 				++k;
1934 				int government_type = GetGovernmentTypeIdByName(LuaToString(l, -1, k + 1));
1935 				++k;
1936 				int faction_tier = GetFactionTierIdByName(LuaToString(l, -1, k + 1));
1937 				++k;
1938 				faction->MinisterTitles[title][gender][government_type][faction_tier] = LuaToString(l, -1, k + 1);
1939 			}
1940 		} else if (!strcmp(value, "FactionUpgrade")) {
1941 			faction->FactionUpgrade = LuaToString(l, -1);
1942 		} else if (!strcmp(value, "ButtonIcons")) {
1943 			if (!lua_istable(l, -1)) {
1944 				LuaError(l, "incorrect argument");
1945 			}
1946 			const int subargs = lua_rawlen(l, -1);
1947 			for (int j = 0; j < subargs; ++j) {
1948 				std::string button_action_name = LuaToString(l, -1, j + 1);
1949 				int button_action = GetButtonActionIdByName(button_action_name);
1950 				if (button_action != -1) {
1951 					++j;
1952 					faction->ButtonIcons[button_action].Name = LuaToString(l, -1, j + 1);
1953 					faction->ButtonIcons[button_action].Icon = nullptr;
1954 					faction->ButtonIcons[button_action].Load();
1955 				} else {
1956 					LuaError(l, "Button action \"%s\" doesn't exist." _C_ button_action_name.c_str());
1957 				}
1958 			}
1959 		} else if (!strcmp(value, "ForceTypeWeights")) {
1960 			if (!lua_istable(l, -1)) {
1961 				LuaError(l, "incorrect argument");
1962 			}
1963 
1964 			faction->ForceTypeWeights.clear();
1965 
1966 			const int subargs = lua_rawlen(l, -1);
1967 			for (int j = 0; j < subargs; ++j) {
1968 				int force_type = GetForceTypeIdByName(LuaToString(l, -1, j + 1));
1969 				++j;
1970 				faction->ForceTypeWeights[force_type] = LuaToNumber(l, -1, j + 1);
1971 			}
1972 		} else if (!strcmp(value, "ForceTemplates")) {
1973 			const int args = lua_rawlen(l, -1);
1974 			for (int j = 0; j < args; ++j) {
1975 				lua_rawgeti(l, -1, j + 1);
1976 				CForceTemplate *force = new CForceTemplate;
1977 				if (!lua_istable(l, -1)) {
1978 					LuaError(l, "incorrect argument (expected table for force templates)");
1979 				}
1980 				const int subargs = lua_rawlen(l, -1);
1981 				for (int k = 0; k < subargs; ++k) {
1982 					value = LuaToString(l, -1, k + 1);
1983 					++k;
1984 					if (!strcmp(value, "force-type")) {
1985 						force->ForceType = GetForceTypeIdByName(LuaToString(l, -1, k + 1));
1986 						if (force->ForceType == -1) {
1987 							LuaError(l, "Force type doesn't exist.");
1988 						}
1989 						faction->ForceTemplates[force->ForceType].push_back(force);
1990 					} else if (!strcmp(value, "priority")) {
1991 						force->Priority = LuaToNumber(l, -1, k + 1);
1992 					} else if (!strcmp(value, "weight")) {
1993 						force->Weight = LuaToNumber(l, -1, k + 1);
1994 					} else if (!strcmp(value, "unit-class")) {
1995 						int unit_class = GetOrAddUnitTypeClassIndexByName(LuaToString(l, -1, k + 1));
1996 						++k;
1997 						int unit_quantity = LuaToNumber(l, -1, k + 1);
1998 						force->Units.push_back(std::pair<int, int>(unit_class, unit_quantity));
1999 					} else {
2000 						printf("\n%s\n", faction->Ident.c_str());
2001 						LuaError(l, "Unsupported tag: %s" _C_ value);
2002 					}
2003 				}
2004 				lua_pop(l, 1);
2005 			}
2006 			for (std::map<int, std::vector<CForceTemplate *>>::iterator iterator = faction->ForceTemplates.begin(); iterator != faction->ForceTemplates.end(); ++iterator) {
2007 				std::sort(iterator->second.begin(), iterator->second.end(), [](CForceTemplate *a, CForceTemplate *b) {
2008 					return a->Priority > b->Priority;
2009 				});
2010 			}
2011 		} else if (!strcmp(value, "AiBuildingTemplates")) {
2012 			const int args = lua_rawlen(l, -1);
2013 			for (int j = 0; j < args; ++j) {
2014 				lua_rawgeti(l, -1, j + 1);
2015 				CAiBuildingTemplate *building_template = new CAiBuildingTemplate;
2016 				if (!lua_istable(l, -1)) {
2017 					LuaError(l, "incorrect argument (expected table for force templates)");
2018 				}
2019 				const int subargs = lua_rawlen(l, -1);
2020 				for (int k = 0; k < subargs; ++k) {
2021 					value = LuaToString(l, -1, k + 1);
2022 					++k;
2023 					if (!strcmp(value, "unit-class")) {
2024 						int unit_class = GetOrAddUnitTypeClassIndexByName(LuaToString(l, -1, k + 1));
2025 						building_template->UnitClass = unit_class;
2026 						faction->AiBuildingTemplates.push_back(building_template);
2027 					} else if (!strcmp(value, "priority")) {
2028 						building_template->Priority = LuaToNumber(l, -1, k + 1);
2029 					} else if (!strcmp(value, "per-settlement")) {
2030 						building_template->PerSettlement = LuaToBoolean(l, -1, k + 1);
2031 					} else {
2032 						printf("\n%s\n", faction->Ident.c_str());
2033 						LuaError(l, "Unsupported tag: %s" _C_ value);
2034 					}
2035 				}
2036 				lua_pop(l, 1);
2037 			}
2038 			std::sort(faction->AiBuildingTemplates.begin(), faction->AiBuildingTemplates.end(), [](CAiBuildingTemplate *a, CAiBuildingTemplate *b) {
2039 				return a->Priority > b->Priority;
2040 			});
2041 		} else if (!strcmp(value, "UIFillers")) {
2042 			if (!lua_istable(l, -1)) {
2043 				LuaError(l, "incorrect argument");
2044 			}
2045 
2046 			faction->UIFillers.clear();
2047 
2048 			const int subargs = lua_rawlen(l, -1);
2049 			for (int j = 0; j < subargs; ++j) {
2050 				CFiller filler = CFiller();
2051 				std::string filler_file = LuaToString(l, -1, j + 1);
2052 				if (filler_file.empty()) {
2053 					LuaError(l, "Filler graphic file is empty.");
2054 				}
2055 				filler.G = CGraphic::New(filler_file);
2056 				++j;
2057 				filler.X = LuaToNumber(l, -1, j + 1);
2058 				++j;
2059 				filler.Y = LuaToNumber(l, -1, j + 1);
2060 				faction->UIFillers.push_back(filler);
2061 			}
2062 		} else if (!strcmp(value, "Conditions")) {
2063 			faction->Conditions = new LuaCallback(l, -1);
2064 		} else if (!strcmp(value, "ProvinceNames")) {
2065 			faction->ProvinceNames.clear();
2066 			const int args = lua_rawlen(l, -1);
2067 			for (int j = 0; j < args; ++j) {
2068 				faction->ProvinceNames.push_back(LuaToString(l, -1, j + 1));
2069 			}
2070 		} else if (!strcmp(value, "ShipNames")) {
2071 			faction->ShipNames.clear();
2072 			const int args = lua_rawlen(l, -1);
2073 			for (int j = 0; j < args; ++j) {
2074 				faction->ShipNames.push_back(LuaToString(l, -1, j + 1));
2075 			}
2076 		} else if (!strcmp(value, "HistoricalUpgrades")) {
2077 			if (!lua_istable(l, -1)) {
2078 				LuaError(l, "incorrect argument");
2079 			}
2080 			const int subargs = lua_rawlen(l, -1);
2081 			for (int j = 0; j < subargs; ++j) {
2082 				CDate date;
2083 				lua_rawgeti(l, -1, j + 1);
2084 				CclGetDate(l, &date);
2085 				lua_pop(l, 1);
2086 				++j;
2087 
2088 				std::string technology_ident = LuaToString(l, -1, j + 1);
2089 				++j;
2090 
2091 				bool has_upgrade = LuaToBoolean(l, -1, j + 1);
2092 
2093 				faction->HistoricalUpgrades[technology_ident][date] = has_upgrade;
2094 			}
2095 		} else if (!strcmp(value, "HistoricalTiers")) {
2096 			if (!lua_istable(l, -1)) {
2097 				LuaError(l, "incorrect argument");
2098 			}
2099 			const int subargs = lua_rawlen(l, -1);
2100 			for (int j = 0; j < subargs; ++j) {
2101 				int year = LuaToNumber(l, -1, j + 1);
2102 				++j;
2103 				std::string faction_tier_name = LuaToString(l, -1, j + 1);
2104 				int faction_tier = GetFactionTierIdByName(faction_tier_name);
2105 				if (faction_tier == -1) {
2106 					LuaError(l, "Faction tier \"%s\" doesn't exist." _C_ faction_tier_name.c_str());
2107 				}
2108 				faction->HistoricalTiers[year] = faction_tier;
2109 			}
2110 		} else if (!strcmp(value, "HistoricalGovernmentTypes")) {
2111 			if (!lua_istable(l, -1)) {
2112 				LuaError(l, "incorrect argument");
2113 			}
2114 			const int subargs = lua_rawlen(l, -1);
2115 			for (int j = 0; j < subargs; ++j) {
2116 				int year = LuaToNumber(l, -1, j + 1);
2117 				++j;
2118 				std::string government_type_name = LuaToString(l, -1, j + 1);
2119 				int government_type = GetGovernmentTypeIdByName(government_type_name);
2120 				if (government_type == -1) {
2121 					LuaError(l, "Government type \"%s\" doesn't exist." _C_ government_type_name.c_str());
2122 				}
2123 				faction->HistoricalGovernmentTypes[year] = government_type;
2124 			}
2125 		} else if (!strcmp(value, "HistoricalDiplomacyStates")) {
2126 			if (!lua_istable(l, -1)) {
2127 				LuaError(l, "incorrect argument");
2128 			}
2129 			const int subargs = lua_rawlen(l, -1);
2130 			for (int j = 0; j < subargs; ++j) {
2131 				CDate date;
2132 				lua_rawgeti(l, -1, j + 1);
2133 				CclGetDate(l, &date);
2134 				lua_pop(l, 1);
2135 				++j;
2136 
2137 				std::string diplomacy_state_faction_ident = LuaToString(l, -1, j + 1);
2138 				CFaction *diplomacy_state_faction = PlayerRaces.GetFaction(diplomacy_state_faction_ident);
2139 				if (diplomacy_state_faction == nullptr) {
2140 					LuaError(l, "Faction \"%s\" doesn't exist." _C_ diplomacy_state_faction_ident.c_str());
2141 				}
2142 				++j;
2143 
2144 				std::string diplomacy_state_name = LuaToString(l, -1, j + 1);
2145 				int diplomacy_state = GetDiplomacyStateIdByName(diplomacy_state_name);
2146 				if (diplomacy_state == -1) {
2147 					LuaError(l, "Diplomacy state \"%s\" doesn't exist." _C_ diplomacy_state_name.c_str());
2148 				}
2149 				faction->HistoricalDiplomacyStates[std::pair<CDate, CFaction *>(date, diplomacy_state_faction)] = diplomacy_state;
2150 			}
2151 		} else if (!strcmp(value, "HistoricalResources")) {
2152 			if (!lua_istable(l, -1)) {
2153 				LuaError(l, "incorrect argument");
2154 			}
2155 			const int subargs = lua_rawlen(l, -1);
2156 			for (int j = 0; j < subargs; ++j) {
2157 				CDate date;
2158 				lua_rawgeti(l, -1, j + 1);
2159 				CclGetDate(l, &date);
2160 				lua_pop(l, 1);
2161 				++j;
2162 
2163 				std::string resource_ident = LuaToString(l, -1, j + 1);
2164 				int resource = GetResourceIdByName(l, resource_ident.c_str());
2165 				if (resource == -1) {
2166 					LuaError(l, "Resource \"%s\" doesn't exist." _C_ resource_ident.c_str());
2167 				}
2168 				++j;
2169 
2170 				faction->HistoricalResources[std::pair<CDate, int>(date, resource)] = LuaToNumber(l, -1, j + 1);
2171 			}
2172 		} else if (!strcmp(value, "HistoricalCapitals")) {
2173 			if (!lua_istable(l, -1)) {
2174 				LuaError(l, "incorrect argument");
2175 			}
2176 			const int subargs = lua_rawlen(l, -1);
2177 			for (int j = 0; j < subargs; ++j) {
2178 				CDate date;
2179 				lua_rawgeti(l, -1, j + 1);
2180 				CclGetDate(l, &date);
2181 				lua_pop(l, 1);
2182 				++j;
2183 
2184 				std::string site_ident = LuaToString(l, -1, j + 1);
2185 
2186 				faction->HistoricalCapitals.push_back(std::pair<CDate, std::string>(date, site_ident));
2187 			}
2188 		} else if (!strcmp(value, "Mod")) {
2189 			faction->Mod = LuaToString(l, -1);
2190 		} else {
2191 			LuaError(l, "Unsupported tag: %s" _C_ value);
2192 		}
2193 	}
2194 
2195 	if (faction->Type == FactionTypeTribe) {
2196 		faction->DefiniteArticle = true;
2197 	}
2198 
2199 	if (!parent_faction.empty()) { //process this here
2200 		faction->ParentFaction = PlayerRaces.GetFactionIndexByName(parent_faction);
2201 
2202 		if (faction->ParentFaction == -1) { //if a parent faction was set but wasn't found, give an error
2203 			LuaError(l, "Faction %s doesn't exist" _C_ parent_faction.c_str());
2204 		}
2205 
2206 		if (faction->ParentFaction != -1 && faction->FactionUpgrade.empty()) { //if the faction has no faction upgrade, inherit that of its parent faction
2207 			faction->FactionUpgrade = PlayerRaces.Factions[faction->ParentFaction]->FactionUpgrade;
2208 		}
2209 
2210 		if (faction->ParentFaction != -1) { //inherit button icons from parent civilization, for button actions which none are specified
2211 			for (std::map<int, IconConfig>::iterator iterator = PlayerRaces.Factions[faction->ParentFaction]->ButtonIcons.begin(); iterator != PlayerRaces.Factions[faction->ParentFaction]->ButtonIcons.end(); ++iterator) {
2212 				if (faction->ButtonIcons.find(iterator->first) == faction->ButtonIcons.end()) {
2213 					faction->ButtonIcons[iterator->first] = iterator->second;
2214 				}
2215 			}
2216 
2217 			for (std::map<std::string, std::map<CDate, bool>>::iterator iterator = PlayerRaces.Factions[faction->ParentFaction]->HistoricalUpgrades.begin(); iterator != PlayerRaces.Factions[faction->ParentFaction]->HistoricalUpgrades.end(); ++iterator) {
2218 				if (faction->HistoricalUpgrades.find(iterator->first) == faction->HistoricalUpgrades.end()) {
2219 					faction->HistoricalUpgrades[iterator->first] = iterator->second;
2220 				}
2221 			}
2222 		}
2223 	} else if (parent_faction.empty()) {
2224 		faction->ParentFaction = -1; // to allow redefinitions to remove the parent faction setting
2225 	}
2226 
2227 	return 0;
2228 }
2229 
2230 /**
2231 **  Define a dynasty.
2232 **
2233 **  @param l  Lua state.
2234 */
CclDefineDynasty(lua_State * l)2235 static int CclDefineDynasty(lua_State *l)
2236 {
2237 	LuaCheckArgs(l, 2);
2238 	if (!lua_istable(l, 2)) {
2239 		LuaError(l, "incorrect argument (expected table)");
2240 	}
2241 
2242 	std::string dynasty_ident = LuaToString(l, 1);
2243 
2244 	CDynasty *dynasty = PlayerRaces.GetDynasty(dynasty_ident);
2245 	if (!dynasty) { // new definition
2246 		dynasty = new CDynasty;
2247 		dynasty->Ident = dynasty_ident;
2248 		dynasty->ID = PlayerRaces.Dynasties.size();
2249 		PlayerRaces.Dynasties.push_back(dynasty);
2250 		DynastyStringToIndex[dynasty->Ident] = dynasty->ID;
2251 	}
2252 
2253 	//  Parse the list:
2254 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
2255 		const char *value = LuaToString(l, -2);
2256 
2257 		if (!strcmp(value, "Civilization")) {
2258 			CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, -1));
2259 			if (civilization) {
2260 				dynasty->Civilization = civilization->ID;
2261 			}
2262 		} else if (!strcmp(value, "Name")) {
2263 			dynasty->Name = LuaToString(l, -1);
2264 		} else if (!strcmp(value, "Description")) {
2265 			dynasty->Description = LuaToString(l, -1);
2266 		} else if (!strcmp(value, "Quote")) {
2267 			dynasty->Quote = LuaToString(l, -1);
2268 		} else if (!strcmp(value, "Background")) {
2269 			dynasty->Background = LuaToString(l, -1);
2270 		} else if (!strcmp(value, "Icon")) {
2271 			dynasty->Icon.Name = LuaToString(l, -1);
2272 			dynasty->Icon.Icon = nullptr;
2273 			dynasty->Icon.Load();
2274 			dynasty->Icon.Icon->Load();
2275 		} else if (!strcmp(value, "Factions")) {
2276 			if (!lua_istable(l, -1)) {
2277 				LuaError(l, "incorrect argument");
2278 			}
2279 			const int subargs = lua_rawlen(l, -1);
2280 			for (int k = 0; k < subargs; ++k) {
2281 				CFaction *faction = PlayerRaces.GetFaction(LuaToString(l, -1, k + 1));
2282 				if (!faction) {
2283 					LuaError(l, "Faction doesn't exist.");
2284 				}
2285 				dynasty->Factions.push_back(faction);
2286 				faction->Dynasties.push_back(dynasty);
2287 			}
2288 		} else if (!strcmp(value, "DynastyUpgrade")) {
2289 			dynasty->DynastyUpgrade = CUpgrade::Get(LuaToString(l, -1));
2290 		} else if (!strcmp(value, "Conditions")) {
2291 			dynasty->Conditions = new LuaCallback(l, -1);
2292 		} else {
2293 			LuaError(l, "Unsupported tag: %s" _C_ value);
2294 		}
2295 	}
2296 
2297 	return 0;
2298 }
2299 
2300 /**
2301 **  Define a religion.
2302 **
2303 **  @param l  Lua state.
2304 */
CclDefineReligion(lua_State * l)2305 static int CclDefineReligion(lua_State *l)
2306 {
2307 	LuaCheckArgs(l, 2);
2308 	if (!lua_istable(l, 2)) {
2309 		LuaError(l, "incorrect argument (expected table)");
2310 	}
2311 
2312 	std::string religion_ident = LuaToString(l, 1);
2313 	CReligion *religion = CReligion::GetOrAddReligion(religion_ident);
2314 
2315 	//  Parse the list:
2316 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
2317 		const char *value = LuaToString(l, -2);
2318 
2319 		if (!strcmp(value, "Name")) {
2320 			religion->Name = LuaToString(l, -1);
2321 		} else if (!strcmp(value, "Description")) {
2322 			religion->Description = LuaToString(l, -1);
2323 		} else if (!strcmp(value, "Background")) {
2324 			religion->Background = LuaToString(l, -1);
2325 		} else if (!strcmp(value, "Quote")) {
2326 			religion->Quote = LuaToString(l, -1);
2327 		} else if (!strcmp(value, "CulturalDeities")) {
2328 			religion->CulturalDeities = LuaToBoolean(l, -1);
2329 		} else if (!strcmp(value, "Domains")) {
2330 			if (!lua_istable(l, -1)) {
2331 				LuaError(l, "incorrect argument (expected table)");
2332 			}
2333 			const int subargs = lua_rawlen(l, -1);
2334 			for (int j = 0; j < subargs; ++j) {
2335 				CDeityDomain *deity_domain = CDeityDomain::GetDeityDomain(LuaToString(l, -1, j + 1));
2336 				if (deity_domain) {
2337 					religion->Domains.push_back(deity_domain);
2338 				}
2339 			}
2340 		} else {
2341 			LuaError(l, "Unsupported tag: %s" _C_ value);
2342 		}
2343 	}
2344 
2345 	return 0;
2346 }
2347 
2348 /**
2349 **  Define a deity.
2350 **
2351 **  @param l  Lua state.
2352 */
CclDefineDeity(lua_State * l)2353 static int CclDefineDeity(lua_State *l)
2354 {
2355 	LuaCheckArgs(l, 2);
2356 	if (!lua_istable(l, 2)) {
2357 		LuaError(l, "incorrect argument (expected table)");
2358 	}
2359 
2360 	std::string deity_ident = LuaToString(l, 1);
2361 	CDeity *deity = CDeity::GetOrAddDeity(deity_ident);
2362 
2363 	//  Parse the list:
2364 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
2365 		const char *value = LuaToString(l, -2);
2366 
2367 		if (!strcmp(value, "Name")) {
2368 			deity->Name = LuaToString(l, -1);
2369 		} else if (!strcmp(value, "Pantheon")) {
2370 			deity->Pantheon = CPantheon::GetPantheon(LuaToString(l, -1));
2371 		} else if (!strcmp(value, "Gender")) {
2372 			deity->Gender = GetGenderIdByName(LuaToString(l, -1));
2373 		} else if (!strcmp(value, "Major")) {
2374 			deity->Major = LuaToBoolean(l, -1);
2375 		} else if (!strcmp(value, "Description")) {
2376 			deity->Description = LuaToString(l, -1);
2377 		} else if (!strcmp(value, "Background")) {
2378 			deity->Background = LuaToString(l, -1);
2379 		} else if (!strcmp(value, "Quote")) {
2380 			deity->Quote = LuaToString(l, -1);
2381 		} else if (!strcmp(value, "HomePlane")) {
2382 			CPlane *plane = CPlane::GetPlane(LuaToString(l, -1));
2383 			if (!plane) {
2384 				LuaError(l, "Plane doesn't exist.");
2385 			}
2386 			deity->HomePlane = plane;
2387 		} else if (!strcmp(value, "DeityUpgrade")) {
2388 			CUpgrade *upgrade = CUpgrade::Get(LuaToString(l, -1));
2389 			if (!upgrade) {
2390 				LuaError(l, "Upgrade doesn't exist.");
2391 			}
2392 			deity->DeityUpgrade = upgrade;
2393 			CDeity::DeitiesByUpgrade[upgrade] = deity;
2394 		} else if (!strcmp(value, "CharacterUpgrade")) {
2395 			CUpgrade *upgrade = CUpgrade::Get(LuaToString(l, -1));
2396 			if (!upgrade) {
2397 				LuaError(l, "Upgrade doesn't exist.");
2398 			}
2399 			deity->CharacterUpgrade = upgrade;
2400 		} else if (!strcmp(value, "Icon")) {
2401 			deity->Icon.Name = LuaToString(l, -1);
2402 			deity->Icon.Icon = nullptr;
2403 			deity->Icon.Load();
2404 			deity->Icon.Icon->Load();
2405 		} else if (!strcmp(value, "Civilizations")) {
2406 			if (!lua_istable(l, -1)) {
2407 				LuaError(l, "incorrect argument (expected table)");
2408 			}
2409 			const int subargs = lua_rawlen(l, -1);
2410 			for (int j = 0; j < subargs; ++j) {
2411 				CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, -1, j + 1));
2412 				if (civilization) {
2413 					deity->Civilizations.push_back(civilization);
2414 					civilization->Deities.push_back(deity);
2415 				}
2416 			}
2417 		} else if (!strcmp(value, "Religions")) {
2418 			if (!lua_istable(l, -1)) {
2419 				LuaError(l, "incorrect argument (expected table)");
2420 			}
2421 			const int subargs = lua_rawlen(l, -1);
2422 			for (int j = 0; j < subargs; ++j) {
2423 				CReligion *religion = CReligion::GetReligion(LuaToString(l, -1, j + 1));
2424 				if (religion) {
2425 					deity->Religions.push_back(religion);
2426 				}
2427 			}
2428 		} else if (!strcmp(value, "Domains")) {
2429 			if (!lua_istable(l, -1)) {
2430 				LuaError(l, "incorrect argument (expected table)");
2431 			}
2432 			const int subargs = lua_rawlen(l, -1);
2433 			for (int j = 0; j < subargs; ++j) {
2434 				CDeityDomain *deity_domain = CDeityDomain::GetDeityDomain(LuaToString(l, -1, j + 1));
2435 				if (deity_domain) {
2436 					deity->Domains.push_back(deity_domain);
2437 				}
2438 			}
2439 		} else if (!strcmp(value, "HolyOrders")) {
2440 			if (!lua_istable(l, -1)) {
2441 				LuaError(l, "incorrect argument (expected table)");
2442 			}
2443 			const int subargs = lua_rawlen(l, -1);
2444 			for (int j = 0; j < subargs; ++j) {
2445 				CFaction *holy_order = PlayerRaces.GetFaction(LuaToString(l, -1, j + 1));
2446 				if (!holy_order) {
2447 					LuaError(l, "Holy order doesn't exist.");
2448 				}
2449 
2450 				deity->HolyOrders.push_back(holy_order);
2451 				holy_order->HolyOrderDeity = deity;
2452 			}
2453 		} else if (!strcmp(value, "Abilities")) {
2454 			if (!lua_istable(l, -1)) {
2455 				LuaError(l, "incorrect argument (expected table)");
2456 			}
2457 			const int subargs = lua_rawlen(l, -1);
2458 			for (int j = 0; j < subargs; ++j) {
2459 				CUpgrade *ability = CUpgrade::Get(LuaToString(l, -1, j + 1));
2460 				if (!ability || !ability->Ability) {
2461 					LuaError(l, "Ability doesn't exist.");
2462 				}
2463 
2464 				if (std::find(deity->Abilities.begin(), deity->Abilities.end(), ability) == deity->Abilities.end()) {
2465 					deity->Abilities.push_back(ability);
2466 				}
2467 			}
2468 		} else if (!strcmp(value, "Feasts")) {
2469 			if (!lua_istable(l, -1)) {
2470 				LuaError(l, "incorrect argument (expected table)");
2471 			}
2472 			const int subargs = lua_rawlen(l, -1);
2473 			for (int j = 0; j < subargs; ++j) {
2474 				std::string feast = LuaToString(l, -1, j + 1);
2475 
2476 				deity->Feasts.push_back(feast);
2477 			}
2478 		} else if (!strcmp(value, "CulturalNames")) {
2479 			if (!lua_istable(l, -1)) {
2480 				LuaError(l, "incorrect argument (expected table)");
2481 			}
2482 			const int subargs = lua_rawlen(l, -1);
2483 			for (int j = 0; j < subargs; ++j) {
2484 				const CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, -1, j + 1));
2485 				++j;
2486 				if (!civilization) {
2487 					continue;
2488 				}
2489 
2490 				std::string cultural_name = LuaToString(l, -1, j + 1);
2491 				deity->CulturalNames[civilization] = cultural_name;
2492 			}
2493 		} else {
2494 			LuaError(l, "Unsupported tag: %s" _C_ value);
2495 		}
2496 	}
2497 
2498 	if (deity->Major && deity->Domains.size() > MAJOR_DEITY_DOMAIN_MAX) {
2499 		deity->Domains.resize(MAJOR_DEITY_DOMAIN_MAX);
2500 	} else if (!deity->Major && deity->Domains.size() > MINOR_DEITY_DOMAIN_MAX) {
2501 		deity->Domains.resize(MINOR_DEITY_DOMAIN_MAX);
2502 	}
2503 
2504 	for (CDeityDomain *domain : deity->Domains) {
2505 		for (CUpgrade *ability : domain->Abilities) {
2506 			if (std::find(deity->Abilities.begin(), deity->Abilities.end(), ability) == deity->Abilities.end()) {
2507 				deity->Abilities.push_back(ability);
2508 			}
2509 		}
2510 	}
2511 
2512 	return 0;
2513 }
2514 
2515 /**
2516 **  Define a language.
2517 **
2518 **  @param l  Lua state.
2519 */
CclDefineLanguage(lua_State * l)2520 static int CclDefineLanguage(lua_State *l)
2521 {
2522 	LuaCheckArgs(l, 2);
2523 	if (!lua_istable(l, 2)) {
2524 		LuaError(l, "incorrect argument (expected table)");
2525 	}
2526 
2527 	std::string language_ident = LuaToString(l, 1);
2528 	CLanguage *language = PlayerRaces.GetLanguage(language_ident);
2529 	if (!language) {
2530 		language = new CLanguage;
2531 		PlayerRaces.Languages.push_back(language);
2532 		LanguageIdentToPointer[language_ident] = language;
2533 	}
2534 
2535 	language->Ident = language_ident;
2536 
2537 	//  Parse the list:
2538 	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
2539 		const char *value = LuaToString(l, -2);
2540 
2541 		if (!strcmp(value, "Name")) {
2542 			language->Name = LuaToString(l, -1);
2543 		} else if (!strcmp(value, "Family")) {
2544 			language->Family = LuaToString(l, -1);
2545 		} else if (!strcmp(value, "DialectOf")) {
2546 			CLanguage *parent_language = PlayerRaces.GetLanguage(LuaToString(l, -1));
2547 			if (parent_language) {
2548 				language->DialectOf = parent_language;
2549 				parent_language->Dialects.push_back(language);
2550 			} else {
2551 				LuaError(l, "Language not found.");
2552 			}
2553 		} else if (!strcmp(value, "NounEndings")) {
2554 			if (!lua_istable(l, -1)) {
2555 				LuaError(l, "incorrect argument");
2556 			}
2557 			const int subargs = lua_rawlen(l, -1);
2558 			for (int k = 0; k < subargs; ++k) {
2559 				std::string grammatical_number_name = LuaToString(l, -1, k + 1);
2560 				int grammatical_number = GetGrammaticalNumberIdByName(grammatical_number_name);
2561 				if (grammatical_number == -1) {
2562 					LuaError(l, "Grammatical number \"%s\" doesn't exist." _C_ grammatical_number_name.c_str());
2563 				}
2564 				++k;
2565 
2566 				std::string grammatical_case_name = LuaToString(l, -1, k + 1);
2567 				int grammatical_case = GetGrammaticalCaseIdByName(grammatical_case_name);
2568 				if (grammatical_case == -1) {
2569 					LuaError(l, "Grammatical case \"%s\" doesn't exist." _C_ grammatical_case_name.c_str());
2570 				}
2571 				++k;
2572 
2573 				int word_junction_type = WordJunctionTypeNoWordJunction;
2574 				if (GetWordJunctionTypeIdByName(LuaToString(l, -1, k + 1)) != -1) {
2575 					std::string word_junction_type_name = LuaToString(l, -1, k + 1);
2576 					int word_junction_type = GetWordJunctionTypeIdByName(word_junction_type_name);
2577 					if (word_junction_type == -1) {
2578 						LuaError(l, "Word junction type \"%s\" doesn't exist." _C_ word_junction_type_name.c_str());
2579 					}
2580 					++k;
2581 				}
2582 
2583 				language->NounEndings[grammatical_number][grammatical_case][word_junction_type] = LuaToString(l, -1, k + 1);
2584 			}
2585 		} else if (!strcmp(value, "AdjectiveEndings")) {
2586 			if (!lua_istable(l, -1)) {
2587 				LuaError(l, "incorrect argument");
2588 			}
2589 			const int subargs = lua_rawlen(l, -1);
2590 			for (int k = 0; k < subargs; ++k) {
2591 				std::string article_type_name = LuaToString(l, -1, k + 1);
2592 				int article_type = GetArticleTypeIdByName(article_type_name);
2593 				if (article_type == -1) {
2594 					LuaError(l, "Article type \"%s\" doesn't exist." _C_ article_type_name.c_str());
2595 				}
2596 				++k;
2597 
2598 				std::string grammatical_case_name = LuaToString(l, -1, k + 1);
2599 				int grammatical_case = GetGrammaticalCaseIdByName(grammatical_case_name);
2600 				if (grammatical_case == -1) {
2601 					LuaError(l, "Grammatical case \"%s\" doesn't exist." _C_ grammatical_case_name.c_str());
2602 				}
2603 				++k;
2604 
2605 				std::string grammatical_number_name = LuaToString(l, -1, k + 1);
2606 				int grammatical_number = GetGrammaticalNumberIdByName(grammatical_number_name);
2607 				if (grammatical_number == -1) {
2608 					LuaError(l, "Grammatical number \"%s\" doesn't exist." _C_ grammatical_number_name.c_str());
2609 				}
2610 				++k;
2611 
2612 				std::string grammatical_gender_name = LuaToString(l, -1, k + 1);
2613 				int grammatical_gender = GetGrammaticalGenderIdByName(grammatical_gender_name);
2614 				if (grammatical_gender == -1) {
2615 					LuaError(l, "Grammatical gender \"%s\" doesn't exist." _C_ grammatical_gender_name.c_str());
2616 				}
2617 				++k;
2618 
2619 				language->AdjectiveEndings[article_type][grammatical_case][grammatical_number][grammatical_gender] = LuaToString(l, -1, k + 1);
2620 			}
2621 		} else if (!strcmp(value, "NameTranslations")) {
2622 			if (!lua_istable(l, -1)) {
2623 				LuaError(l, "incorrect argument");
2624 			}
2625 			const int subargs = lua_rawlen(l, -1);
2626 			for (int k = 0; k < subargs; ++k) {
2627 				std::string translation_from = LuaToString(l, -1, k + 1); //name to be translated
2628 				++k;
2629 				std::string translation_to = LuaToString(l, -1, k + 1); //name translation
2630 				language->NameTranslations[translation_from].push_back(translation_to);
2631 			}
2632 		} else {
2633 			LuaError(l, "Unsupported tag: %s" _C_ value);
2634 		}
2635 	}
2636 
2637 	return 0;
2638 }
2639 //Wyrmgus end
2640 
2641 /**
2642 **  Get the civilizations.
2643 **
2644 **  @param l  Lua state.
2645 */
CclGetCivilizations(lua_State * l)2646 static int CclGetCivilizations(lua_State *l)
2647 {
2648 	const int nargs = lua_gettop(l);
2649 	bool only_visible = false;
2650 	if (nargs >= 1) {
2651 		only_visible = LuaToBoolean(l, 1);
2652 	}
2653 
2654 	std::vector<std::string> civilization_idents;
2655 	for (int i = 0; i < MAX_RACES; ++i) {
2656 		if (!PlayerRaces.Name[i].empty() && (!only_visible || PlayerRaces.Visible[i])) {
2657 			civilization_idents.push_back(PlayerRaces.Name[i]);
2658 		}
2659 	}
2660 
2661 	lua_createtable(l, civilization_idents.size(), 0);
2662 	for (unsigned int i = 1; i <= civilization_idents.size(); ++i)
2663 	{
2664 		lua_pushstring(l, civilization_idents[i - 1].c_str());
2665 		lua_rawseti(l, -2, i);
2666 	}
2667 
2668 	return 1;
2669 }
2670 
2671 /**
2672 **  Get the factions.
2673 **
2674 **  @param l  Lua state.
2675 */
CclGetFactions(lua_State * l)2676 static int CclGetFactions(lua_State *l)
2677 {
2678 	CCivilization *civilization = nullptr;
2679 	if (lua_gettop(l) >= 1) {
2680 		civilization = CCivilization::GetCivilization(LuaToString(l, 1));
2681 	}
2682 
2683 	int faction_type = -1;
2684 	if (lua_gettop(l) >= 2) {
2685 		faction_type = GetFactionTypeIdByName(LuaToString(l, 2));
2686 	}
2687 
2688 	std::vector<std::string> factions;
2689 	if (civilization != nullptr) {
2690 		for (size_t i = 0; i < PlayerRaces.Factions.size(); ++i) {
2691 			if (faction_type != -1 && PlayerRaces.Factions[i]->Type != faction_type) {
2692 				continue;
2693 			}
2694 			if (PlayerRaces.Factions[i]->Civilization == civilization) {
2695 				factions.push_back(PlayerRaces.Factions[i]->Ident);
2696 			}
2697 		}
2698 	} else {
2699 		for (size_t i = 0; i < PlayerRaces.Factions.size(); ++i) {
2700 			if (faction_type != -1 && PlayerRaces.Factions[i]->Type != faction_type) {
2701 				continue;
2702 			}
2703 			factions.push_back(PlayerRaces.Factions[i]->Ident);
2704 		}
2705 	}
2706 
2707 	lua_createtable(l, factions.size(), 0);
2708 	for (size_t i = 1; i <= factions.size(); ++i)
2709 	{
2710 		lua_pushstring(l, factions[i-1].c_str());
2711 		lua_rawseti(l, -2, i);
2712 	}
2713 
2714 	return 1;
2715 }
2716 
2717 /**
2718 **  Get the dynasties.
2719 **
2720 **  @param l  Lua state.
2721 */
CclGetDynasties(lua_State * l)2722 static int CclGetDynasties(lua_State *l)
2723 {
2724 	int civilization_id = -1;
2725 	if (lua_gettop(l) >= 1) {
2726 		CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, 1));
2727 		if (civilization) {
2728 			civilization_id = civilization->ID;
2729 		}
2730 	}
2731 
2732 	std::vector<std::string> dynasties;
2733 	if (civilization_id != -1) {
2734 		for (size_t i = 0; i < PlayerRaces.Dynasties.size(); ++i) {
2735 			if (PlayerRaces.Dynasties[i]->Civilization == civilization_id) {
2736 				dynasties.push_back(PlayerRaces.Dynasties[i]->Ident);
2737 			}
2738 		}
2739 	} else {
2740 		for (size_t i = 0; i < PlayerRaces.Dynasties.size(); ++i) {
2741 			dynasties.push_back(PlayerRaces.Dynasties[i]->Ident);
2742 		}
2743 	}
2744 
2745 	lua_createtable(l, dynasties.size(), 0);
2746 	for (size_t i = 1; i <= dynasties.size(); ++i)
2747 	{
2748 		lua_pushstring(l, dynasties[i-1].c_str());
2749 		lua_rawseti(l, -2, i);
2750 	}
2751 
2752 	return 1;
2753 }
2754 
2755 /**
2756 **  Get the player colors.
2757 **
2758 **  @param l  Lua state.
2759 */
CclGetPlayerColors(lua_State * l)2760 static int CclGetPlayerColors(lua_State *l)
2761 {
2762 	std::vector<std::string> player_colors;
2763 	for (int i = 0; i < PlayerColorMax; ++i)
2764 	{
2765 		if (!PlayerColorNames[i].empty()) {
2766 			player_colors.push_back(PlayerColorNames[i]);
2767 		}
2768 	}
2769 
2770 	lua_createtable(l, player_colors.size(), 0);
2771 	for (size_t i = 1; i <= player_colors.size(); ++i)
2772 	{
2773 		lua_pushstring(l, player_colors[i-1].c_str());
2774 		lua_rawseti(l, -2, i);
2775 	}
2776 
2777 	return 1;
2778 }
2779 
2780 /**
2781 **  Get faction data.
2782 **
2783 **  @param l  Lua state.
2784 */
CclGetFactionData(lua_State * l)2785 static int CclGetFactionData(lua_State *l)
2786 {
2787 	LuaCheckArgs(l, 2);
2788 	std::string faction_name = LuaToString(l, 1);
2789 	CFaction *faction = PlayerRaces.GetFaction(faction_name);
2790 	if (faction == nullptr) {
2791 		LuaError(l, "Faction \"%s\" doesn't exist." _C_ faction_name.c_str());
2792 	}
2793 
2794 	const char *data = LuaToString(l, 2);
2795 
2796 	if (!strcmp(data, "Name")) {
2797 		lua_pushstring(l, faction->Name.c_str());
2798 		return 1;
2799 	} else if (!strcmp(data, "Description")) {
2800 		lua_pushstring(l, faction->Description.c_str());
2801 		return 1;
2802 	} else if (!strcmp(data, "Quote")) {
2803 		lua_pushstring(l, faction->Quote.c_str());
2804 		return 1;
2805 	} else if (!strcmp(data, "Background")) {
2806 		lua_pushstring(l, faction->Background.c_str());
2807 		return 1;
2808 	} else if (!strcmp(data, "Adjective")) {
2809 		if (!faction->Adjective.empty()) {
2810 			lua_pushstring(l, faction->Adjective.c_str());
2811 		} else {
2812 			lua_pushstring(l, faction->Name.c_str());
2813 		}
2814 		return 1;
2815 	} else if (!strcmp(data, "Type")) {
2816 		lua_pushstring(l, GetFactionTypeNameById(faction->Type).c_str());
2817 		return 1;
2818 	} else if (!strcmp(data, "Civilization")) {
2819 		if (faction->Civilization != nullptr) {
2820 			lua_pushstring(l, PlayerRaces.Name[faction->Civilization->ID].c_str());
2821 		} else {
2822 			lua_pushstring(l, "");
2823 		}
2824 		return 1;
2825 	} else if (!strcmp(data, "Color")) {
2826 		if (faction->Colors.size() > 0) {
2827 			lua_pushstring(l, PlayerColorNames[faction->Colors[0]].c_str());
2828 		} else {
2829 			lua_pushstring(l, "");
2830 		}
2831 		return 1;
2832 	} else if (!strcmp(data, "Playable")) {
2833 		lua_pushboolean(l, faction->Playable);
2834 		return 1;
2835 	} else if (!strcmp(data, "FactionUpgrade")) {
2836 		lua_pushstring(l, faction->FactionUpgrade.c_str());
2837 		return 1;
2838 	} else if (!strcmp(data, "ParentFaction")) {
2839 		if (faction->ParentFaction != -1) {
2840 			lua_pushstring(l, PlayerRaces.Factions[faction->ParentFaction]->Ident.c_str());
2841 		} else {
2842 			lua_pushstring(l, "");
2843 		}
2844 		return 1;
2845 	} else if (!strcmp(data, "DefaultAI")) {
2846 		lua_pushstring(l, faction->DefaultAI.c_str());
2847 		return 1;
2848 	} else {
2849 		LuaError(l, "Invalid field: %s" _C_ data);
2850 	}
2851 
2852 	return 0;
2853 }
2854 
2855 /**
2856 **  Get dynasty data.
2857 **
2858 **  @param l  Lua state.
2859 */
CclGetDynastyData(lua_State * l)2860 static int CclGetDynastyData(lua_State *l)
2861 {
2862 	LuaCheckArgs(l, 2);
2863 	std::string dynasty_ident = LuaToString(l, 1);
2864 	CDynasty *dynasty = PlayerRaces.GetDynasty(dynasty_ident);
2865 	if (dynasty == nullptr) {
2866 		LuaError(l, "Dynasty \"%s\" doesn't exist." _C_ dynasty_ident.c_str());
2867 	}
2868 
2869 	const char *data = LuaToString(l, 2);
2870 
2871 	if (!strcmp(data, "Name")) {
2872 		lua_pushstring(l, dynasty->Name.c_str());
2873 		return 1;
2874 	} else if (!strcmp(data, "Description")) {
2875 		lua_pushstring(l, dynasty->Description.c_str());
2876 		return 1;
2877 	} else if (!strcmp(data, "Quote")) {
2878 		lua_pushstring(l, dynasty->Quote.c_str());
2879 		return 1;
2880 	} else if (!strcmp(data, "Background")) {
2881 		lua_pushstring(l, dynasty->Background.c_str());
2882 		return 1;
2883 	} else if (!strcmp(data, "Civilization")) {
2884 		if (dynasty->Civilization != -1) {
2885 			lua_pushstring(l, PlayerRaces.Name[dynasty->Civilization].c_str());
2886 		} else {
2887 			lua_pushstring(l, "");
2888 		}
2889 		return 1;
2890 	} else if (!strcmp(data, "DynastyUpgrade")) {
2891 		if (dynasty->DynastyUpgrade) {
2892 			lua_pushstring(l, dynasty->DynastyUpgrade->Ident.c_str());
2893 		} else {
2894 			lua_pushstring(l, "");
2895 		}
2896 		return 1;
2897 	} else if (!strcmp(data, "Factions")) {
2898 		lua_createtable(l, dynasty->Factions.size(), 0);
2899 		for (size_t i = 1; i <= dynasty->Factions.size(); ++i)
2900 		{
2901 			lua_pushstring(l, dynasty->Factions[i-1]->Ident.c_str());
2902 			lua_rawseti(l, -2, i);
2903 		}
2904 		return 1;
2905 	} else {
2906 		LuaError(l, "Invalid field: %s" _C_ data);
2907 	}
2908 
2909 	return 0;
2910 }
2911 //Wyrmgus end
2912 
2913 /**
2914 **  Define player colors
2915 **
2916 **  @param l  Lua state.
2917 */
CclDefinePlayerColors(lua_State * l)2918 static int CclDefinePlayerColors(lua_State *l)
2919 {
2920 	LuaCheckArgs(l, 1);
2921 	if (!lua_istable(l, 1)) {
2922 		LuaError(l, "incorrect argument");
2923 	}
2924 
2925 	const int args = lua_rawlen(l, 1);
2926 	for (int i = 0; i < args; ++i) {
2927 		PlayerColorNames[i / 2] = LuaToString(l, 1, i + 1);
2928 		++i;
2929 		lua_rawgeti(l, 1, i + 1);
2930 		if (!lua_istable(l, -1)) {
2931 			LuaError(l, "incorrect argument");
2932 		}
2933 		const int numcolors = lua_rawlen(l, -1);
2934 		if (numcolors != PlayerColorIndexCount) {
2935 			LuaError(l, "You should use %d colors (See DefinePlayerColorIndex())" _C_ PlayerColorIndexCount);
2936 		}
2937 		for (int j = 0; j < numcolors; ++j) {
2938 			lua_rawgeti(l, -1, j + 1);
2939 			PlayerColorsRGB[i / 2][j].Parse(l);
2940 			lua_pop(l, 1);
2941 		}
2942 	}
2943 
2944 	return 0;
2945 }
2946 
2947 /**
2948 **  Make new player colors
2949 **
2950 **  @param l  Lua state.
2951 */
CclNewPlayerColors(lua_State * l)2952 static int CclNewPlayerColors(lua_State *l)
2953 {
2954 	LuaCheckArgs(l, 0);
2955 	SetPlayersPalette();
2956 
2957 	return 0;
2958 }
2959 
2960 /**
2961 **  Define player color indexes
2962 **
2963 **  @param l  Lua state.
2964 */
CclDefinePlayerColorIndex(lua_State * l)2965 static int CclDefinePlayerColorIndex(lua_State *l)
2966 {
2967 	LuaCheckArgs(l, 2);
2968 	PlayerColorIndexStart = LuaToNumber(l, 1);
2969 	PlayerColorIndexCount = LuaToNumber(l, 2);
2970 
2971 	//Wyrmgus start
2972 //	for (int i = 0; i < PlayerMax; ++i) {
2973 	for (int i = 0; i < PlayerColorMax; ++i) {
2974 	//Wyrmgus end
2975 		PlayerColorsRGB[i].clear();
2976 		PlayerColorsRGB[i].resize(PlayerColorIndexCount);
2977 		PlayerColors[i].clear();
2978 		PlayerColors[i].resize(PlayerColorIndexCount, 0);
2979 	}
2980 	return 0;
2981 }
2982 
2983 /**
2984 **  Define conversible player colors.
2985 **
2986 **  @param l  Lua state.
2987 */
CclDefineConversiblePlayerColors(lua_State * l)2988 static int CclDefineConversiblePlayerColors(lua_State *l)
2989 {
2990 	ConversiblePlayerColors.clear();
2991 
2992 	const unsigned int args = lua_gettop(l);
2993 	for (unsigned int i = 0; i < args; ++i) {
2994 		std::string player_color_name = LuaToString(l, i + 1);
2995 		int player_color = GetPlayerColorIndexByName(player_color_name);
2996 		if (player_color != -1) {
2997 			ConversiblePlayerColors.push_back(player_color);
2998 		} else {
2999 			LuaError(l, "Player color \"%s\" doesn't exist." _C_ player_color_name.c_str());
3000 		}
3001 	}
3002 
3003 	return 0;
3004 }
3005 
3006 // ----------------------------------------------------------------------------
3007 
3008 /**
3009 **  Get player data.
3010 **
3011 **  @param l  Lua state.
3012 */
CclGetPlayerData(lua_State * l)3013 static int CclGetPlayerData(lua_State *l)
3014 {
3015 	if (lua_gettop(l) < 2) {
3016 		LuaError(l, "incorrect argument");
3017 	}
3018 	lua_pushvalue(l, 1);
3019 	const CPlayer *p = CclGetPlayer(l);
3020 	lua_pop(l, 1);
3021 	const char *data = LuaToString(l, 2);
3022 
3023 	if (!strcmp(data, "Name")) {
3024 		lua_pushstring(l, p->Name.c_str());
3025 		return 1;
3026 	//Wyrmgus start
3027 	} else if (!strcmp(data, "Faction")) {
3028 		if (p->Race != -1 && p->Faction != -1) {
3029 			lua_pushstring(l, PlayerRaces.Factions[p->Faction]->Ident.c_str());
3030 		} else {
3031 			lua_pushstring(l, "");
3032 		}
3033 		return 1;
3034 	} else if (!strcmp(data, "Dynasty")) {
3035 		if (p->Dynasty) {
3036 			lua_pushstring(l, p->Dynasty->Ident.c_str());
3037 		} else {
3038 			lua_pushstring(l, "");
3039 		}
3040 		return 1;
3041 	//Wyrmgus end
3042 	} else if (!strcmp(data, "RaceName")) {
3043 		lua_pushstring(l, PlayerRaces.Name[p->Race].c_str());
3044 		return 1;
3045 	//Wyrmgus start
3046 	} else if (!strcmp(data, "Color")) {
3047 		bool found_color = false;
3048 		for (int i = 0; i < PlayerColorMax; ++i) {
3049 			if (PlayerColors[i][0] == p->Color) {
3050 				lua_pushstring(l, PlayerColorNames[i].c_str());
3051 				found_color = true;
3052 				break;
3053 			}
3054 		}
3055 		if (!found_color) {
3056 			LuaError(l, "Player %d has no color." _C_ p->Index);
3057 		}
3058 		return 1;
3059 	//Wyrmgus end
3060 	} else if (!strcmp(data, "Resources")) {
3061 		LuaCheckArgs(l, 3);
3062 
3063 		const std::string res = LuaToString(l, 3);
3064 		const int resId = GetResourceIdByName(l, res.c_str());
3065 		lua_pushnumber(l, p->Resources[resId] + p->StoredResources[resId]);
3066 		return 1;
3067 	} else if (!strcmp(data, "StoredResources")) {
3068 		LuaCheckArgs(l, 3);
3069 
3070 		const std::string res = LuaToString(l, 3);
3071 		const int resId = GetResourceIdByName(l, res.c_str());
3072 		lua_pushnumber(l, p->StoredResources[resId]);
3073 		return 1;
3074 	} else if (!strcmp(data, "MaxResources")) {
3075 		LuaCheckArgs(l, 3);
3076 
3077 		const std::string res = LuaToString(l, 3);
3078 		const int resId = GetResourceIdByName(l, res.c_str());
3079 		lua_pushnumber(l, p->MaxResources[resId]);
3080 		return 1;
3081 	//Wyrmgus start
3082 	} else if (!strcmp(data, "Prices")) {
3083 		LuaCheckArgs(l, 3);
3084 
3085 		const std::string res = LuaToString(l, 3);
3086 		const int resId = GetResourceIdByName(l, res.c_str());
3087 		lua_pushnumber(l, p->GetResourcePrice(resId));
3088 		return 1;
3089 	} else if (!strcmp(data, "ResourceDemand")) {
3090 		LuaCheckArgs(l, 3);
3091 
3092 		const std::string res = LuaToString(l, 3);
3093 		const int resId = GetResourceIdByName(l, res.c_str());
3094 		lua_pushnumber(l, p->ResourceDemand[resId]);
3095 		return 1;
3096 	} else if (!strcmp(data, "StoredResourceDemand")) {
3097 		LuaCheckArgs(l, 3);
3098 
3099 		const std::string res = LuaToString(l, 3);
3100 		const int resId = GetResourceIdByName(l, res.c_str());
3101 		lua_pushnumber(l, p->StoredResourceDemand[resId]);
3102 		return 1;
3103 	} else if (!strcmp(data, "EffectiveResourceDemand")) {
3104 		LuaCheckArgs(l, 3);
3105 
3106 		const std::string res = LuaToString(l, 3);
3107 		const int resId = GetResourceIdByName(l, res.c_str());
3108 		lua_pushnumber(l, p->GetEffectiveResourceDemand(resId));
3109 		return 1;
3110 	} else if (!strcmp(data, "EffectiveResourceSellPrice")) {
3111 		LuaCheckArgs(l, 3);
3112 
3113 		const std::string res = LuaToString(l, 3);
3114 		const int resId = GetResourceIdByName(l, res.c_str());
3115 		lua_pushnumber(l, p->GetEffectiveResourceSellPrice(resId));
3116 		return 1;
3117 	} else if (!strcmp(data, "EffectiveResourceBuyPrice")) {
3118 		LuaCheckArgs(l, 3);
3119 
3120 		const std::string res = LuaToString(l, 3);
3121 		const int resId = GetResourceIdByName(l, res.c_str());
3122 		lua_pushnumber(l, p->GetEffectiveResourceBuyPrice(resId));
3123 		return 1;
3124 	} else if (!strcmp(data, "TotalPriceDifferenceWith")) {
3125 		LuaCheckArgs(l, 3);
3126 
3127 		int other_player = LuaToNumber(l, 3);;
3128 
3129 		lua_pushnumber(l, p->GetTotalPriceDifferenceWith(Players[other_player]));
3130 		return 1;
3131 	} else if (!strcmp(data, "TradePotentialWith")) {
3132 		LuaCheckArgs(l, 3);
3133 
3134 		int other_player = LuaToNumber(l, 3);;
3135 
3136 		lua_pushnumber(l, p->GetTradePotentialWith(Players[other_player]));
3137 		return 1;
3138 	} else if (!strcmp(data, "HasHero")) {
3139 		LuaCheckArgs(l, 3);
3140 
3141 		CCharacter *hero = CCharacter::GetCharacter(LuaToString(l, 3));
3142 
3143 		lua_pushboolean(l, p->HasHero(hero));
3144 		return 1;
3145 	//Wyrmgus end
3146 	} else if (!strcmp(data, "UnitTypesCount")) {
3147 		LuaCheckArgs(l, 3);
3148 		CUnitType *type = CclGetUnitType(l);
3149 		Assert(type);
3150 		lua_pushnumber(l, p->GetUnitTypeCount(type));
3151 		return 1;
3152 	} else if (!strcmp(data, "UnitTypesUnderConstructionCount")) {
3153 		LuaCheckArgs(l, 3);
3154 		CUnitType *type = CclGetUnitType(l);
3155 		Assert(type);
3156 		lua_pushnumber(l, p->GetUnitTypeUnderConstructionCount(type));
3157 		return 1;
3158 	} else if (!strcmp(data, "UnitTypesAiActiveCount")) {
3159 		LuaCheckArgs(l, 3);
3160 		CUnitType *type = CclGetUnitType(l);
3161 		Assert(type);
3162 		lua_pushnumber(l, p->GetUnitTypeAiActiveCount(type));
3163 		return 1;
3164 	//Wyrmgus start
3165 	} else if (!strcmp(data, "Heroes")) {
3166 		lua_createtable(l, p->Heroes.size(), 0);
3167 		for (size_t i = 1; i <= p->Heroes.size(); ++i)
3168 		{
3169 			lua_pushstring(l, p->Heroes[i-1]->Character->Ident.c_str());
3170 			lua_rawseti(l, -2, i);
3171 		}
3172 		return 1;
3173 	//Wyrmgus end
3174 	} else if (!strcmp(data, "AiEnabled")) {
3175 		lua_pushboolean(l, p->AiEnabled);
3176 		return 1;
3177 	} else if (!strcmp(data, "TotalNumUnits")) {
3178 		lua_pushnumber(l, p->GetUnitCount());
3179 		return 1;
3180 	//Wyrmgus start
3181 	} else if (!strcmp(data, "TotalNumUnitsConstructed")) {
3182 		lua_pushnumber(l, p->GetUnitCount() - p->NumBuildingsUnderConstruction);
3183 		return 1;
3184 	//Wyrmgus end
3185 	} else if (!strcmp(data, "NumBuildings")) {
3186 		lua_pushnumber(l, p->NumBuildings);
3187 		return 1;
3188 	//Wyrmgus start
3189 	} else if (!strcmp(data, "NumBuildingsUnderConstruction")) {
3190 		lua_pushnumber(l, p->NumBuildingsUnderConstruction);
3191 		return 1;
3192 	} else if (!strcmp(data, "NumTownHalls")) {
3193 		lua_pushnumber(l, p->NumTownHalls);
3194 		return 1;
3195 	} else if (!strcmp(data, "NumHeroes")) {
3196 		lua_pushnumber(l, p->Heroes.size());
3197 		return 1;
3198 	} else if (!strcmp(data, "TradeCost")) {
3199 		lua_pushnumber(l, p->TradeCost);
3200 		return 1;
3201 	//Wyrmgus end
3202 	} else if (!strcmp(data, "Supply")) {
3203 		lua_pushnumber(l, p->Supply);
3204 		return 1;
3205 	} else if (!strcmp(data, "Demand")) {
3206 		lua_pushnumber(l, p->Demand);
3207 		return 1;
3208 	} else if (!strcmp(data, "UnitLimit")) {
3209 		lua_pushnumber(l, p->UnitLimit);
3210 		return 1;
3211 	} else if (!strcmp(data, "BuildingLimit")) {
3212 		lua_pushnumber(l, p->BuildingLimit);
3213 		return 1;
3214 	} else if (!strcmp(data, "TotalUnitLimit")) {
3215 		lua_pushnumber(l, p->TotalUnitLimit);
3216 		return 1;
3217 	} else if (!strcmp(data, "Score")) {
3218 		lua_pushnumber(l, p->Score);
3219 		return 1;
3220 	} else if (!strcmp(data, "TotalUnits")) {
3221 		lua_pushnumber(l, p->TotalUnits);
3222 		return 1;
3223 	} else if (!strcmp(data, "TotalBuildings")) {
3224 		lua_pushnumber(l, p->TotalBuildings);
3225 		return 1;
3226 	} else if (!strcmp(data, "TotalResources")) {
3227 		LuaCheckArgs(l, 3);
3228 
3229 		const std::string res = LuaToString(l, 3);
3230 		const int resId = GetResourceIdByName(l, res.c_str());
3231 		lua_pushnumber(l, p->TotalResources[resId]);
3232 		return 1;
3233 	} else if (!strcmp(data, "TotalRazings")) {
3234 		lua_pushnumber(l, p->TotalRazings);
3235 		return 1;
3236 	} else if (!strcmp(data, "TotalKills")) {
3237 		lua_pushnumber(l, p->TotalKills);
3238 		return 1;
3239 	//Wyrmgus start
3240 	} else if (!strcmp(data, "UnitTypeKills")) {
3241 		LuaCheckArgs(l, 3);
3242 		CUnitType *type = CclGetUnitType(l);
3243 		Assert(type);
3244 		lua_pushnumber(l, p->UnitTypeKills[type->Slot]);
3245 		return 1;
3246 	//Wyrmgus end
3247 	} else if (!strcmp(data, "SpeedResourcesHarvest")) {
3248 		LuaCheckArgs(l, 3);
3249 
3250 		const std::string res = LuaToString(l, 3);
3251 		const int resId = GetResourceIdByName(l, res.c_str());
3252 		lua_pushnumber(l, p->SpeedResourcesHarvest[resId]);
3253 		return 1;
3254 	} else if (!strcmp(data, "SpeedResourcesReturn")) {
3255 		LuaCheckArgs(l, 3);
3256 
3257 		const std::string res = LuaToString(l, 3);
3258 		const int resId = GetResourceIdByName(l, res.c_str());
3259 		lua_pushnumber(l, p->SpeedResourcesReturn[resId]);
3260 		return 1;
3261 	} else if (!strcmp(data, "SpeedBuild")) {
3262 		lua_pushnumber(l, p->SpeedBuild);
3263 		return 1;
3264 	} else if (!strcmp(data, "SpeedTrain")) {
3265 		lua_pushnumber(l, p->SpeedTrain);
3266 		return 1;
3267 	} else if (!strcmp(data, "SpeedUpgrade")) {
3268 		lua_pushnumber(l, p->SpeedUpgrade);
3269 		return 1;
3270 	} else if (!strcmp(data, "SpeedResearch")) {
3271 		lua_pushnumber(l, p->SpeedResearch);
3272 		return 1;
3273 	} else if (!strcmp(data, "Allow")) {
3274 		LuaCheckArgs(l, 3);
3275 		const char *ident = LuaToString(l, 3);
3276 		if (!strncmp(ident, "unit-", 5)) {
3277 			int id = UnitTypeIdByIdent(ident);
3278 			if (UnitIdAllowed(Players[p->Index], id) > 0) {
3279 				lua_pushstring(l, "A");
3280 			} else if (UnitIdAllowed(Players[p->Index], id) == 0) {
3281 				lua_pushstring(l, "F");
3282 			}
3283 		} else if (!strncmp(ident, "upgrade-", 8)) {
3284 			if (UpgradeIdentAllowed(Players[p->Index], ident) == 'A') {
3285 				lua_pushstring(l, "A");
3286 			} else if (UpgradeIdentAllowed(Players[p->Index], ident) == 'R') {
3287 				lua_pushstring(l, "R");
3288 			} else if (UpgradeIdentAllowed(Players[p->Index], ident) == 'F') {
3289 				lua_pushstring(l, "F");
3290 			}
3291 		} else {
3292 			DebugPrint(" wrong ident %s\n" _C_ ident);
3293 		}
3294 		return 1;
3295 	//Wyrmgus start
3296 	} else if (!strcmp(data, "HasContactWith")) {
3297 		LuaCheckArgs(l, 3);
3298 		int second_player = LuaToNumber(l, 3);
3299 		lua_pushboolean(l, p->HasContactWith(Players[second_player]));
3300 		return 1;
3301 	} else if (!strcmp(data, "HasQuest")) {
3302 		LuaCheckArgs(l, 3);
3303 		CQuest *quest = GetQuest(LuaToString(l, 3));
3304 		if (std::find(p->CurrentQuests.begin(), p->CurrentQuests.end(), quest) != p->CurrentQuests.end()) {
3305 			lua_pushboolean(l, true);
3306 		} else {
3307 			lua_pushboolean(l, false);
3308 		}
3309 		return 1;
3310 	} else if (!strcmp(data, "CompletedQuest")) {
3311 		LuaCheckArgs(l, 3);
3312 		CQuest *quest = GetQuest(LuaToString(l, 3));
3313 		if (std::find(p->CompletedQuests.begin(), p->CompletedQuests.end(), quest) != p->CompletedQuests.end()) {
3314 			lua_pushboolean(l, true);
3315 		} else {
3316 			lua_pushboolean(l, false);
3317 		}
3318 		return 1;
3319 	} else if (!strcmp(data, "FactionTitle")) {
3320 		lua_pushstring(l, p->GetFactionTitleName().c_str());
3321 		return 1;
3322 	} else if (!strcmp(data, "CharacterTitle")) {
3323 		LuaCheckArgs(l, 4);
3324 		std::string title_type_ident = LuaToString(l, 3);
3325 		std::string gender_ident = LuaToString(l, 4);
3326 		int title_type_id = GetCharacterTitleIdByName(title_type_ident);
3327 		int gender_id = GetGenderIdByName(gender_ident);
3328 
3329 		lua_pushstring(l, p->GetCharacterTitleName(title_type_id, gender_id).c_str());
3330 		return 1;
3331 	} else if (!strcmp(data, "HasSettlement")) {
3332 		LuaCheckArgs(l, 3);
3333 		std::string site_ident = LuaToString(l, 3);
3334 		CSite *site = CSite::GetSite(site_ident);
3335 		lua_pushboolean(l, p->HasSettlement(site));
3336 		return 1;
3337 	} else if (!strcmp(data, "SettlementName")) {
3338 		LuaCheckArgs(l, 3);
3339 		std::string site_ident = LuaToString(l, 3);
3340 		const CSite *site = CSite::GetSite(site_ident);
3341 		if (site) {
3342 			lua_pushstring(l, site->GetCulturalName(p->Race != -1 ? CCivilization::Civilizations[p->Race] : nullptr).c_str());
3343 		} else {
3344 			lua_pushstring(l, "");
3345 		}
3346 		return 1;
3347 	//Wyrmgus end
3348 	} else if (!strcmp(data, "Currency")) {
3349 		const CCurrency *currency = p->GetCurrency();
3350 		if (currency) {
3351 			lua_pushstring(l, currency->Name.c_str());
3352 		} else {
3353 			lua_pushstring(l, "");
3354 		}
3355 		return 1;
3356 	} else {
3357 		LuaError(l, "Invalid field: %s" _C_ data);
3358 	}
3359 
3360 	return 0;
3361 }
3362 
3363 /**
3364 **  Set player data.
3365 **
3366 **  @param l  Lua state.
3367 */
CclSetPlayerData(lua_State * l)3368 static int CclSetPlayerData(lua_State *l)
3369 {
3370 	if (lua_gettop(l) < 3) {
3371 		LuaError(l, "incorrect argument");
3372 	}
3373 	lua_pushvalue(l, 1);
3374 	CPlayer *p = CclGetPlayer(l);
3375 	lua_pop(l, 1);
3376 	const char *data = LuaToString(l, 2);
3377 
3378 	//Wyrmgus start
3379 	//if player is unused, return
3380 	if (p->Type == PlayerNobody && Editor.Running == EditorNotRunning) {
3381 		return 0;
3382 	}
3383 	//Wyrmgus end
3384 
3385 	if (!strcmp(data, "Name")) {
3386 		p->SetName(LuaToString(l, 3));
3387 	} else if (!strcmp(data, "RaceName")) {
3388 		if (GameRunning) {
3389 			p->SetFaction(nullptr);
3390 		}
3391 
3392 		const char *civilization_ident = LuaToString(l, 3);
3393 		CCivilization *civilization = CCivilization::GetCivilization(civilization_ident);
3394 		if (civilization) {
3395 			p->SetCivilization(civilization->ID);
3396 		}
3397 	//Wyrmgus start
3398 	} else if (!strcmp(data, "Faction")) {
3399 		std::string faction_name = LuaToString(l, 3);
3400 		if (faction_name == "random") {
3401 			p->SetRandomFaction();
3402 		} else {
3403 			p->SetFaction(PlayerRaces.GetFaction(faction_name));
3404 		}
3405 	} else if (!strcmp(data, "Dynasty")) {
3406 		std::string dynasty_ident = LuaToString(l, 3);
3407 		p->SetDynasty(PlayerRaces.GetDynasty(dynasty_ident));
3408 	//Wyrmgus end
3409 	} else if (!strcmp(data, "Resources")) {
3410 		LuaCheckArgs(l, 4);
3411 
3412 		const std::string res = LuaToString(l, 3);
3413 		const int resId = GetResourceIdByName(l, res.c_str());
3414 		p->SetResource(resId, LuaToNumber(l, 4));
3415 	} else if (!strcmp(data, "StoredResources")) {
3416 		LuaCheckArgs(l, 4);
3417 
3418 		const std::string res = LuaToString(l, 3);
3419 		const int resId = GetResourceIdByName(l, res.c_str());
3420 		p->SetResource(resId, LuaToNumber(l, 4), STORE_BUILDING);
3421 		// } else if (!strcmp(data, "UnitTypesCount")) {
3422 		// } else if (!strcmp(data, "AiEnabled")) {
3423 		// } else if (!strcmp(data, "TotalNumUnits")) {
3424 		// } else if (!strcmp(data, "NumBuildings")) {
3425 		// } else if (!strcmp(data, "Supply")) {
3426 		// } else if (!strcmp(data, "Demand")) {
3427 	} else if (!strcmp(data, "UnitLimit")) {
3428 		p->UnitLimit = LuaToNumber(l, 3);
3429 	} else if (!strcmp(data, "BuildingLimit")) {
3430 		p->BuildingLimit = LuaToNumber(l, 3);
3431 	} else if (!strcmp(data, "TotalUnitLimit")) {
3432 		p->TotalUnitLimit = LuaToNumber(l, 3);
3433 	} else if (!strcmp(data, "Score")) {
3434 		p->Score = LuaToNumber(l, 3);
3435 	} else if (!strcmp(data, "TotalUnits")) {
3436 		p->TotalUnits = LuaToNumber(l, 3);
3437 	} else if (!strcmp(data, "TotalBuildings")) {
3438 		p->TotalBuildings = LuaToNumber(l, 3);
3439 	} else if (!strcmp(data, "TotalResources")) {
3440 		LuaCheckArgs(l, 4);
3441 
3442 		const std::string res = LuaToString(l, 3);
3443 		const int resId = GetResourceIdByName(l, res.c_str());
3444 		p->TotalResources[resId] = LuaToNumber(l, 4);
3445 	} else if (!strcmp(data, "TotalRazings")) {
3446 		p->TotalRazings = LuaToNumber(l, 3);
3447 	} else if (!strcmp(data, "TotalKills")) {
3448 		p->TotalKills = LuaToNumber(l, 3);
3449 	} else if (!strcmp(data, "SpeedResourcesHarvest")) {
3450 		LuaCheckArgs(l, 4);
3451 
3452 		const std::string res = LuaToString(l, 3);
3453 		const int resId = GetResourceIdByName(l, res.c_str());
3454 		p->SpeedResourcesHarvest[resId] = LuaToNumber(l, 4);
3455 	} else if (!strcmp(data, "SpeedResourcesReturn")) {
3456 		LuaCheckArgs(l, 4);
3457 
3458 		const std::string res = LuaToString(l, 3);
3459 		const int resId = GetResourceIdByName(l, res.c_str());
3460 		p->SpeedResourcesReturn[resId] = LuaToNumber(l, 4);
3461 	} else if (!strcmp(data, "SpeedBuild")) {
3462 		p->SpeedBuild = LuaToNumber(l, 3);
3463 	} else if (!strcmp(data, "SpeedTrain")) {
3464 		p->SpeedTrain = LuaToNumber(l, 3);
3465 	} else if (!strcmp(data, "SpeedUpgrade")) {
3466 		p->SpeedUpgrade = LuaToNumber(l, 3);
3467 	} else if (!strcmp(data, "SpeedResearch")) {
3468 		p->SpeedResearch = LuaToNumber(l, 3);
3469 	} else if (!strcmp(data, "Allow")) {
3470 		LuaCheckArgs(l, 4);
3471 		const char *ident = LuaToString(l, 3);
3472 		const std::string acquire = LuaToString(l, 4);
3473 
3474 		if (!strncmp(ident, "upgrade-", 8)) {
3475 			if (acquire == "R" && UpgradeIdentAllowed(*p, ident) != 'R') {
3476 				UpgradeAcquire(*p, CUpgrade::Get(ident));
3477 			} else if (acquire == "F" || acquire == "A") {
3478 				if (UpgradeIdentAllowed(*p, ident) == 'R') {
3479 					UpgradeLost(*p, CUpgrade::Get(ident)->ID);
3480 				}
3481 				AllowUpgradeId(*p, UpgradeIdByIdent(ident), acquire[0]);
3482 			}
3483 		//Wyrmgus start
3484 		} else if (!strncmp(ident, "unit-", 5)) {
3485 			const int UnitMax = 65536; /// How many units supported
3486 			int id = UnitTypeIdByIdent(ident);
3487 			if (acquire == "A" || acquire == "R") {
3488 				AllowUnitId(*p, id, UnitMax);
3489 			} else if (acquire == "F") {
3490 				AllowUnitId(*p, id, 0);
3491 			}
3492 		//Wyrmgus end
3493 		} else {
3494 			LuaError(l, " wrong ident %s\n" _C_ ident);
3495 		}
3496 	//Wyrmgus start
3497 	} else if (!strcmp(data, "AiEnabled")) {
3498 		p->AiEnabled = LuaToBoolean(l, 3);
3499 	} else if (!strcmp(data, "Team")) {
3500 		p->Team = LuaToNumber(l, 3);
3501 	} else if (!strcmp(data, "AcceptQuest")) {
3502 		CQuest *quest = GetQuest(LuaToString(l, 3));
3503 		if (quest) {
3504 			p->AcceptQuest(quest);
3505 		}
3506 	} else if (!strcmp(data, "CompleteQuest")) {
3507 		CQuest *quest = GetQuest(LuaToString(l, 3));
3508 		if (quest) {
3509 			p->CompleteQuest(quest);
3510 		}
3511 	} else if (!strcmp(data, "FailQuest")) {
3512 		CQuest *quest = GetQuest(LuaToString(l, 3));
3513 		if (quest) {
3514 			p->FailQuest(quest);
3515 		}
3516 	} else if (!strcmp(data, "AddModifier")) {
3517 		LuaCheckArgs(l, 4);
3518 		CUpgrade *modifier_upgrade = CUpgrade::Get(LuaToString(l, 3));
3519 		int cycles = LuaToNumber(l, 4);
3520 		if (modifier_upgrade) {
3521 			p->AddModifier(modifier_upgrade, cycles);
3522 		}
3523 	//Wyrmgus end
3524 	} else {
3525 		LuaError(l, "Invalid field: %s" _C_ data);
3526 	}
3527 
3528 	return 0;
3529 }
3530 
3531 /**
3532 **  Set ai player algo.
3533 **
3534 **  @param l  Lua state.
3535 */
CclSetAiType(lua_State * l)3536 static int CclSetAiType(lua_State *l)
3537 {
3538 	CPlayer *p;
3539 
3540 	if (lua_gettop(l) < 2) {
3541 		LuaError(l, "incorrect argument");
3542 	}
3543 	lua_pushvalue(l, 1);
3544 	p = CclGetPlayer(l);
3545 	lua_pop(l, 1);
3546 
3547 	p->AiName = LuaToString(l, 2);
3548 
3549 	return 0;
3550 }
3551 
3552 //Wyrmgus start
3553 /**
3554 **  Init ai for player.
3555 **
3556 **  @param l  Lua state.
3557 */
CclInitAi(lua_State * l)3558 static int CclInitAi(lua_State *l)
3559 {
3560 	CPlayer *p;
3561 
3562 	if (lua_gettop(l) < 1) {
3563 		LuaError(l, "incorrect argument");
3564 	}
3565 	lua_pushvalue(l, 1);
3566 	p = CclGetPlayer(l);
3567 	lua_pop(l, 1);
3568 
3569 	AiInit(*p);
3570 
3571 	return 0;
3572 }
3573 
CclGetLanguages(lua_State * l)3574 static int CclGetLanguages(lua_State *l)
3575 {
3576 	bool only_used = false;
3577 	if (lua_gettop(l) >= 1) {
3578 		only_used = LuaToBoolean(l, 1);
3579 	}
3580 
3581 	std::vector<std::string> languages;
3582 	for (size_t i = 0; i != PlayerRaces.Languages.size(); ++i) {
3583 		if (!only_used || PlayerRaces.Languages[i]->UsedByCivilizationOrFaction) {
3584 			languages.push_back(PlayerRaces.Languages[i]->Ident);
3585 		}
3586 	}
3587 
3588 	lua_createtable(l, languages.size(), 0);
3589 	for (size_t i = 1; i <= languages.size(); ++i)
3590 	{
3591 		lua_pushstring(l, languages[i-1].c_str());
3592 		lua_rawseti(l, -2, i);
3593 	}
3594 	return 1;
3595 }
3596 
3597 /**
3598 **  Get language data.
3599 **
3600 **  @param l  Lua state.
3601 */
CclGetLanguageData(lua_State * l)3602 static int CclGetLanguageData(lua_State *l)
3603 {
3604 	if (lua_gettop(l) < 2) {
3605 		LuaError(l, "incorrect argument");
3606 	}
3607 	std::string language_name = LuaToString(l, 1);
3608 	const CLanguage *language = PlayerRaces.GetLanguage(language_name);
3609 	if (!language) {
3610 		LuaError(l, "Language \"%s\" doesn't exist." _C_ language_name.c_str());
3611 	}
3612 	const char *data = LuaToString(l, 2);
3613 
3614 	if (!strcmp(data, "Name")) {
3615 		lua_pushstring(l, language->Name.c_str());
3616 		return 1;
3617 	} else if (!strcmp(data, "Family")) {
3618 		lua_pushstring(l, language->Family.c_str());
3619 		return 1;
3620 	} else if (!strcmp(data, "Words")) {
3621 		lua_createtable(l, language->LanguageWords.size(), 0);
3622 		for (size_t i = 1; i <= language->LanguageWords.size(); ++i)
3623 		{
3624 			lua_pushstring(l, language->LanguageWords[i-1]->Word.c_str());
3625 			lua_rawseti(l, -2, i);
3626 		}
3627 		return 1;
3628 	} else {
3629 		LuaError(l, "Invalid field: %s" _C_ data);
3630 	}
3631 
3632 	return 0;
3633 }
3634 
3635 /**
3636 **  Get language word data.
3637 **
3638 **  @param l  Lua state.
3639 */
CclGetLanguageWordData(lua_State * l)3640 static int CclGetLanguageWordData(lua_State *l)
3641 {
3642 	if (lua_gettop(l) < 3) {
3643 		LuaError(l, "incorrect argument");
3644 	}
3645 	std::string language_name = LuaToString(l, 1);
3646 	const CLanguage *language = PlayerRaces.GetLanguage(language_name);
3647 	if (!language) {
3648 		LuaError(l, "Language \"%s\" doesn't exist." _C_ language_name.c_str());
3649 	}
3650 
3651 	std::string word_name = LuaToString(l, 2);
3652 	std::vector<std::string> word_meanings;
3653 	const LanguageWord *word = language->GetWord(word_name, -1, word_meanings);
3654 	if (word == nullptr) {
3655 		LuaError(l, "Word \"%s\" doesn't exist for the \"%s\" language." _C_ word_name.c_str() _C_ language_name.c_str());
3656 	}
3657 
3658 	const char *data = LuaToString(l, 3);
3659 
3660 	if (!strcmp(data, "Type")) {
3661 		if (word->Type != -1) {
3662 			lua_pushstring(l, GetWordTypeNameById(word->Type).c_str());
3663 		} else {
3664 			lua_pushstring(l, "");
3665 		}
3666 		return 1;
3667 	} else if (!strcmp(data, "Meaning")) {
3668 		for (size_t i = 0; i < word->Meanings.size(); ++i) {
3669 			lua_pushstring(l, word->Meanings[i].c_str());
3670 			return 1;
3671 		}
3672 		lua_pushstring(l, "");
3673 		return 1;
3674 	} else if (!strcmp(data, "Gender")) {
3675 		if (word->Gender != -1) {
3676 			lua_pushstring(l, GetGrammaticalGenderNameById(word->Gender).c_str());
3677 		} else {
3678 			lua_pushstring(l, "");
3679 		}
3680 		return 1;
3681 	} else {
3682 		LuaError(l, "Invalid field: %s" _C_ data);
3683 	}
3684 
3685 	return 0;
3686 }
3687 
CclGetReligions(lua_State * l)3688 static int CclGetReligions(lua_State *l)
3689 {
3690 	lua_createtable(l, CReligion::Religions.size(), 0);
3691 	for (size_t i = 1; i <= CReligion::Religions.size(); ++i)
3692 	{
3693 		lua_pushstring(l, CReligion::Religions[i-1]->Ident.c_str());
3694 		lua_rawseti(l, -2, i);
3695 	}
3696 	return 1;
3697 }
3698 
CclGetDeityDomains(lua_State * l)3699 static int CclGetDeityDomains(lua_State *l)
3700 {
3701 	lua_createtable(l, CDeityDomain::DeityDomains.size(), 0);
3702 	for (size_t i = 1; i <= CDeityDomain::DeityDomains.size(); ++i)
3703 	{
3704 		lua_pushstring(l, CDeityDomain::DeityDomains[i-1]->Ident.c_str());
3705 		lua_rawseti(l, -2, i);
3706 	}
3707 	return 1;
3708 }
3709 
CclGetDeities(lua_State * l)3710 static int CclGetDeities(lua_State *l)
3711 {
3712 	lua_createtable(l, CDeity::Deities.size(), 0);
3713 	for (size_t i = 1; i <= CDeity::Deities.size(); ++i)
3714 	{
3715 		lua_pushstring(l, CDeity::Deities[i-1]->Ident.c_str());
3716 		lua_rawseti(l, -2, i);
3717 	}
3718 	return 1;
3719 }
3720 
3721 /**
3722 **  Get religion data.
3723 **
3724 **  @param l  Lua state.
3725 */
CclGetReligionData(lua_State * l)3726 static int CclGetReligionData(lua_State *l)
3727 {
3728 	if (lua_gettop(l) < 2) {
3729 		LuaError(l, "incorrect argument");
3730 	}
3731 	std::string religion_ident = LuaToString(l, 1);
3732 	const CReligion *religion = CReligion::GetReligion(religion_ident);
3733 	if (!religion) {
3734 		return 0;
3735 	}
3736 	const char *data = LuaToString(l, 2);
3737 
3738 	if (!strcmp(data, "Name")) {
3739 		lua_pushstring(l, religion->Name.c_str());
3740 		return 1;
3741 	} else if (!strcmp(data, "Description")) {
3742 		lua_pushstring(l, religion->Description.c_str());
3743 		return 1;
3744 	} else if (!strcmp(data, "Background")) {
3745 		lua_pushstring(l, religion->Background.c_str());
3746 		return 1;
3747 	} else if (!strcmp(data, "Quote")) {
3748 		lua_pushstring(l, religion->Quote.c_str());
3749 		return 1;
3750 	} else if (!strcmp(data, "CulturalDeities")) {
3751 		lua_pushboolean(l, religion->CulturalDeities);
3752 		return 1;
3753 	} else {
3754 		LuaError(l, "Invalid field: %s" _C_ data);
3755 	}
3756 
3757 	return 0;
3758 }
3759 
3760 /**
3761 **  Get deity domain data.
3762 **
3763 **  @param l  Lua state.
3764 */
CclGetDeityDomainData(lua_State * l)3765 static int CclGetDeityDomainData(lua_State *l)
3766 {
3767 	if (lua_gettop(l) < 2) {
3768 		LuaError(l, "incorrect argument");
3769 	}
3770 	std::string deity_domain_ident = LuaToString(l, 1);
3771 	const CDeityDomain *deity_domain = CDeityDomain::GetDeityDomain(deity_domain_ident);
3772 	if (!deity_domain) {
3773 		return 0;
3774 	}
3775 	const char *data = LuaToString(l, 2);
3776 
3777 	if (!strcmp(data, "Name")) {
3778 		lua_pushstring(l, deity_domain->Name.c_str());
3779 		return 1;
3780 	} else if (!strcmp(data, "Abilities")) {
3781 		lua_createtable(l, deity_domain->Abilities.size(), 0);
3782 		for (size_t i = 1; i <= deity_domain->Abilities.size(); ++i)
3783 		{
3784 			lua_pushstring(l, deity_domain->Abilities[i-1]->Ident.c_str());
3785 			lua_rawseti(l, -2, i);
3786 		}
3787 		return 1;
3788 	} else {
3789 		LuaError(l, "Invalid field: %s" _C_ data);
3790 	}
3791 
3792 	return 0;
3793 }
3794 
3795 /**
3796 **  Get deity data.
3797 **
3798 **  @param l  Lua state.
3799 */
CclGetDeityData(lua_State * l)3800 static int CclGetDeityData(lua_State *l)
3801 {
3802 	if (lua_gettop(l) < 2) {
3803 		LuaError(l, "incorrect argument");
3804 	}
3805 	std::string deity_ident = LuaToString(l, 1);
3806 	const CDeity *deity = CDeity::GetDeity(deity_ident);
3807 	if (!deity) {
3808 		return 0;
3809 	}
3810 	const char *data = LuaToString(l, 2);
3811 
3812 	if (!strcmp(data, "Name")) {
3813 		lua_pushstring(l, deity->Name.c_str());
3814 		return 1;
3815 	} else if (!strcmp(data, "Pantheon")) {
3816 		if (deity->Pantheon) {
3817 			lua_pushstring(l, deity->Pantheon->Name.c_str());
3818 		} else {
3819 			lua_pushstring(l, "");
3820 		}
3821 		return 1;
3822 	} else if (!strcmp(data, "Description")) {
3823 		lua_pushstring(l, deity->Description.c_str());
3824 		return 1;
3825 	} else if (!strcmp(data, "Background")) {
3826 		lua_pushstring(l, deity->Background.c_str());
3827 		return 1;
3828 	} else if (!strcmp(data, "Quote")) {
3829 		lua_pushstring(l, deity->Quote.c_str());
3830 		return 1;
3831 	} else if (!strcmp(data, "Major")) {
3832 		lua_pushboolean(l, deity->Major);
3833 		return 1;
3834 	} else if (!strcmp(data, "HomePlane")) {
3835 		if (deity->HomePlane) {
3836 			lua_pushstring(l, deity->HomePlane->Ident.c_str());
3837 		} else {
3838 			lua_pushstring(l, "");
3839 		}
3840 		return 1;
3841 	} else if (!strcmp(data, "Icon")) {
3842 		lua_pushstring(l, deity->Icon.Name.c_str());
3843 		return 1;
3844 	} else if (!strcmp(data, "Civilizations")) {
3845 		lua_createtable(l, deity->Civilizations.size(), 0);
3846 		for (size_t i = 1; i <= deity->Civilizations.size(); ++i)
3847 		{
3848 			lua_pushstring(l, PlayerRaces.Name[deity->Civilizations[i-1]->ID].c_str());
3849 			lua_rawseti(l, -2, i);
3850 		}
3851 		return 1;
3852 	} else if (!strcmp(data, "Religions")) {
3853 		lua_createtable(l, deity->Religions.size(), 0);
3854 		for (size_t i = 1; i <= deity->Religions.size(); ++i)
3855 		{
3856 			lua_pushstring(l, deity->Religions[i-1]->Ident.c_str());
3857 			lua_rawseti(l, -2, i);
3858 		}
3859 		return 1;
3860 	} else if (!strcmp(data, "Domains")) {
3861 		lua_createtable(l, deity->Domains.size(), 0);
3862 		for (size_t i = 1; i <= deity->Domains.size(); ++i)
3863 		{
3864 			lua_pushstring(l, deity->Domains[i-1]->Ident.c_str());
3865 			lua_rawseti(l, -2, i);
3866 		}
3867 		return 1;
3868 	} else if (!strcmp(data, "Abilities")) {
3869 		lua_createtable(l, deity->Abilities.size(), 0);
3870 		for (size_t i = 1; i <= deity->Abilities.size(); ++i)
3871 		{
3872 			lua_pushstring(l, deity->Abilities[i-1]->Ident.c_str());
3873 			lua_rawseti(l, -2, i);
3874 		}
3875 		return 1;
3876 	} else if (!strcmp(data, "CulturalName")) {
3877 		if (lua_gettop(l) < 3) {
3878 			LuaError(l, "incorrect argument");
3879 		}
3880 
3881 		const CCivilization *civilization = CCivilization::GetCivilization(LuaToString(l, 3));
3882 		lua_pushstring(l, deity->GetCulturalName(civilization).c_str());
3883 
3884 		return 1;
3885 	} else if (!strcmp(data, "Gender")) {
3886 		lua_pushstring(l, GetGenderNameById(deity->Gender).c_str());
3887 		return 1;
3888 	} else {
3889 		LuaError(l, "Invalid field: %s" _C_ data);
3890 	}
3891 
3892 	return 0;
3893 }
3894 //Wyrmgus end
3895 
3896 // ----------------------------------------------------------------------------
3897 
3898 /**
3899 **  Register CCL features for players.
3900 */
PlayerCclRegister()3901 void PlayerCclRegister()
3902 {
3903 	lua_register(Lua, "Player", CclPlayer);
3904 	lua_register(Lua, "ChangeUnitsOwner", CclChangeUnitsOwner);
3905 	lua_register(Lua, "GetThisPlayer", CclGetThisPlayer);
3906 	lua_register(Lua, "SetThisPlayer", CclSetThisPlayer);
3907 
3908 	lua_register(Lua, "SetMaxSelectable", CclSetMaxSelectable);
3909 
3910 	lua_register(Lua, "SetAllPlayersUnitLimit", CclSetAllPlayersUnitLimit);
3911 	lua_register(Lua, "SetAllPlayersBuildingLimit", CclSetAllPlayersBuildingLimit);
3912 	lua_register(Lua, "SetAllPlayersTotalUnitLimit", CclSetAllPlayersTotalUnitLimit);
3913 
3914 	lua_register(Lua, "SetDiplomacy", CclSetDiplomacy);
3915 	lua_register(Lua, "Diplomacy", CclDiplomacy);
3916 	lua_register(Lua, "SetSharedVision", CclSetSharedVision);
3917 	lua_register(Lua, "SharedVision", CclSharedVision);
3918 
3919 	//Wyrmgus start
3920 	lua_register(Lua, "DefineCivilization", CclDefineCivilization);
3921 	lua_register(Lua, "DefineLanguageWord", CclDefineLanguageWord);
3922 	lua_register(Lua, "GetCivilizationData", CclGetCivilizationData);
3923 	lua_register(Lua, "GetCivilizationClassUnitType", CclGetCivilizationClassUnitType);
3924 	lua_register(Lua, "GetFactionClassUnitType", CclGetFactionClassUnitType);
3925 	lua_register(Lua, "DefineFaction", CclDefineFaction);
3926 	lua_register(Lua, "DefineDynasty", CclDefineDynasty);
3927 	lua_register(Lua, "DefineReligion", CclDefineReligion);
3928 	lua_register(Lua, "DefineDeity", CclDefineDeity);
3929 	lua_register(Lua, "DefineLanguage", CclDefineLanguage);
3930 	lua_register(Lua, "GetCivilizations", CclGetCivilizations);
3931 	lua_register(Lua, "GetFactions", CclGetFactions);
3932 	lua_register(Lua, "GetDynasties", CclGetDynasties);
3933 	lua_register(Lua, "GetPlayerColors", CclGetPlayerColors);
3934 	lua_register(Lua, "GetFactionData", CclGetFactionData);
3935 	lua_register(Lua, "GetDynastyData", CclGetDynastyData);
3936 	//Wyrmgus end
3937 	lua_register(Lua, "DefinePlayerColors", CclDefinePlayerColors);
3938 	lua_register(Lua, "DefinePlayerColorIndex", CclDefinePlayerColorIndex);
3939 
3940 	lua_register(Lua, "NewColors", CclNewPlayerColors);
3941 
3942 	lua_register(Lua, "DefineConversiblePlayerColors", CclDefineConversiblePlayerColors);
3943 
3944 	// player member access functions
3945 	lua_register(Lua, "GetPlayerData", CclGetPlayerData);
3946 	lua_register(Lua, "SetPlayerData", CclSetPlayerData);
3947 	lua_register(Lua, "SetAiType", CclSetAiType);
3948 	//Wyrmgus start
3949 	lua_register(Lua, "InitAi", CclInitAi);
3950 	lua_register(Lua, "GetLanguages", CclGetLanguages);
3951 	lua_register(Lua, "GetLanguageData", CclGetLanguageData);
3952 	lua_register(Lua, "GetLanguageWordData", CclGetLanguageWordData);
3953 
3954 	lua_register(Lua, "GetReligions", CclGetReligions);
3955 	lua_register(Lua, "GetDeityDomains", CclGetDeityDomains);
3956 	lua_register(Lua, "GetDeities", CclGetDeities);
3957 	lua_register(Lua, "GetReligionData", CclGetReligionData);
3958 	lua_register(Lua, "GetDeityDomainData", CclGetDeityDomainData);
3959 	lua_register(Lua, "GetDeityData", CclGetDeityData);
3960 	//Wyrmgus end
3961 }
3962