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_character.cpp - The character ccl functions. */
12 //
13 // (c) Copyright 2015-2019 by Andrettin
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 //@{
31
32 /*----------------------------------------------------------------------------
33 -- Includes
34 ----------------------------------------------------------------------------*/
35
36 #include "stratagus.h"
37
38 #include "character.h"
39
40 #include "civilization.h"
41 #include "grand_strategy.h"
42 #include "map/historical_location.h"
43 #include "map/map_template.h"
44 #include "map/site.h"
45 #include "player.h"
46 #include "province.h"
47 #include "quest.h"
48 #include "religion/deity.h"
49 #include "script.h"
50 #include "spells.h"
51 #include "time/timeline.h"
52 #include "unit/unittype.h"
53 #include "upgrade/upgrade.h"
54
55 #include "../ai/ai_local.h" //for using AiHelpers
56
57 /*----------------------------------------------------------------------------
58 -- Variables
59 ----------------------------------------------------------------------------*/
60
61 /*----------------------------------------------------------------------------
62 -- Functions
63 ----------------------------------------------------------------------------*/
64
65 /**
66 ** Define a character.
67 **
68 ** @param l Lua state.
69 */
CclDefineCharacter(lua_State * l)70 static int CclDefineCharacter(lua_State *l)
71 {
72 LuaCheckArgs(l, 2);
73 if (!lua_istable(l, 2)) {
74 LuaError(l, "incorrect argument (expected table)");
75 }
76
77 std::string character_ident = LuaToString(l, 1);
78 CCharacter *character = CCharacter::GetCharacter(character_ident, false);
79 bool redefinition = false;
80 if (!character) {
81 if (LoadingPersistentHeroes) {
82 fprintf(stderr, "Character \"%s\" has persistent data, but doesn't exist.", character_ident.c_str());
83 return 0;
84 }
85 character = CCharacter::GetOrAddCharacter(character_ident);
86 } else {
87 redefinition = true;
88 if (!LoadingPersistentHeroes) {
89 fprintf(stderr, "Character \"%s\" is being redefined.\n", character_ident.c_str());
90 }
91 }
92
93 std::string faction_ident;
94 std::vector<std::string> alternate_names;
95
96 // Parse the list:
97 for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
98 const char *value = LuaToString(l, -2);
99
100 if (!strcmp(value, "Name")) {
101 character->Name = LuaToString(l, -1);
102 } else if (!strcmp(value, "AlternateNames")) { // alternate names the character may have, used for building the civilization's personal names
103 const int args = lua_rawlen(l, -1);
104 for (int j = 0; j < args; ++j) {
105 alternate_names.push_back(LuaToString(l, -1, j + 1));
106 }
107 } else if (!strcmp(value, "ExtraName")) {
108 character->ExtraName = LuaToString(l, -1);
109 } else if (!strcmp(value, "FamilyName")) {
110 character->FamilyName = LuaToString(l, -1);
111 } else if (!strcmp(value, "Description")) {
112 character->Description = LuaToString(l, -1);
113 } else if (!strcmp(value, "Background")) {
114 character->Background = LuaToString(l, -1);
115 } else if (!strcmp(value, "Quote")) {
116 character->Quote = LuaToString(l, -1);
117 } else if (!strcmp(value, "Variation")) { //to keep backwards compatibility
118 character->HairVariation = LuaToString(l, -1);
119 } else if (!strcmp(value, "HairVariation")) {
120 character->HairVariation = LuaToString(l, -1);
121 } else if (!strcmp(value, "Type")) {
122 std::string unit_type_ident = LuaToString(l, -1);
123 int unit_type_id = UnitTypeIdByIdent(unit_type_ident);
124 if (unit_type_id != -1) {
125 if (character->Type == nullptr || character->Type == UnitTypes[unit_type_id] || character->Type->CanExperienceUpgradeTo(UnitTypes[unit_type_id])) {
126 character->Type = const_cast<CUnitType *>(&(*UnitTypes[unit_type_id]));
127 if (character->Level < character->Type->DefaultStat.Variables[LEVEL_INDEX].Value) {
128 character->Level = character->Type->DefaultStat.Variables[LEVEL_INDEX].Value;
129 }
130 }
131 } else {
132 LuaError(l, "Unit type \"%s\" doesn't exist." _C_ unit_type_ident.c_str());
133 }
134 } else if (!strcmp(value, "Trait")) {
135 std::string trait_ident = LuaToString(l, -1);
136 int upgrade_id = UpgradeIdByIdent(trait_ident);
137 if (upgrade_id != -1) {
138 character->Trait = AllUpgrades[upgrade_id];
139 } else {
140 LuaError(l, "Trait upgrade \"%s\" doesn't exist." _C_ trait_ident.c_str());
141 }
142 } else if (!strcmp(value, "BirthDate")) {
143 CclGetDate(l, &character->BirthDate);
144 } else if (!strcmp(value, "StartDate")) {
145 CclGetDate(l, &character->StartDate);
146 } else if (!strcmp(value, "DeathDate")) {
147 CclGetDate(l, &character->DeathDate);
148 } else if (!strcmp(value, "ViolentDeath")) {
149 character->ViolentDeath = LuaToBoolean(l, -1);
150 } else if (!strcmp(value, "Civilization")) {
151 character->Civilization = CCivilization::GetCivilization(LuaToString(l, -1));
152 } else if (!strcmp(value, "Faction")) {
153 CFaction *faction = PlayerRaces.GetFaction(LuaToString(l, -1));
154 if (faction != nullptr) {
155 character->Faction = faction;
156 } else {
157 LuaError(l, "Faction \"%s\" doesn't exist." _C_ faction_ident.c_str());
158 }
159 } else if (!strcmp(value, "Father")) {
160 std::string father_ident = LuaToString(l, -1);
161 CCharacter *father = CCharacter::GetCharacter(father_ident);
162 if (father) {
163 if (father->Gender == MaleGender) {
164 character->Father = const_cast<CCharacter *>(&(*father));
165 if (!father->IsParentOf(character_ident)) { //check whether the character has already been set as a child of the father
166 father->Children.push_back(character);
167 }
168 // see if the father's other children aren't already included in the character's siblings, and if they aren't, add them (and add the character to the siblings' sibling list, of course)
169 for (size_t i = 0; i < father->Children.size(); ++i) {
170 if (father->Children[i]->Ident != character_ident) {
171 if (!character->IsSiblingOf(father->Children[i]->Ident)) {
172 character->Siblings.push_back(father->Children[i]);
173 }
174 if (!father->Children[i]->IsSiblingOf(character_ident)) {
175 father->Children[i]->Siblings.push_back(character);
176 }
177 }
178 }
179 } else {
180 LuaError(l, "Character \"%s\" set to be the biological father of \"%s\", but isn't male." _C_ father_ident.c_str() _C_ character_ident.c_str());
181 }
182 } else {
183 LuaError(l, "Character \"%s\" doesn't exist." _C_ father_ident.c_str());
184 }
185 } else if (!strcmp(value, "Mother")) {
186 std::string mother_ident = LuaToString(l, -1);
187 CCharacter *mother = CCharacter::GetCharacter(mother_ident);
188 if (mother) {
189 if (mother->Gender == FemaleGender) {
190 character->Mother = const_cast<CCharacter *>(&(*mother));
191 if (!mother->IsParentOf(character_ident)) { //check whether the character has already been set as a child of the mother
192 mother->Children.push_back(character);
193 }
194 // see if the mother's other children aren't already included in the character's siblings, and if they aren't, add them (and add the character to the siblings' sibling list, of course)
195 for (size_t i = 0; i < mother->Children.size(); ++i) {
196 if (mother->Children[i]->Ident != character_ident) {
197 if (!character->IsSiblingOf(mother->Children[i]->Ident)) {
198 character->Siblings.push_back(mother->Children[i]);
199 }
200 if (!mother->Children[i]->IsSiblingOf(character_ident)) {
201 mother->Children[i]->Siblings.push_back(character);
202 }
203 }
204 }
205 } else {
206 LuaError(l, "Character \"%s\" set to be the biological mother of \"%s\", but isn't female (gender is \"%s\")." _C_ mother_ident.c_str() _C_ character_ident.c_str() _C_ GetGenderNameById(mother->Gender).c_str());
207 }
208 } else {
209 LuaError(l, "Character \"%s\" doesn't exist." _C_ mother_ident.c_str());
210 }
211 } else if (!strcmp(value, "Children")) {
212 const int args = lua_rawlen(l, -1);
213 for (int j = 0; j < args; ++j) {
214 std::string child_ident = LuaToString(l, -1, j + 1);
215 CCharacter *child = CCharacter::GetCharacter(child_ident);
216 if (child) {
217 if (character->Gender == MaleGender) {
218 child->Father = character;
219 } else {
220 child->Mother = character;
221 }
222 if (!character->IsParentOf(child_ident)) { //check whether the character has already been set as a parent of the child
223 character->Children.push_back(child);
224 }
225 // see if the character's other children aren't already included in the child's siblings, and if they aren't, add them (and add the character to the siblings' sibling list too)
226 for (size_t i = 0; i < character->Children.size(); ++i) {
227 if (character->Children[i] != child) {
228 if (!child->IsSiblingOf(character->Children[i]->Ident)) {
229 child->Siblings.push_back(character->Children[i]);
230 }
231 if (!character->Children[i]->IsSiblingOf(child_ident)) {
232 character->Children[i]->Siblings.push_back(child);
233 }
234 }
235 }
236 } else {
237 LuaError(l, "Character \"%s\" doesn't exist." _C_ child_ident.c_str());
238 }
239 }
240 } else if (!strcmp(value, "Gender")) {
241 character->Gender = GetGenderIdByName(LuaToString(l, -1));
242 } else if (!strcmp(value, "Icon")) {
243 character->Icon.Name = LuaToString(l, -1);
244 character->Icon.Icon = nullptr;
245 character->Icon.Load();
246 character->Icon.Icon->Load();
247 } else if (!strcmp(value, "HeroicIcon")) {
248 character->HeroicIcon.Name = LuaToString(l, -1);
249 character->HeroicIcon.Icon = nullptr;
250 character->HeroicIcon.Load();
251 character->HeroicIcon.Icon->Load();
252 } else if (!strcmp(value, "Level")) {
253 character->Level = LuaToNumber(l, -1);
254 } else if (!strcmp(value, "ExperiencePercent")) {
255 character->ExperiencePercent = LuaToNumber(l, -1);
256 } else if (!strcmp(value, "Deity")) {
257 CDeity *deity = CDeity::GetDeity(LuaToString(l, -1));
258 if (deity) {
259 character->Deity = deity;
260 if (character->Icon.Name.empty() && !deity->Icon.Name.empty()) {
261 character->Icon.Name = deity->Icon.Name;
262 character->Icon.Icon = nullptr;
263 character->Icon.Load();
264 }
265 }
266 } else if (!strcmp(value, "Conditions")) {
267 character->Conditions = new LuaCallback(l, -1);
268 } else if (!strcmp(value, "Abilities")) {
269 character->Abilities.clear();
270 const int args = lua_rawlen(l, -1);
271 for (int j = 0; j < args; ++j) {
272 std::string ability_ident = LuaToString(l, -1, j + 1);
273 int ability_id = UpgradeIdByIdent(ability_ident);
274 if (ability_id != -1) {
275 character->Abilities.push_back(AllUpgrades[ability_id]);
276 } else {
277 fprintf(stderr, "Ability \"%s\" doesn't exist.", ability_ident.c_str());
278 }
279 }
280 } else if (!strcmp(value, "Deities")) {
281 character->Deities.clear();
282 const int args = lua_rawlen(l, -1);
283 for (int j = 0; j < args; ++j) {
284 std::string deity_ident = LuaToString(l, -1, j + 1);
285 CDeity *deity = CDeity::GetDeity(deity_ident);
286 if (deity) {
287 character->Deities.push_back(deity);
288 }
289 }
290 } else if (!strcmp(value, "ReadWorks")) {
291 character->ReadWorks.clear();
292 const int args = lua_rawlen(l, -1);
293 for (int j = 0; j < args; ++j) {
294 std::string work_ident = LuaToString(l, -1, j + 1);
295 int work_id = UpgradeIdByIdent(work_ident);
296 if (work_id != -1) {
297 character->ReadWorks.push_back(AllUpgrades[work_id]);
298 } else {
299 fprintf(stderr, "Work \"%s\" doesn't exist.", work_ident.c_str());
300 }
301 }
302 } else if (!strcmp(value, "AuthoredWorks")) {
303 character->AuthoredWorks.clear();
304 const int args = lua_rawlen(l, -1);
305 for (int j = 0; j < args; ++j) {
306 std::string work_ident = LuaToString(l, -1, j + 1);
307 int work_id = UpgradeIdByIdent(work_ident);
308 if (work_id != -1) {
309 character->AuthoredWorks.push_back(AllUpgrades[work_id]);
310 AllUpgrades[work_id]->Author = character;
311 } else {
312 fprintf(stderr, "Work \"%s\" doesn't exist.", work_ident.c_str());
313 }
314 }
315 } else if (!strcmp(value, "LiteraryAppearances")) {
316 character->LiteraryAppearances.clear();
317 const int args = lua_rawlen(l, -1);
318 for (int j = 0; j < args; ++j) {
319 std::string work_ident = LuaToString(l, -1, j + 1);
320 int work_id = UpgradeIdByIdent(work_ident);
321 if (work_id != -1) {
322 character->LiteraryAppearances.push_back(AllUpgrades[work_id]);
323 AllUpgrades[work_id]->Characters.push_back(character);
324 } else {
325 fprintf(stderr, "Work \"%s\" doesn't exist.", work_ident.c_str());
326 }
327 }
328 } else if (!strcmp(value, "ConsumedElixirs")) {
329 character->ConsumedElixirs.clear();
330 const int args = lua_rawlen(l, -1);
331 for (int j = 0; j < args; ++j) {
332 std::string elixir_ident = LuaToString(l, -1, j + 1);
333 int elixir_id = UpgradeIdByIdent(elixir_ident);
334 if (elixir_id != -1) {
335 character->ConsumedElixirs.push_back(AllUpgrades[elixir_id]);
336 } else {
337 fprintf(stderr, "Elixir \"%s\" doesn't exist.", elixir_ident.c_str());
338 }
339 }
340 } else if (!strcmp(value, "Items")) {
341 character->Items.clear();
342 const int args = lua_rawlen(l, -1);
343 for (int j = 0; j < args; ++j) {
344 lua_rawgeti(l, -1, j + 1);
345 CPersistentItem *item = new CPersistentItem;
346 item->Owner = character;
347 character->Items.push_back(item);
348 if (!lua_istable(l, -1)) {
349 LuaError(l, "incorrect argument (expected table for items)");
350 }
351 const int subargs = lua_rawlen(l, -1);
352 for (int k = 0; k < subargs; ++k) {
353 value = LuaToString(l, -1, k + 1);
354 ++k;
355 if (!strcmp(value, "type")) {
356 std::string item_ident = LuaToString(l, -1, k + 1);
357 int item_type_id = UnitTypeIdByIdent(item_ident);
358 if (item_type_id != -1) {
359 item->Type = const_cast<CUnitType *>(&(*UnitTypes[item_type_id]));
360 } else {
361 fprintf(stderr, "Item type \"%s\" doesn't exist.\n", item_ident.c_str());
362 character->Items.erase(std::remove(character->Items.begin(), character->Items.end(), item), character->Items.end());
363 delete item;
364 break;
365 }
366 } else if (!strcmp(value, "prefix")) {
367 std::string upgrade_ident = LuaToString(l, -1, k + 1);
368 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
369 if (upgrade_id != -1) {
370 item->Prefix = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
371 } else {
372 fprintf(stderr, "Item prefix \"%s\" doesn't exist.", upgrade_ident.c_str());
373 }
374 } else if (!strcmp(value, "suffix")) {
375 std::string upgrade_ident = LuaToString(l, -1, k + 1);
376 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
377 if (upgrade_id != -1) {
378 item->Suffix = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
379 } else {
380 fprintf(stderr, "Item suffix \"%s\" doesn't exist.", upgrade_ident.c_str());
381 }
382 } else if (!strcmp(value, "spell")) {
383 std::string spell_ident = LuaToString(l, -1, k + 1);
384 CSpell *spell = CSpell::GetSpell(spell_ident);
385 if (spell != nullptr) {
386 item->Spell = const_cast<CSpell *>(&(*spell));
387 } else {
388 fprintf(stderr, "Spell \"%s\" doesn't exist.", spell_ident.c_str());
389 }
390 } else if (!strcmp(value, "work")) {
391 std::string upgrade_ident = LuaToString(l, -1, k + 1);
392 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
393 if (upgrade_id != -1) {
394 item->Work = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
395 } else {
396 fprintf(stderr, "Literary work \"%s\" doesn't exist.", upgrade_ident.c_str());
397 }
398 } else if (!strcmp(value, "elixir")) {
399 std::string upgrade_ident = LuaToString(l, -1, k + 1);
400 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
401 if (upgrade_id != -1) {
402 item->Elixir = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
403 } else {
404 fprintf(stderr, "Elixir \"%s\" doesn't exist.", upgrade_ident.c_str());
405 }
406 } else if (!strcmp(value, "name")) {
407 item->Name = LuaToString(l, -1, k + 1);
408 } else if (!strcmp(value, "unique")) {
409 std::string unique_ident = LuaToString(l, -1, k + 1);
410 CUniqueItem *unique_item = GetUniqueItem(unique_ident);
411 item->Unique = unique_item;
412 if (unique_item != nullptr) {
413 item->Name = unique_item->Name;
414 if (unique_item->Type != nullptr) {
415 item->Type = unique_item->Type;
416 } else {
417 fprintf(stderr, "Unique item \"%s\" has no type.\n", unique_item->Ident.c_str());
418 }
419 item->Prefix = unique_item->Prefix;
420 item->Suffix = unique_item->Suffix;
421 item->Spell = unique_item->Spell;
422 item->Work = unique_item->Work;
423 item->Elixir = unique_item->Elixir;
424 } else {
425 fprintf(stderr, "Unique item \"%s\" doesn't exist.\n", unique_ident.c_str());
426 }
427 } else if (!strcmp(value, "bound")) {
428 item->Bound = LuaToBoolean(l, -1, k + 1);
429 } else if (!strcmp(value, "identified")) {
430 item->Identified = LuaToBoolean(l, -1, k + 1);
431 } else if (!strcmp(value, "equipped")) {
432 bool is_equipped = LuaToBoolean(l, -1, k + 1);
433 if (is_equipped && GetItemClassSlot(item->Type->ItemClass) != -1) {
434 character->EquippedItems[GetItemClassSlot(item->Type->ItemClass)].push_back(item);
435 }
436 } else {
437 printf("\n%s\n", character->Ident.c_str());
438 LuaError(l, "Unsupported tag: %s" _C_ value);
439 }
440 }
441 lua_pop(l, 1);
442 }
443 } else if (!strcmp(value, "ForbiddenUpgrades")) {
444 character->ForbiddenUpgrades.clear();
445 const int args = lua_rawlen(l, -1);
446 for (int j = 0; j < args; ++j) {
447 std::string unit_type_ident = LuaToString(l, -1, j + 1);
448 int unit_type_id = UnitTypeIdByIdent(unit_type_ident);
449 if (unit_type_id != -1) {
450 character->ForbiddenUpgrades.push_back(UnitTypes[unit_type_id]);
451 } else {
452 LuaError(l, "Unit type \"%s\" doesn't exist." _C_ unit_type_ident.c_str());
453 }
454 }
455 } else if (!strcmp(value, "HistoricalFactions")) {
456 if (!lua_istable(l, -1)) {
457 LuaError(l, "incorrect argument");
458 }
459 const int subargs = lua_rawlen(l, -1);
460 for (int j = 0; j < subargs; ++j) {
461 CDate date;
462 lua_rawgeti(l, -1, j + 1);
463 CclGetDate(l, &date);
464 lua_pop(l, 1);
465 ++j;
466
467 std::string historical_faction_name = LuaToString(l, -1, j + 1);
468 CFaction *historical_faction = PlayerRaces.GetFaction(historical_faction_name);
469 if (!historical_faction) {
470 LuaError(l, "Faction \"%s\" doesn't exist." _C_ historical_faction_name.c_str());
471 }
472
473 character->HistoricalFactions.push_back(std::pair<CDate, CFaction *>(date, historical_faction));
474 }
475 } else if (!strcmp(value, "HistoricalLocations")) {
476 if (!lua_istable(l, -1)) {
477 LuaError(l, "incorrect argument");
478 }
479 const int subargs = lua_rawlen(l, -1);
480 for (int j = 0; j < subargs; ++j) {
481 CHistoricalLocation *historical_location = new CHistoricalLocation;
482 lua_rawgeti(l, -1, j + 1);
483 CclGetDate(l, &historical_location->Date);
484 lua_pop(l, 1);
485 ++j;
486
487 historical_location->MapTemplate = CMapTemplate::GetMapTemplate(LuaToString(l, -1, j + 1));
488 ++j;
489
490 lua_rawgeti(l, -1, j + 1);
491 if (lua_istable(l, -1)) { //coordinates
492 CclGetPos(l, &historical_location->Position.x, &historical_location->Position.y);
493 } else { //site ident
494 std::string site_ident = LuaToString(l, -1);
495 historical_location->Site = CSite::GetSite(site_ident);
496 if (!historical_location->Site) {
497 LuaError(l, "Site \"%s\" doesn't exist.\n" _C_ site_ident.c_str());
498 }
499 historical_location->MapTemplate = historical_location->Site->MapTemplate;
500 historical_location->Position = historical_location->Site->Position;
501 }
502 lua_pop(l, 1);
503
504 character->HistoricalLocations.push_back(historical_location);
505 }
506 } else if (!strcmp(value, "HistoricalTitles")) {
507 if (!lua_istable(l, -1)) {
508 LuaError(l, "incorrect argument");
509 }
510 const int subargs = lua_rawlen(l, -1);
511 for (int j = 0; j < subargs; ++j) {
512 int title = GetCharacterTitleIdByName(LuaToString(l, -1, j + 1));
513 if (title == -1) {
514 LuaError(l, "Character title doesn't exist.");
515 }
516 ++j;
517 CDate start_date;
518 lua_rawgeti(l, -1, j + 1);
519 CclGetDate(l, &start_date);
520 lua_pop(l, 1);
521 ++j;
522 CDate end_date;
523 lua_rawgeti(l, -1, j + 1);
524 CclGetDate(l, &end_date);
525 lua_pop(l, 1);
526 ++j;
527
528 std::string title_faction_name = LuaToString(l, -1, j + 1);
529 CFaction *title_faction = PlayerRaces.GetFaction(title_faction_name);
530 if (!title_faction) {
531 LuaError(l, "Faction \"%s\" doesn't exist." _C_ title_faction_name.c_str());
532 }
533 if (start_date.Year != 0 && end_date.Year != 0 && IsMinisterialTitle(title)) { // don't put in the faction's historical data if a blank year was given
534 title_faction->HistoricalMinisters[std::tuple<CDate, CDate, int>(start_date, end_date, title)] = character;
535 }
536 character->HistoricalTitles.push_back(std::tuple<CDate, CDate, CFaction *, int>(start_date, end_date, title_faction, title));
537 }
538 } else {
539 LuaError(l, "Unsupported tag: %s" _C_ value);
540 }
541 }
542
543 if (!redefinition) {
544 if (character->Type->BoolFlag[FAUNA_INDEX].value) {
545 character->Type->PersonalNames[character->Gender].push_back(character->Name);
546 for (size_t i = 0; i < alternate_names.size(); ++i) {
547 character->Type->PersonalNames[character->Gender].push_back(alternate_names[i]);
548 }
549 } else if (character->Civilization) {
550 character->Civilization->PersonalNames[character->Gender].push_back(character->Name);
551 for (size_t i = 0; i < alternate_names.size(); ++i) {
552 character->Civilization->PersonalNames[character->Gender].push_back(alternate_names[i]);
553 }
554 }
555 }
556
557 if (character->Trait == nullptr) { //if no trait was set, have the character be the same trait as the unit type (if the unit type has a single one predefined)
558 if (character->Type != nullptr && character->Type->Traits.size() == 1) {
559 character->Trait = character->Type->Traits[0];
560 }
561 }
562
563 if (character->Gender == NoGender) { //if no gender was set, have the character be the same gender as the unit type (if the unit type has it predefined)
564 if (character->Type != nullptr && character->Type->DefaultStat.Variables[GENDER_INDEX].Value != 0) {
565 character->Gender = character->Type->DefaultStat.Variables[GENDER_INDEX].Value;
566 }
567 }
568
569 //check if the abilities are correct for this character's unit type
570 if (character->Type != nullptr && character->Abilities.size() > 0 && ((int) AiHelpers.LearnableAbilities.size()) > character->Type->Slot) {
571 int ability_count = (int) character->Abilities.size();
572 for (int i = (ability_count - 1); i >= 0; --i) {
573 if (std::find(AiHelpers.LearnableAbilities[character->Type->Slot].begin(), AiHelpers.LearnableAbilities[character->Type->Slot].end(), character->Abilities[i]) == AiHelpers.LearnableAbilities[character->Type->Slot].end()) {
574 character->Abilities.erase(std::remove(character->Abilities.begin(), character->Abilities.end(), character->Abilities[i]), character->Abilities.end());
575 }
576 }
577 }
578
579 character->GenerateMissingDates();
580 character->UpdateAttributes();
581
582 character->Initialized = true;
583
584 return 0;
585 }
586
587 /**
588 ** Define a custom hero.
589 **
590 ** @param l Lua state.
591 */
CclDefineCustomHero(lua_State * l)592 static int CclDefineCustomHero(lua_State *l)
593 {
594 LuaCheckArgs(l, 2);
595 if (!lua_istable(l, 2)) {
596 LuaError(l, "incorrect argument (expected table)");
597 }
598
599 std::string hero_ident = LuaToString(l, 1);
600 CCharacter *hero = GetCustomHero(hero_ident);
601 if (!hero) {
602 hero = new CCharacter;
603 hero->Ident = hero_ident;
604 CustomHeroes[hero_ident] = hero;
605 } else {
606 fprintf(stderr, "Custom hero \"%s\" is being redefined.\n", hero_ident.c_str());
607 }
608 hero->Custom = true;
609
610 // Parse the list:
611 for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
612 const char *value = LuaToString(l, -2);
613
614 if (!strcmp(value, "Name")) {
615 hero->Name = LuaToString(l, -1);
616 } else if (!strcmp(value, "ExtraName")) {
617 hero->ExtraName = LuaToString(l, -1);
618 } else if (!strcmp(value, "FamilyName")) {
619 hero->FamilyName = LuaToString(l, -1);
620 } else if (!strcmp(value, "Dynasty")) { // for backwards compatibility
621 hero->FamilyName = LuaToString(l, -1);
622 } else if (!strcmp(value, "Description")) {
623 hero->Description = LuaToString(l, -1);
624 } else if (!strcmp(value, "Variation")) { //to keep backwards compatibility
625 hero->HairVariation = LuaToString(l, -1);
626 } else if (!strcmp(value, "HairVariation")) {
627 hero->HairVariation = LuaToString(l, -1);
628 } else if (!strcmp(value, "Type")) {
629 std::string unit_type_ident = LuaToString(l, -1);
630 int unit_type_id = UnitTypeIdByIdent(unit_type_ident);
631 if (unit_type_id != -1) {
632 hero->Type = const_cast<CUnitType *>(&(*UnitTypes[unit_type_id]));
633 if (hero->Level < hero->Type->DefaultStat.Variables[LEVEL_INDEX].Value) {
634 hero->Level = hero->Type->DefaultStat.Variables[LEVEL_INDEX].Value;
635 }
636 } else {
637 LuaError(l, "Unit type \"%s\" doesn't exist." _C_ unit_type_ident.c_str());
638 }
639 } else if (!strcmp(value, "Trait")) {
640 std::string trait_ident = LuaToString(l, -1);
641 int upgrade_id = UpgradeIdByIdent(trait_ident);
642 if (upgrade_id != -1) {
643 hero->Trait = AllUpgrades[upgrade_id];
644 } else {
645 LuaError(l, "Trait upgrade \"%s\" doesn't exist." _C_ trait_ident.c_str());
646 }
647 } else if (!strcmp(value, "Civilization")) {
648 hero->Civilization = CCivilization::GetCivilization(LuaToString(l, -1));
649 } else if (!strcmp(value, "Gender")) {
650 hero->Gender = GetGenderIdByName(LuaToString(l, -1));
651 } else if (!strcmp(value, "Level")) {
652 hero->Level = LuaToNumber(l, -1);
653 } else if (!strcmp(value, "ExperiencePercent")) {
654 hero->ExperiencePercent = LuaToNumber(l, -1);
655 } else if (!strcmp(value, "Abilities")) {
656 hero->Abilities.clear();
657 const int args = lua_rawlen(l, -1);
658 for (int j = 0; j < args; ++j) {
659 std::string ability_ident = LuaToString(l, -1, j + 1);
660 int ability_id = UpgradeIdByIdent(ability_ident);
661 if (ability_id != -1) {
662 hero->Abilities.push_back(AllUpgrades[ability_id]);
663 } else {
664 fprintf(stderr, "Ability \"%s\" doesn't exist.", ability_ident.c_str());
665 }
666 }
667 } else if (!strcmp(value, "Deities")) {
668 hero->Deities.clear();
669 const int args = lua_rawlen(l, -1);
670 for (int j = 0; j < args; ++j) {
671 std::string deity_ident = LuaToString(l, -1, j + 1);
672 CDeity *deity = CDeity::GetDeity(deity_ident);
673 if (deity) {
674 hero->Deities.push_back(deity);
675 }
676 }
677 } else if (!strcmp(value, "ReadWorks")) {
678 hero->ReadWorks.clear();
679 const int args = lua_rawlen(l, -1);
680 for (int j = 0; j < args; ++j) {
681 std::string work_ident = LuaToString(l, -1, j + 1);
682 int work_id = UpgradeIdByIdent(work_ident);
683 if (work_id != -1) {
684 hero->ReadWorks.push_back(AllUpgrades[work_id]);
685 } else {
686 fprintf(stderr, "Work \"%s\" doesn't exist.", work_ident.c_str());
687 }
688 }
689 } else if (!strcmp(value, "ConsumedElixirs")) {
690 hero->ConsumedElixirs.clear();
691 const int args = lua_rawlen(l, -1);
692 for (int j = 0; j < args; ++j) {
693 std::string elixir_ident = LuaToString(l, -1, j + 1);
694 int elixir_id = UpgradeIdByIdent(elixir_ident);
695 if (elixir_id != -1) {
696 hero->ConsumedElixirs.push_back(AllUpgrades[elixir_id]);
697 } else {
698 fprintf(stderr, "Elixir \"%s\" doesn't exist.", elixir_ident.c_str());
699 }
700 }
701 } else if (!strcmp(value, "Items")) {
702 const int args = lua_rawlen(l, -1);
703 for (int j = 0; j < args; ++j) {
704 lua_rawgeti(l, -1, j + 1);
705 CPersistentItem *item = new CPersistentItem;
706 item->Owner = hero;
707 hero->Items.push_back(item);
708 if (!lua_istable(l, -1)) {
709 LuaError(l, "incorrect argument (expected table for items)");
710 }
711 const int subargs = lua_rawlen(l, -1);
712 for (int k = 0; k < subargs; ++k) {
713 value = LuaToString(l, -1, k + 1);
714 ++k;
715 if (!strcmp(value, "type")) {
716 std::string item_ident = LuaToString(l, -1, k + 1);
717 int item_type_id = UnitTypeIdByIdent(item_ident);
718 if (item_type_id != -1) {
719 item->Type = const_cast<CUnitType *>(&(*UnitTypes[item_type_id]));
720 } else {
721 fprintf(stderr, "Item type \"%s\" doesn't exist.\n", item_ident.c_str());
722 hero->Items.erase(std::remove(hero->Items.begin(), hero->Items.end(), item), hero->Items.end());
723 delete item;
724 break;
725 }
726 } else if (!strcmp(value, "prefix")) {
727 std::string upgrade_ident = LuaToString(l, -1, k + 1);
728 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
729 if (upgrade_id != -1) {
730 item->Prefix = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
731 } else {
732 fprintf(stderr, "Item prefix \"%s\" doesn't exist.", upgrade_ident.c_str());
733 }
734 } else if (!strcmp(value, "suffix")) {
735 std::string upgrade_ident = LuaToString(l, -1, k + 1);
736 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
737 if (upgrade_id != -1) {
738 item->Suffix = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
739 } else {
740 fprintf(stderr, "Item suffix \"%s\" doesn't exist.", upgrade_ident.c_str());
741 }
742 } else if (!strcmp(value, "spell")) {
743 std::string spell_ident = LuaToString(l, -1, k + 1);
744 CSpell *spell = CSpell::GetSpell(spell_ident);
745 if (spell != nullptr) {
746 item->Spell = const_cast<CSpell *>(&(*spell));
747 } else {
748 fprintf(stderr, "Spell \"%s\" doesn't exist.", spell_ident.c_str());
749 }
750 } else if (!strcmp(value, "work")) {
751 std::string upgrade_ident = LuaToString(l, -1, k + 1);
752 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
753 if (upgrade_id != -1) {
754 item->Work = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
755 } else {
756 fprintf(stderr, "Literary work \"%s\" doesn't exist.", upgrade_ident.c_str());
757 }
758 } else if (!strcmp(value, "elixir")) {
759 std::string upgrade_ident = LuaToString(l, -1, k + 1);
760 int upgrade_id = UpgradeIdByIdent(upgrade_ident);
761 if (upgrade_id != -1) {
762 item->Elixir = const_cast<CUpgrade *>(&(*AllUpgrades[upgrade_id]));
763 } else {
764 fprintf(stderr, "Elixir \"%s\" doesn't exist.", upgrade_ident.c_str());
765 }
766 } else if (!strcmp(value, "name")) {
767 item->Name = LuaToString(l, -1, k + 1);
768 } else if (!strcmp(value, "unique")) {
769 std::string unique_ident = LuaToString(l, -1, k + 1);
770 CUniqueItem *unique_item = GetUniqueItem(unique_ident);
771 item->Unique = unique_item;
772 if (unique_item != nullptr) {
773 item->Name = unique_item->Name;
774 if (unique_item->Type != nullptr) {
775 item->Type = unique_item->Type;
776 } else {
777 fprintf(stderr, "Unique item \"%s\" has no type.\n", item->Name.c_str());
778 }
779 item->Prefix = unique_item->Prefix;
780 item->Suffix = unique_item->Suffix;
781 item->Spell = unique_item->Spell;
782 item->Work = unique_item->Work;
783 item->Elixir = unique_item->Elixir;
784 } else {
785 fprintf(stderr, "Unique item \"%s\" doesn't exist.\n", unique_ident.c_str());
786 }
787 } else if (!strcmp(value, "bound")) {
788 item->Bound = LuaToBoolean(l, -1, k + 1);
789 } else if (!strcmp(value, "identified")) {
790 item->Identified = LuaToBoolean(l, -1, k + 1);
791 } else if (!strcmp(value, "equipped")) {
792 bool is_equipped = LuaToBoolean(l, -1, k + 1);
793 if (is_equipped && GetItemClassSlot(item->Type->ItemClass) != -1) {
794 hero->EquippedItems[GetItemClassSlot(item->Type->ItemClass)].push_back(item);
795 }
796 } else {
797 printf("\n%s\n", hero->Ident.c_str());
798 LuaError(l, "Unsupported tag: %s" _C_ value);
799 }
800 }
801 lua_pop(l, 1);
802 }
803 } else if (!strcmp(value, "QuestsInProgress")) {
804 hero->QuestsInProgress.clear();
805 const int args = lua_rawlen(l, -1);
806 for (int j = 0; j < args; ++j) {
807 std::string quest_name = LuaToString(l, -1, j + 1);
808 if (GetQuest(quest_name) != nullptr) {
809 hero->QuestsInProgress.push_back(GetQuest(quest_name));
810 } else {
811 LuaError(l, "Quest \"%s\" doesn't exist." _C_ quest_name.c_str());
812 }
813 }
814 } else if (!strcmp(value, "QuestsCompleted")) {
815 hero->QuestsCompleted.clear();
816 const int args = lua_rawlen(l, -1);
817 for (int j = 0; j < args; ++j) {
818 std::string quest_name = LuaToString(l, -1, j + 1);
819 if (GetQuest(quest_name) != nullptr) {
820 hero->QuestsCompleted.push_back(GetQuest(quest_name));
821 } else {
822 LuaError(l, "Quest \"%s\" doesn't exist." _C_ quest_name.c_str());
823 }
824 }
825 } else if (!strcmp(value, "ForbiddenUpgrades")) {
826 hero->ForbiddenUpgrades.clear();
827 const int args = lua_rawlen(l, -1);
828 for (int j = 0; j < args; ++j) {
829 std::string unit_type_ident = LuaToString(l, -1, j + 1);
830 int unit_type_id = UnitTypeIdByIdent(unit_type_ident);
831 if (unit_type_id != -1) {
832 hero->ForbiddenUpgrades.push_back(UnitTypes[unit_type_id]);
833 } else {
834 LuaError(l, "Unit type \"%s\" doesn't exist." _C_ unit_type_ident.c_str());
835 }
836 }
837 } else if (!strcmp(value, "Icon")) {
838 hero->Icon.Name = LuaToString(l, -1);
839 hero->Icon.Icon = nullptr;
840 hero->Icon.Load();
841 hero->Icon.Icon->Load();
842 } else if (!strcmp(value, "HeroicIcon")) {
843 hero->HeroicIcon.Name = LuaToString(l, -1);
844 hero->HeroicIcon.Icon = nullptr;
845 hero->HeroicIcon.Load();
846 hero->HeroicIcon.Icon->Load();
847 } else {
848 LuaError(l, "Unsupported tag: %s" _C_ value);
849 }
850 }
851
852 if (hero->Gender == NoGender) { //if no gender was set, have the hero be the same gender as the unit type (if the unit type has it predefined)
853 if (hero->Type != nullptr && hero->Type->DefaultStat.Variables[GENDER_INDEX].Value != 0) {
854 hero->Gender = hero->Type->DefaultStat.Variables[GENDER_INDEX].Value;
855 }
856 }
857
858 //check if the abilities are correct for this hero's unit type
859 if (hero->Abilities.size() > 0 && ((int) AiHelpers.LearnableAbilities.size()) > hero->Type->Slot) {
860 int ability_count = (int) hero->Abilities.size();
861 for (int i = (ability_count - 1); i >= 0; --i) {
862 if (std::find(AiHelpers.LearnableAbilities[hero->Type->Slot].begin(), AiHelpers.LearnableAbilities[hero->Type->Slot].end(), hero->Abilities[i]) == AiHelpers.LearnableAbilities[hero->Type->Slot].end()) {
863 hero->Abilities.erase(std::remove(hero->Abilities.begin(), hero->Abilities.end(), hero->Abilities[i]), hero->Abilities.end());
864 }
865 }
866 }
867
868 return 0;
869 }
870
871 /**
872 ** Get character data.
873 **
874 ** @param l Lua state.
875 */
CclGetCharacterData(lua_State * l)876 static int CclGetCharacterData(lua_State *l)
877 {
878 if (lua_gettop(l) < 2) {
879 LuaError(l, "incorrect argument");
880 }
881 std::string character_name = LuaToString(l, 1);
882 CCharacter *character = CCharacter::GetCharacter(character_name);
883 if (!character) {
884 LuaError(l, "Character \"%s\" doesn't exist." _C_ character_name.c_str());
885 }
886 const char *data = LuaToString(l, 2);
887
888 if (!strcmp(data, "Name")) {
889 lua_pushstring(l, character->Name.c_str());
890 return 1;
891 } else if (!strcmp(data, "FamilyName")) {
892 lua_pushstring(l, character->FamilyName.c_str());
893 return 1;
894 } else if (!strcmp(data, "FullName")) {
895 lua_pushstring(l, character->GetFullName().c_str());
896 return 1;
897 } else if (!strcmp(data, "Description")) {
898 lua_pushstring(l, character->Description.c_str());
899 return 1;
900 } else if (!strcmp(data, "Background")) {
901 lua_pushstring(l, character->Background.c_str());
902 return 1;
903 } else if (!strcmp(data, "Quote")) {
904 lua_pushstring(l, character->Quote.c_str());
905 return 1;
906 } else if (!strcmp(data, "Civilization")) {
907 if (character->Civilization) {
908 lua_pushstring(l, PlayerRaces.Name[character->Civilization->ID].c_str());
909 } else {
910 lua_pushstring(l, "");
911 }
912 return 1;
913 } else if (!strcmp(data, "Faction")) {
914 if (character->Faction != nullptr) {
915 lua_pushstring(l, character->Faction->Ident.c_str());
916 } else {
917 lua_pushstring(l, "");
918 }
919 return 1;
920 } else if (!strcmp(data, "BirthDate")) {
921 if (character->BirthDate.Year != 0) {
922 lua_pushstring(l, character->BirthDate.ToDisplayString(character->GetCalendar()).c_str());
923 } else {
924 lua_pushstring(l, "");
925 }
926 return 1;
927 } else if (!strcmp(data, "BirthYear")) {
928 lua_pushnumber(l, character->BirthDate.Year);
929 return 1;
930 } else if (!strcmp(data, "StartDate")) {
931 if (character->StartDate.Year != 0) {
932 lua_pushstring(l, character->StartDate.ToDisplayString(character->GetCalendar()).c_str());
933 } else {
934 lua_pushstring(l, "");
935 }
936 return 1;
937 } else if (!strcmp(data, "StartYear")) {
938 lua_pushnumber(l, character->StartDate.Year);
939 return 1;
940 } else if (!strcmp(data, "DeathDate")) {
941 if (character->DeathDate.Year != 0) {
942 lua_pushstring(l, character->DeathDate.ToDisplayString(character->GetCalendar()).c_str());
943 } else {
944 lua_pushstring(l, "");
945 }
946 return 1;
947 } else if (!strcmp(data, "DeathYear")) {
948 lua_pushnumber(l, character->DeathDate.Year);
949 return 1;
950 } else if (!strcmp(data, "ViolentDeath")) {
951 lua_pushboolean(l, character->ViolentDeath);
952 return 1;
953 } else if (!strcmp(data, "Gender")) {
954 lua_pushstring(l, GetGenderNameById(character->Gender).c_str());
955 return 1;
956 } else if (!strcmp(data, "Level")) {
957 lua_pushnumber(l, character->Level);
958 return 1;
959 } else if (!strcmp(data, "Type")) {
960 if (character->Type != nullptr) {
961 lua_pushstring(l, character->Type->Ident.c_str());
962 } else {
963 lua_pushstring(l, "");
964 }
965 return 1;
966 } else if (!strcmp(data, "Trait")) {
967 if (character->Trait != nullptr) {
968 lua_pushstring(l, character->Trait->Ident.c_str());
969 } else {
970 lua_pushstring(l, "");
971 }
972 return 1;
973 } else if (!strcmp(data, "Deity")) {
974 if (character->Deity != nullptr) {
975 lua_pushstring(l, character->Deity->Ident.c_str());
976 } else {
977 lua_pushstring(l, "");
978 }
979 return 1;
980 } else if (!strcmp(data, "Deities")) {
981 lua_createtable(l, character->Deities.size(), 0);
982 for (size_t i = 1; i <= character->Deities.size(); ++i)
983 {
984 lua_pushstring(l, character->Deities[i-1]->Ident.c_str());
985 lua_rawseti(l, -2, i);
986 }
987 return 1;
988 } else if (!strcmp(data, "Father")) {
989 if (character->Father != nullptr) {
990 lua_pushstring(l, character->Father->Ident.c_str());
991 } else {
992 lua_pushstring(l, "");
993 }
994 return 1;
995 } else if (!strcmp(data, "Mother")) {
996 if (character->Mother != nullptr) {
997 lua_pushstring(l, character->Mother->Ident.c_str());
998 } else {
999 lua_pushstring(l, "");
1000 }
1001 return 1;
1002 } else if (!strcmp(data, "Children")) {
1003 lua_createtable(l, character->Children.size(), 0);
1004 for (size_t i = 1; i <= character->Children.size(); ++i)
1005 {
1006 lua_pushstring(l, character->Children[i-1]->Ident.c_str());
1007 lua_rawseti(l, -2, i);
1008 }
1009 return 1;
1010 } else if (!strcmp(data, "Siblings")) {
1011 lua_createtable(l, character->Siblings.size(), 0);
1012 for (size_t i = 1; i <= character->Siblings.size(); ++i)
1013 {
1014 lua_pushstring(l, character->Siblings[i-1]->Ident.c_str());
1015 lua_rawseti(l, -2, i);
1016 }
1017 return 1;
1018 } else if (!strcmp(data, "Icon")) {
1019 lua_pushstring(l, character->GetIcon().Name.c_str());
1020 return 1;
1021 } else if (!strcmp(data, "BaseIcon")) {
1022 lua_pushstring(l, character->Icon.Name.c_str());
1023 return 1;
1024 } else if (!strcmp(data, "HairVariation")) {
1025 lua_pushstring(l, character->HairVariation.c_str());
1026 return 1;
1027 } else if (!strcmp(data, "IsUsable")) {
1028 lua_pushboolean(l, character->IsUsable());
1029 return 1;
1030 } else if (!strcmp(data, "Abilities")) {
1031 lua_createtable(l, character->Abilities.size(), 0);
1032 for (size_t i = 1; i <= character->Abilities.size(); ++i)
1033 {
1034 lua_pushstring(l, character->Abilities[i-1]->Ident.c_str());
1035 lua_rawseti(l, -2, i);
1036 }
1037 return 1;
1038 } else {
1039 LuaError(l, "Invalid field: %s" _C_ data);
1040 }
1041
1042 return 0;
1043 }
1044
1045 /**
1046 ** Get custom hero data.
1047 **
1048 ** @param l Lua state.
1049 */
CclGetCustomHeroData(lua_State * l)1050 static int CclGetCustomHeroData(lua_State *l)
1051 {
1052 if (lua_gettop(l) < 2) {
1053 LuaError(l, "incorrect argument");
1054 }
1055 std::string character_name = LuaToString(l, 1);
1056 CCharacter *character = GetCustomHero(character_name);
1057 if (!character) {
1058 LuaError(l, "Custom hero \"%s\" doesn't exist." _C_ character_name.c_str());
1059 }
1060 const char *data = LuaToString(l, 2);
1061
1062 if (!strcmp(data, "Name")) {
1063 lua_pushstring(l, character->Name.c_str());
1064 return 1;
1065 } else if (!strcmp(data, "FamilyName")) {
1066 lua_pushstring(l, character->FamilyName.c_str());
1067 return 1;
1068 } else if (!strcmp(data, "FullName")) {
1069 lua_pushstring(l, character->GetFullName().c_str());
1070 return 1;
1071 } else if (!strcmp(data, "Civilization")) {
1072 if (character->Civilization) {
1073 lua_pushstring(l, PlayerRaces.Name[character->Civilization->ID].c_str());
1074 } else {
1075 lua_pushstring(l, "");
1076 }
1077 return 1;
1078 } else if (!strcmp(data, "Gender")) {
1079 lua_pushstring(l, GetGenderNameById(character->Gender).c_str());
1080 return 1;
1081 } else if (!strcmp(data, "Level")) {
1082 lua_pushnumber(l, character->Level);
1083 return 1;
1084 } else if (!strcmp(data, "Type")) {
1085 if (character->Type != nullptr) {
1086 lua_pushstring(l, character->Type->Ident.c_str());
1087 } else {
1088 lua_pushstring(l, "");
1089 }
1090 return 1;
1091 } else if (!strcmp(data, "Trait")) {
1092 if (character->Trait != nullptr) {
1093 lua_pushstring(l, character->Trait->Ident.c_str());
1094 } else {
1095 lua_pushstring(l, "");
1096 }
1097 return 1;
1098 } else if (!strcmp(data, "Icon")) {
1099 lua_pushstring(l, character->GetIcon().Name.c_str());
1100 return 1;
1101 } else {
1102 LuaError(l, "Invalid field: %s" _C_ data);
1103 }
1104
1105 return 0;
1106 }
1107
CclGetCharacters(lua_State * l)1108 static int CclGetCharacters(lua_State *l)
1109 {
1110 std::vector<std::string> character_names;
1111 for (const CCharacter *character : CCharacter::Characters) {
1112 character_names.push_back(character->Ident);
1113 }
1114
1115 lua_createtable(l, character_names.size(), 0);
1116 for (size_t i = 1; i <= character_names.size(); ++i)
1117 {
1118 lua_pushstring(l, character_names[i-1].c_str());
1119 lua_rawseti(l, -2, i);
1120 }
1121 return 1;
1122 }
1123
CclGetCustomHeroes(lua_State * l)1124 static int CclGetCustomHeroes(lua_State *l)
1125 {
1126 std::vector<std::string> character_names;
1127 for (std::map<std::string, CCharacter *>::iterator iterator = CustomHeroes.begin(); iterator != CustomHeroes.end(); ++iterator) {
1128 character_names.push_back(iterator->first);
1129 }
1130
1131 lua_createtable(l, character_names.size(), 0);
1132 for (size_t i = 1; i <= character_names.size(); ++i)
1133 {
1134 lua_pushstring(l, character_names[i-1].c_str());
1135 lua_rawseti(l, -2, i);
1136 }
1137 return 1;
1138 }
1139
CclGetGrandStrategyHeroes(lua_State * l)1140 static int CclGetGrandStrategyHeroes(lua_State *l)
1141 {
1142 lua_createtable(l, GrandStrategyGame.Heroes.size(), 0);
1143 for (size_t i = 1; i <= GrandStrategyGame.Heroes.size(); ++i)
1144 {
1145 lua_pushstring(l, GrandStrategyGame.Heroes[i-1]->GetFullName().c_str());
1146 lua_rawseti(l, -2, i);
1147 }
1148 return 1;
1149 }
1150
1151 /**
1152 ** Parse character temporary data
1153 **
1154 ** @param l Lua state.
1155 */
CclCharacter(lua_State * l)1156 static int CclCharacter(lua_State *l)
1157 {
1158 const std::string ident = LuaToString(l, 1);
1159
1160 if (!lua_istable(l, 2)) {
1161 LuaError(l, "incorrect argument");
1162 }
1163
1164 CCharacter *character = CCharacter::GetCharacter(ident);
1165 if (!character) {
1166 return 0;
1167 }
1168
1169 // Parse the list:
1170 const int args = lua_rawlen(l, 2);
1171 for (int j = 0; j < args; ++j) {
1172 const char *value = LuaToString(l, 2, j + 1);
1173 ++j;
1174
1175 if (!strcmp(value, "deity")) {
1176 CDeity *deity = CDeity::GetDeity(LuaToString(l, 2, j + 1));
1177 if (deity) {
1178 character->Deities.push_back(deity);
1179 }
1180 } else {
1181 fprintf(stderr, "Character: Unsupported tag: %s\n", value);
1182 }
1183 }
1184
1185 return 0;
1186 }
1187
1188 // ----------------------------------------------------------------------------
1189
1190 /**
1191 ** Register CCL features for characters.
1192 */
CharacterCclRegister()1193 void CharacterCclRegister()
1194 {
1195 lua_register(Lua, "DefineCharacter", CclDefineCharacter);
1196 lua_register(Lua, "DefineCustomHero", CclDefineCustomHero);
1197 lua_register(Lua, "GetCharacterData", CclGetCharacterData);
1198 lua_register(Lua, "GetCustomHeroData", CclGetCustomHeroData);
1199 lua_register(Lua, "GetCharacters", CclGetCharacters);
1200 lua_register(Lua, "GetCustomHeroes", CclGetCustomHeroes);
1201 lua_register(Lua, "GetGrandStrategyHeroes", CclGetGrandStrategyHeroes);
1202 lua_register(Lua, "Character", CclCharacter);
1203 }
1204
1205 //@}
1206