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 grand_strategy.cpp - The grand strategy mode. */
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 -- Includes
32 ----------------------------------------------------------------------------*/
33
34 #include "stratagus.h"
35
36 #include "grand_strategy.h"
37
38 #include "character.h"
39 #include "civilization.h"
40 #include "game.h" // for loading screen elements
41 #include "font.h" // for grand strategy mode tooltip drawing
42 #include "iolib.h"
43 #include "luacallback.h"
44 #include "menus.h"
45 #include "player.h"
46 #include "results.h"
47 #include "sound_server.h"
48 #include "ui/interface.h"
49 #include "ui/ui.h"
50 #include "unit/unit.h"
51 #include "unit/unittype.h"
52 #include "upgrade/upgrade.h"
53 #include "upgrade/upgrade_modifier.h"
54 #include "util.h"
55 #include "video.h"
56
57 #include <ctype.h>
58
59 #include <string>
60 #include <map>
61
62 /*----------------------------------------------------------------------------
63 -- Variables
64 ----------------------------------------------------------------------------*/
65
66 bool GrandStrategy = false; ///if the game is in grand strategy mode
67 bool GrandStrategyGameLoading = false;
68 int GrandStrategyYear = 0;
69 std::string GrandStrategyWorld;
70 int PopulationGrowthThreshold = 1000;
71 CGrandStrategyGame GrandStrategyGame;
72 std::map<std::string, int> GrandStrategyHeroStringToIndex;
73 std::vector<CGrandStrategyEvent *> GrandStrategyEvents;
74 std::map<std::string, CGrandStrategyEvent *> GrandStrategyEventStringToPointer;
75
76 /*----------------------------------------------------------------------------
77 -- Functions
78 ----------------------------------------------------------------------------*/
79
DrawInterface()80 void CGrandStrategyGame::DrawInterface()
81 {
82 if (this->PlayerFaction != nullptr && this->PlayerFaction->OwnedProvinces.size() > 0) { //draw resource bar
83 std::vector<int> stored_resources;
84 stored_resources.push_back(CopperCost);
85 stored_resources.push_back(WoodCost);
86 stored_resources.push_back(StoneCost);
87 stored_resources.push_back(ResearchCost);
88 stored_resources.push_back(PrestigeCost);
89
90 Vec2i hovered_research_icon(-1, -1);
91 Vec2i hovered_prestige_icon(-1, -1);
92 for (size_t i = 0; i < stored_resources.size(); ++i) {
93 int x = 154 + (100 * i);
94 int y = 0;
95 UI.Resources[stored_resources[i]].G->DrawFrameClip(0, x, y, true);
96
97 int quantity_stored = this->PlayerFaction->Resources[stored_resources[i]];
98 int income = 0;
99 if (stored_resources[i] == CopperCost) {
100 income = this->PlayerFaction->Income[stored_resources[i]];
101 } else if (stored_resources[i] == ResearchCost || stored_resources[i] == LeadershipCost) {
102 income = this->PlayerFaction->Income[stored_resources[i]] / this->PlayerFaction->OwnedProvinces.size();
103 } else {
104 income = this->PlayerFaction->Income[stored_resources[i]];
105 }
106 std::string income_string;
107 if (income != 0) {
108 if (income > 0) {
109 income_string += "+";
110 }
111 income_string += std::to_string((long long) income);
112 }
113 std::string resource_stored_string = std::to_string((long long) quantity_stored) + income_string;
114
115 if (resource_stored_string.size() <= 9) {
116 CLabel(GetGameFont()).Draw(x + 18, y + 1, resource_stored_string);
117 } else {
118 CLabel(GetSmallFont()).Draw(x + 18, y + 1 + 2, resource_stored_string);
119 }
120
121 if (CursorScreenPos.x >= x && CursorScreenPos.x <= (x + UI.Resources[stored_resources[i]].G->getGraphicWidth()) && CursorScreenPos.y >= y && CursorScreenPos.y <= (y + UI.Resources[stored_resources[i]].G->getGraphicHeight())) {
122 if (stored_resources[i] == ResearchCost) {
123 hovered_research_icon.x = x;
124 hovered_research_icon.y = y;
125 } else if (stored_resources[i] == PrestigeCost) {
126 hovered_prestige_icon.x = x;
127 hovered_prestige_icon.y = y;
128 }
129 }
130 }
131 if (hovered_research_icon.x != -1 && hovered_research_icon.y != -1) {
132 DrawGenericPopup("Gain Research by building town halls, lumber mills, smithies and temples", hovered_research_icon.x, hovered_research_icon.y);
133 } else if (hovered_prestige_icon.x != -1 && hovered_prestige_icon.y != -1) {
134 DrawGenericPopup("Prestige influences trade priority between nations, and factions with negative prestige cannot declare war", hovered_prestige_icon.x, hovered_prestige_icon.y);
135 }
136 }
137 }
138
DoTurn()139 void CGrandStrategyGame::DoTurn()
140 {
141 for (size_t i = 0; i < this->Provinces.size(); ++i) {
142 if (this->Provinces[i]->Civilization != -1) { // if this province has a culture
143 if (this->Provinces[i]->Owner != nullptr) {
144 if (!this->Provinces[i]->HasFactionClaim(this->Provinces[i]->Owner->Civilization, this->Provinces[i]->Owner->Faction) && SyncRand(100) < 1) { // 1% chance the owner of this province will get a claim on it
145 this->Provinces[i]->AddFactionClaim(this->Provinces[i]->Owner->Civilization, this->Provinces[i]->Owner->Faction);
146 }
147
148 if (SyncRand(1000) == 0) { // 0.1% chance per year that a (randomly generated) literary work will be created in a province
149 this->CreateWork(nullptr, nullptr, this->Provinces[i]);
150 }
151 }
152 }
153 }
154
155 // check if any literary works should be published this year
156 int works_size = this->UnpublishedWorks.size();
157 for (int i = (works_size - 1); i >= 0; --i) {
158 CGrandStrategyHero *author = nullptr;
159 if (this->UnpublishedWorks[i]->Author != nullptr) {
160 author = this->GetHero(this->UnpublishedWorks[i]->Author->GetFullName());
161 if (author != nullptr && !author->IsAlive()) {
162 continue;
163 }
164 }
165
166 if ((author == nullptr && SyncRand(200) != 0) || (author != nullptr && SyncRand(10) != 0)) { // 0.5% chance per year that a work will be published if no author is preset, and 10% if an author is preset
167 continue;
168 }
169
170 int civilization = this->UnpublishedWorks[i]->Civilization;
171 if (
172 (author != nullptr && author->ProvinceOfOrigin != nullptr)
173 || (civilization != -1 && this->CultureProvinces.find(civilization) != this->CultureProvinces.end() && this->CultureProvinces[civilization].size() > 0)
174 ) {
175 bool characters_existed = true;
176 for (size_t j = 0; j < this->UnpublishedWorks[i]->Characters.size(); ++j) {
177 CGrandStrategyHero *hero = this->GetHero(this->UnpublishedWorks[i]->Characters[j]->GetFullName());
178
179 if (hero == nullptr || !hero->Existed) {
180 characters_existed = false;
181 break;
182 }
183 }
184 if (!characters_existed) {
185 continue;
186 }
187
188 if (author != nullptr && author->Province != nullptr) {
189 this->CreateWork(this->UnpublishedWorks[i], author, author->Province);
190 } else {
191 this->CreateWork(this->UnpublishedWorks[i], author, this->CultureProvinces[civilization][SyncRand(this->CultureProvinces[civilization].size())]);
192 }
193 }
194 }
195 }
196
PerformTrade(CGrandStrategyFaction & importer_faction,CGrandStrategyFaction & exporter_faction,int resource)197 void CGrandStrategyGame::PerformTrade(CGrandStrategyFaction &importer_faction, CGrandStrategyFaction &exporter_faction, int resource)
198 {
199 if (abs(importer_faction.Trade[resource]) > exporter_faction.Trade[resource]) {
200 importer_faction.Resources[resource] += exporter_faction.Trade[resource];
201 exporter_faction.Resources[resource] -= exporter_faction.Trade[resource];
202
203 importer_faction.Resources[CopperCost] -= exporter_faction.Trade[resource] * this->CommodityPrices[resource] / 100;
204 exporter_faction.Resources[CopperCost] += exporter_faction.Trade[resource] * this->CommodityPrices[resource] / 100;
205
206 importer_faction.Trade[resource] += exporter_faction.Trade[resource];
207 exporter_faction.Trade[resource] = 0;
208 } else {
209 importer_faction.Resources[resource] += abs(importer_faction.Trade[resource]);
210 exporter_faction.Resources[resource] -= abs(importer_faction.Trade[resource]);
211
212 importer_faction.Resources[CopperCost] -= abs(importer_faction.Trade[resource]) * this->CommodityPrices[resource] / 100;
213 exporter_faction.Resources[CopperCost] += abs(importer_faction.Trade[resource]) * this->CommodityPrices[resource] / 100;
214
215 exporter_faction.Trade[resource] += importer_faction.Trade[resource];
216 importer_faction.Trade[resource] = 0;
217 }
218 }
219
CreateWork(CUpgrade * work,CGrandStrategyHero * author,CGrandStrategyProvince * province)220 void CGrandStrategyGame::CreateWork(CUpgrade *work, CGrandStrategyHero *author, CGrandStrategyProvince *province)
221 {
222 if (!province || !province->Owner) {
223 return;
224 }
225
226 if (!province->Owner->HasTechnologyClass("writing")) { // only factions which have knowledge of writing can produce literary works
227 return;
228 }
229
230 if (work != nullptr) {
231 this->UnpublishedWorks.erase(std::remove(this->UnpublishedWorks.begin(), this->UnpublishedWorks.end(), work), this->UnpublishedWorks.end()); // remove work from the vector, so that it doesn't get created again
232 }
233
234 std::string work_name;
235 if (work != nullptr) {
236 work_name = work->Name;
237 } else {
238 work_name = province->GenerateWorkName();
239 if (work_name.empty()) {
240 return;
241 }
242 }
243
244 if (author == nullptr) {
245 author = province->GetRandomAuthor();
246 }
247
248 if (province->Owner == GrandStrategyGame.PlayerFaction || work != nullptr) { // only show foreign works that are predefined
249 std::string work_creation_message = "if (GenericDialog ~= nil) then GenericDialog(\"" + work_name + "\", \"";
250 if (author != nullptr) {
251 work_creation_message += "The " + FullyDecapitalizeString(author->Type->Name) + " " + author->GetFullName() + " ";
252 } else {
253 work_creation_message += "A sage ";
254 }
255 work_creation_message += "has written the literary work \\\"" + work_name + "\\\" in ";
256 if (province->Owner != GrandStrategyGame.PlayerFaction) {
257 work_creation_message += "the foreign lands of ";
258 }
259 work_creation_message += province->Name + "!";
260 if (work != nullptr && !work->Description.empty()) {
261 work_creation_message += " " + FindAndReplaceString(FindAndReplaceString(work->Description, "\"", "\\\""), "\n", "\\n");
262 }
263 if (work != nullptr && !work->Quote.empty()) {
264 work_creation_message += "\\n\\n" + FindAndReplaceString(FindAndReplaceString(work->Quote, "\"", "\\\""), "\n", "\\n");
265 }
266 work_creation_message += "\"";
267 if (province->Owner == GrandStrategyGame.PlayerFaction) {
268 work_creation_message += ", \"+1 Prestige\"";
269 }
270 work_creation_message += ") end;";
271 CclCommand(work_creation_message);
272 }
273
274 province->Owner->Resources[PrestigeCost] += 1;
275 }
276
TradePriority(CGrandStrategyFaction & faction_a,CGrandStrategyFaction & faction_b)277 bool CGrandStrategyGame::TradePriority(CGrandStrategyFaction &faction_a, CGrandStrategyFaction &faction_b)
278 {
279 return faction_a.Resources[PrestigeCost] > faction_b.Resources[PrestigeCost];
280 }
281
GetHero(std::string hero_full_name)282 CGrandStrategyHero *CGrandStrategyGame::GetHero(std::string hero_full_name)
283 {
284 if (!hero_full_name.empty() && GrandStrategyHeroStringToIndex.find(hero_full_name) != GrandStrategyHeroStringToIndex.end()) {
285 return this->Heroes[GrandStrategyHeroStringToIndex[hero_full_name]];
286 } else {
287 return nullptr;
288 }
289 }
290
SetOwner(int civilization_id,int faction_id)291 void CGrandStrategyProvince::SetOwner(int civilization_id, int faction_id)
292 {
293 //if new owner is the same as the current owner, return
294 if (
295 (this->Owner != nullptr && this->Owner->Civilization == civilization_id && this->Owner->Faction == faction_id)
296 || (this->Owner == nullptr && civilization_id == -1 && faction_id == -1)
297 ) {
298 return;
299 }
300
301 CGrandStrategyFaction *old_owner = this->Owner;
302
303 if (this->Owner != nullptr) { //if province has a previous owner, remove it from the owner's province list
304 this->Owner->OwnedProvinces.erase(std::remove(this->Owner->OwnedProvinces.begin(), this->Owner->OwnedProvinces.end(), this->ID), this->Owner->OwnedProvinces.end());
305 }
306
307 for (size_t i = 0; i < UnitTypes.size(); ++i) { //change the province's military score to be appropriate for the new faction's technologies
308 if (IsMilitaryUnit(*UnitTypes[i])) {
309 int old_owner_military_score_bonus = (this->Owner != nullptr ? this->Owner->MilitaryScoreBonus[i] : 0);
310 int new_owner_military_score_bonus = (faction_id != -1 ? GrandStrategyGame.Factions[civilization_id][faction_id]->MilitaryScoreBonus[i] : 0);
311 if (old_owner_military_score_bonus != new_owner_military_score_bonus) {
312 this->MilitaryScore += this->Units[i] * (new_owner_military_score_bonus - old_owner_military_score_bonus);
313 this->OffensiveMilitaryScore += this->Units[i] * new_owner_military_score_bonus - old_owner_military_score_bonus;
314 }
315 } else if (UnitTypes[i]->Class != -1 && UnitTypeClasses[UnitTypes[i]->Class] == "worker") {
316 int militia_unit_type = PlayerRaces.GetCivilizationClassUnitType(UnitTypes[i]->Civilization, GetUnitTypeClassIndexByName("militia"));
317 if (militia_unit_type != -1) {
318 int old_owner_military_score_bonus = (this->Owner != nullptr ? this->Owner->MilitaryScoreBonus[militia_unit_type] : 0);
319 int new_owner_military_score_bonus = (faction_id != -1 ? GrandStrategyGame.Factions[civilization_id][faction_id]->MilitaryScoreBonus[militia_unit_type] : 0);
320 if (old_owner_military_score_bonus != new_owner_military_score_bonus) {
321 this->MilitaryScore += this->Units[i] * ((new_owner_military_score_bonus - old_owner_military_score_bonus) / 2);
322 }
323 }
324 }
325 }
326
327 if (civilization_id != -1 && faction_id != -1) {
328 this->Owner = GrandStrategyGame.Factions[civilization_id][faction_id];
329 this->Owner->OwnedProvinces.push_back(this->ID);
330 } else {
331 this->Owner = nullptr;
332 }
333 }
334
SetSettlementBuilding(int building_id,bool has_settlement_building)335 void CGrandStrategyProvince::SetSettlementBuilding(int building_id, bool has_settlement_building)
336 {
337 if (building_id == -1) {
338 fprintf(stderr, "Tried to set invalid building type for the settlement of \"%s\".\n", this->Name.c_str());
339 return;
340 }
341
342 //if this province has an equivalent building for its civilization/faction, use that instead
343 if (UnitTypes[building_id]->Civilization != -1) {
344 if (this->GetClassUnitType(UnitTypes[building_id]->Class) != building_id && this->GetClassUnitType(UnitTypes[building_id]->Class) != -1) {
345 building_id = this->GetClassUnitType(UnitTypes[building_id]->Class);
346 }
347 }
348
349 if (this->SettlementBuildings[building_id] == has_settlement_building) {
350 return;
351 }
352
353 this->SettlementBuildings[building_id] = has_settlement_building;
354
355 int change = has_settlement_building ? 1 : -1;
356 for (int i = 0; i < MaxCosts; ++i) {
357 if (UnitTypes[building_id]->GrandStrategyProductionEfficiencyModifier[i] != 0) {
358 this->ProductionEfficiencyModifier[i] += UnitTypes[building_id]->GrandStrategyProductionEfficiencyModifier[i] * change;
359 }
360 }
361
362 if (UnitTypes[building_id]->Class != -1 && UnitTypeClasses[UnitTypes[building_id]->Class] == "stronghold") { //increase the military score of the province, if this building is a stronghold
363 this->MilitaryScore += (100 * 2) * change; // two guard towers if has a stronghold
364 }
365 }
366
SetModifier(CUpgrade * modifier,bool has_modifier)367 void CGrandStrategyProvince::SetModifier(CUpgrade *modifier, bool has_modifier)
368 {
369 if (this->HasModifier(modifier) == has_modifier) { // current situation already corresponds to has_modifier setting
370 return;
371 }
372
373 if (has_modifier) {
374 this->Modifiers.push_back(modifier);
375 } else {
376 this->Modifiers.erase(std::remove(this->Modifiers.begin(), this->Modifiers.end(), modifier), this->Modifiers.end());
377 }
378
379 int change = has_modifier ? 1 : -1;
380
381 for (int i = 0; i < MaxCosts; ++i) {
382 if (modifier->GrandStrategyProductionEfficiencyModifier[i] != 0) {
383 this->ProductionEfficiencyModifier[i] += modifier->GrandStrategyProductionEfficiencyModifier[i] * change;
384 }
385 }
386 }
387
SetUnitQuantity(int unit_type_id,int quantity)388 void CGrandStrategyProvince::SetUnitQuantity(int unit_type_id, int quantity)
389 {
390 if (unit_type_id == -1) {
391 return;
392 }
393
394 // fprintf(stderr, "Setting the quantity of unit type \"%s\" to %d in the %s province.\n", UnitTypes[unit_type_id]->Ident.c_str(), quantity, this->Name.c_str());
395
396 quantity = std::max(0, quantity);
397
398 int change = quantity - this->Units[unit_type_id];
399
400 this->TotalUnits += change;
401
402 if (IsMilitaryUnit(*UnitTypes[unit_type_id])) {
403 this->MilitaryScore += change * (UnitTypes[unit_type_id]->DefaultStat.Variables[POINTS_INDEX].Value + (this->Owner != nullptr ? this->Owner->MilitaryScoreBonus[unit_type_id] : 0));
404 this->OffensiveMilitaryScore += change * (UnitTypes[unit_type_id]->DefaultStat.Variables[POINTS_INDEX].Value + (this->Owner != nullptr ? this->Owner->MilitaryScoreBonus[unit_type_id] : 0));
405 }
406
407 if (UnitTypes[unit_type_id]->Class != -1 && UnitTypeClasses[UnitTypes[unit_type_id]->Class] == "worker") {
408 this->TotalWorkers += change;
409
410 //if this unit's civilization can change workers into militia, add half of the militia's points to the military score (one in every two workers becomes a militia when the province is attacked)
411 int militia_unit_type = PlayerRaces.GetCivilizationClassUnitType(UnitTypes[unit_type_id]->Civilization, GetUnitTypeClassIndexByName("militia"));
412 if (militia_unit_type != -1) {
413 this->MilitaryScore += change * ((UnitTypes[militia_unit_type]->DefaultStat.Variables[POINTS_INDEX].Value + (this->Owner != nullptr ? this->Owner->MilitaryScoreBonus[militia_unit_type] : 0)) / 2);
414 }
415 }
416
417 this->Units[unit_type_id] = quantity;
418 }
419
ChangeUnitQuantity(int unit_type_id,int quantity)420 void CGrandStrategyProvince::ChangeUnitQuantity(int unit_type_id, int quantity)
421 {
422 this->SetUnitQuantity(unit_type_id, this->Units[unit_type_id] + quantity);
423 }
424
SetPopulation(int quantity)425 void CGrandStrategyProvince::SetPopulation(int quantity)
426 {
427 if (this->Civilization == -1) {
428 return;
429 }
430
431 int worker_unit_type = this->GetClassUnitType(GetUnitTypeClassIndexByName("worker"));
432
433 if (quantity > 0) {
434 quantity /= 10000; // each population unit represents 10,000 people
435 quantity /= 2; // only (working-age) adults are represented, so around half of the total population
436 quantity = std::max(1, quantity);
437 }
438
439 // quantity -= this->TotalUnits - this->Units[worker_unit_type]; // decrease from the quantity to be set the population that isn't composed of workers
440 // don't take military units in consideration for this population count for now (since they don't cost food anyway)
441 quantity -= this->TotalWorkers - this->Units[worker_unit_type]; // decrease from the quantity to be set the population that isn't composed of workers
442 quantity = std::max(0, quantity);
443
444 this->SetUnitQuantity(worker_unit_type, quantity);
445 }
446
SetHero(std::string hero_full_name,int value)447 void CGrandStrategyProvince::SetHero(std::string hero_full_name, int value)
448 {
449 if (value == 1) {
450 this->Movement = true;
451 }
452 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
453 if (hero) {
454 //update the hero
455 if (value == 0) {
456 hero->Die();
457 return;
458 }
459 hero->State = value;
460 } else {
461 //if the hero hasn't been defined yet, give an error message
462 fprintf(stderr, "Hero \"%s\" doesn't exist.\n", hero_full_name.c_str());
463 return;
464 }
465 }
466
AddFactionClaim(int civilization_id,int faction_id)467 void CGrandStrategyProvince::AddFactionClaim(int civilization_id, int faction_id)
468 {
469 this->Claims.push_back(GrandStrategyGame.Factions[civilization_id][faction_id]);
470 GrandStrategyGame.Factions[civilization_id][faction_id]->Claims.push_back(this);
471 }
472
RemoveFactionClaim(int civilization_id,int faction_id)473 void CGrandStrategyProvince::RemoveFactionClaim(int civilization_id, int faction_id)
474 {
475 this->Claims.erase(std::remove(this->Claims.begin(), this->Claims.end(), GrandStrategyGame.Factions[civilization_id][faction_id]), this->Claims.end());
476 GrandStrategyGame.Factions[civilization_id][faction_id]->Claims.erase(std::remove(GrandStrategyGame.Factions[civilization_id][faction_id]->Claims.begin(), GrandStrategyGame.Factions[civilization_id][faction_id]->Claims.end(), this), GrandStrategyGame.Factions[civilization_id][faction_id]->Claims.end());
477 }
478
HasBuildingClass(std::string building_class_name)479 bool CGrandStrategyProvince::HasBuildingClass(std::string building_class_name)
480 {
481 if (this->Civilization == -1 || building_class_name.empty()) {
482 return false;
483 }
484
485 int building_type = this->GetClassUnitType(GetUnitTypeClassIndexByName(building_class_name));
486
487 if (building_type == -1 && building_class_name == "mercenary-camp") { //special case for mercenary camps, which are a neutral building
488 building_type = UnitTypeIdByIdent("unit-mercenary-camp");
489 }
490
491 if (building_type != -1 && this->SettlementBuildings[building_type] == true) {
492 return true;
493 }
494
495 return false;
496 }
497
HasModifier(CUpgrade * modifier)498 bool CGrandStrategyProvince::HasModifier(CUpgrade *modifier)
499 {
500 return std::find(this->Modifiers.begin(), this->Modifiers.end(), modifier) != this->Modifiers.end();
501 }
502
BordersModifier(CUpgrade * modifier)503 bool CGrandStrategyProvince::BordersModifier(CUpgrade *modifier)
504 {
505 //see if any provinces bordering this one have the modifier (count provinces reachable through water as well)
506
507 for (size_t i = 0; i < this->BorderProvinces.size(); ++i) {
508 CGrandStrategyProvince *border_province = this->BorderProvinces[i];
509 if (border_province->HasModifier(modifier)) {
510 return true;
511 }
512 }
513
514 return false;
515 }
516
HasFactionClaim(int civilization_id,int faction_id)517 bool CGrandStrategyProvince::HasFactionClaim(int civilization_id, int faction_id)
518 {
519 for (size_t i = 0; i < this->Claims.size(); ++i) {
520 if (this->Claims[i]->Civilization == civilization_id && this->Claims[i]->Faction == faction_id) {
521 return true;
522 }
523 }
524 return false;
525 }
526
BordersProvince(CGrandStrategyProvince * province)527 bool CGrandStrategyProvince::BordersProvince(CGrandStrategyProvince *province)
528 {
529 for (size_t i = 0; i < this->BorderProvinces.size(); ++i) {
530 if (this->BorderProvinces[i] == province) {
531 return true;
532 }
533 }
534 return false;
535 }
536
HasSecondaryBorderThroughWaterWith(CGrandStrategyProvince * province)537 bool CGrandStrategyProvince::HasSecondaryBorderThroughWaterWith(CGrandStrategyProvince *province)
538 {
539 for (size_t i = 0; i < this->BorderProvinces.size(); ++i) {
540 CGrandStrategyProvince *border_province = this->BorderProvinces[i];
541 if (border_province->Water) {
542 for (size_t j = 0; j < border_province->BorderProvinces.size(); ++j) {
543 if (border_province->BorderProvinces[j] == province) {
544 return true;
545 }
546 }
547 }
548 }
549 return false;
550 }
551
BordersFaction(int faction_civilization,int faction,bool check_through_water)552 bool CGrandStrategyProvince::BordersFaction(int faction_civilization, int faction, bool check_through_water)
553 {
554 for (size_t i = 0; i < this->BorderProvinces.size(); ++i) {
555 CGrandStrategyProvince *border_province = this->BorderProvinces[i];
556 if (border_province->Owner == nullptr) {
557 if (border_province->Water && check_through_water) {
558 for (size_t j = 0; j < border_province->BorderProvinces.size(); ++j) {
559 if (
560 border_province->BorderProvinces[j]->Owner != nullptr
561 && border_province->BorderProvinces[j]->Owner->Civilization == faction_civilization
562 && border_province->BorderProvinces[j]->Owner->Faction == faction
563 ) {
564 return true;
565 }
566 }
567 }
568 continue;
569 }
570 if (border_province->Owner->Civilization == faction_civilization && border_province->Owner->Faction == faction) {
571 return true;
572 }
573 }
574 return false;
575 }
576
GetPopulation()577 int CGrandStrategyProvince::GetPopulation()
578 {
579 return (this->TotalWorkers * 10000) * 2;
580 }
581
GetClassUnitType(int class_id)582 int CGrandStrategyProvince::GetClassUnitType(int class_id)
583 {
584 return PlayerRaces.GetCivilizationClassUnitType(this->Civilization, class_id);
585 }
586
GetDesirabilityRating()587 int CGrandStrategyProvince::GetDesirabilityRating()
588 {
589 int desirability = 0;
590
591 std::vector<int> resources;
592 resources.push_back(CopperCost);
593 resources.push_back(GoldCost);
594 resources.push_back(SilverCost);
595 resources.push_back(WoodCost);
596 resources.push_back(StoneCost);
597
598 for (size_t i = 0; i < resources.size(); ++i) {
599 desirability += this->ProductionCapacity[resources[i]] * 100 * GrandStrategyGame.CommodityPrices[resources[i]] / 100;
600 }
601
602 if (this->Coastal) {
603 desirability += 250;
604 }
605
606 return desirability;
607 }
608
GenerateWorkName()609 std::string CGrandStrategyProvince::GenerateWorkName()
610 {
611 if (this->Owner == nullptr) {
612 return "";
613 }
614
615 std::string work_name;
616
617 std::vector<CGrandStrategyHero *> potential_heroes;
618 for (size_t i = 0; i < this->Owner->HistoricalMinisters[CharacterTitleHeadOfState].size(); ++i) {
619 potential_heroes.push_back(this->Owner->HistoricalMinisters[CharacterTitleHeadOfState][i]);
620 }
621
622 if (potential_heroes.size() > 0 && SyncRand(10) != 0) { // 9 chances out of 10 that a literary work will use a hero's name as a basis
623 work_name += potential_heroes[SyncRand(potential_heroes.size())]->Name;
624 if (work_name.substr(work_name.size() - 1, 1) != "s") {
625 work_name += "s";
626 }
627
628 work_name += "mol";
629 }
630
631 return work_name;
632 }
633
GetRandomAuthor()634 CGrandStrategyHero *CGrandStrategyProvince::GetRandomAuthor()
635 {
636 std::vector<CGrandStrategyHero *> potential_authors;
637
638 for (size_t i = 0; i < this->Heroes.size(); ++i) {
639 if (this->Heroes[i]->Type->Class != -1 && UnitTypeClasses[this->Heroes[i]->Type->Class] == "priest") { // first see if there are any heroes in the province from a unit class likely to produce scholarly works
640 potential_authors.push_back(this->Heroes[i]);
641 }
642 }
643
644 if (potential_authors.size() == 0) { // if the first loop through the province's heroes failed, try to get a hero from any class
645 for (size_t i = 0; i < this->Heroes.size(); ++i) {
646 potential_authors.push_back(this->Heroes[i]);
647 }
648 }
649
650 if (potential_authors.size() > 0) { // if a hero was found in the province, return it as the result
651 return potential_authors[SyncRand(potential_authors.size())];
652 } else { // if no hero was found, generate one
653 return nullptr;
654 }
655 }
656
SetTechnology(int upgrade_id,bool has_technology,bool secondary_setting)657 void CGrandStrategyFaction::SetTechnology(int upgrade_id, bool has_technology, bool secondary_setting)
658 {
659 if (this->Technologies[upgrade_id] == has_technology) {
660 return;
661 }
662
663 this->Technologies[upgrade_id] = has_technology;
664
665 int change = has_technology ? 1 : -1;
666
667 //add military score bonuses
668 for (size_t z = 0; z < AllUpgrades[upgrade_id]->UpgradeModifiers.size(); ++z) {
669 for (size_t i = 0; i < UnitTypes.size(); ++i) {
670
671 Assert(AllUpgrades[upgrade_id]->UpgradeModifiers[z]->ApplyTo[i] == '?' || AllUpgrades[upgrade_id]->UpgradeModifiers[z]->ApplyTo[i] == 'X');
672
673 if (AllUpgrades[upgrade_id]->UpgradeModifiers[z]->ApplyTo[i] == 'X') {
674 if (AllUpgrades[upgrade_id]->UpgradeModifiers[z]->Modifier.Variables[POINTS_INDEX].Value) {
675 this->MilitaryScoreBonus[i] += AllUpgrades[upgrade_id]->UpgradeModifiers[z]->Modifier.Variables[POINTS_INDEX].Value * change;
676 }
677 }
678 }
679 }
680
681 if (!secondary_setting) { //if this technology is not being set as a result of another technology of the same class being researched
682 if (has_technology) { //if value is true, mark technologies from other civilizations that are of the same class as researched too, so that the player doesn't need to research the same type of technology every time
683 if (AllUpgrades[upgrade_id]->Class != -1) {
684 for (size_t i = 0; i < AllUpgrades.size(); ++i) {
685 if (AllUpgrades[upgrade_id]->Class == AllUpgrades[i]->Class) {
686 this->SetTechnology(i, has_technology, true);
687 }
688 }
689 }
690 }
691 }
692 }
693
SetCapital(CGrandStrategyProvince * province)694 void CGrandStrategyFaction::SetCapital(CGrandStrategyProvince *province)
695 {
696 this->Capital = province;
697 }
698
SetDiplomacyState(CGrandStrategyFaction * faction,int diplomacy_state_id)699 void CGrandStrategyFaction::SetDiplomacyState(CGrandStrategyFaction *faction, int diplomacy_state_id)
700 {
701 int second_diplomacy_state_id; // usually the second diplomacy state is the same as the first, but there are asymmetrical diplomacy states (such as vassal/sovereign relationships)
702 if (diplomacy_state_id == DiplomacyStateVassal) {
703 second_diplomacy_state_id = DiplomacyStateOverlord;
704 } else if (diplomacy_state_id == DiplomacyStateOverlord) {
705 second_diplomacy_state_id = DiplomacyStateVassal;
706 } else {
707 second_diplomacy_state_id = diplomacy_state_id;
708 }
709
710 this->DiplomacyStates[faction] = diplomacy_state_id;
711 faction->DiplomacyStates[this] = second_diplomacy_state_id;
712 }
713
SetMinister(int title,std::string hero_full_name)714 void CGrandStrategyFaction::SetMinister(int title, std::string hero_full_name)
715 {
716 if (this->Ministers[title] != nullptr && std::find(this->Ministers[title]->Titles.begin(), this->Ministers[title]->Titles.end(), std::pair<int, CGrandStrategyFaction *>(title, this)) != this->Ministers[title]->Titles.end()) { // remove from the old minister's array
717 this->Ministers[title]->Titles.erase(std::remove(this->Ministers[title]->Titles.begin(), this->Ministers[title]->Titles.end(), std::pair<int, CGrandStrategyFaction *>(title, this)), this->Ministers[title]->Titles.end());
718 }
719
720 if (hero_full_name.empty()) {
721 if (this->CanHaveSuccession(title, true)) { //if the minister died a violent death, wait until the next turn to replace him
722 this->MinisterSuccession(title);
723 } else {
724 this->Ministers[title] = nullptr;
725 }
726 } else {
727 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
728 if (hero) {
729 this->Ministers[title] = const_cast<CGrandStrategyHero *>(&(*hero));
730 hero->Titles.push_back(std::pair<int, CGrandStrategyFaction *>(title, this));
731
732 if (this->IsAlive()) {
733 int titles_size = hero->Titles.size();
734 for (int i = (titles_size - 1); i >= 0; --i) {
735 if (!(hero->Titles[i].first == title && hero->Titles[i].second == this) && hero->Titles[i].first != CharacterTitleHeadOfState) { // a character can only have multiple head of state titles, but not others
736 hero->Titles[i].second->SetMinister(hero->Titles[i].first, "");
737 }
738 }
739 }
740 } else {
741 fprintf(stderr, "Tried to make \"%s\" the \"%s\" of the \"%s\", but the hero doesn't exist.\n", hero_full_name.c_str(), GetCharacterTitleNameById(title).c_str(), this->GetFullName().c_str());
742 }
743
744 if (this == GrandStrategyGame.PlayerFaction) {
745 std::string new_minister_message = "if (GenericDialog ~= nil) then GenericDialog(\"";
746 // new_minister_message += this->GetCharacterTitle(title, this->Ministers[title]->Gender) + " " + this->Ministers[title]->GetFullName();
747 new_minister_message += "\", \"";
748 // new_minister_message += "A new " + FullyDecapitalizeString(this->GetCharacterTitle(title, this->Ministers[title]->Gender));
749 if (title == CharacterTitleHeadOfState) {
750 new_minister_message += " has come to power in our realm, ";
751 } else {
752 new_minister_message += " has been appointed, ";
753 }
754 new_minister_message += this->Ministers[title]->GetFullName() + "!\\n\\n";
755 new_minister_message += "Type: " + this->Ministers[title]->Type->Name + "\\n" + "Trait: " + this->Ministers[title]->Trait->Name + "\\n" + + "\\n\\n" + this->Ministers[title]->GetMinisterEffectsString(title);
756 new_minister_message += "\") end;";
757 CclCommand(new_minister_message);
758 }
759
760 if (std::find(this->HistoricalMinisters[title].begin(), this->HistoricalMinisters[title].end(), hero) == this->HistoricalMinisters[title].end()) {
761 this->HistoricalMinisters[title].push_back(hero);
762 }
763
764 if (this->IsAlive() && (hero->Province == nullptr || hero->Province->Owner != this)) { // if the hero's province is not owned by this faction, move him to a random province owned by this faction
765 this->GetRandomProvinceWeightedByPopulation()->SetHero(hero->GetFullName(), hero->State);
766 }
767 }
768 }
769
MinisterSuccession(int title)770 void CGrandStrategyFaction::MinisterSuccession(int title)
771 {
772 if (
773 this->Ministers[title] != nullptr
774 && (PlayerRaces.Factions[this->Faction]->Type == FactionTypeTribe || this->GovernmentType == GovernmentTypeMonarchy)
775 && title == CharacterTitleHeadOfState
776 ) { //if is a tribe or a monarchical polity, try to perform ruler succession by descent
777 for (size_t i = 0; i < this->Ministers[title]->Children.size(); ++i) {
778 if (this->Ministers[title]->Children[i]->IsAlive() && this->Ministers[title]->Children[i]->IsVisible() && this->Ministers[title]->Children[i]->Gender == MaleGender) { //historically males have generally been given priority in throne inheritance (if not exclusivity), specially in the cultures currently playable in the game
779 this->SetMinister(title, this->Ministers[title]->Children[i]->GetFullName());
780 return;
781 }
782 }
783 for (size_t i = 0; i < this->Ministers[title]->Siblings.size(); ++i) { // now check for male siblings of the current ruler
784 if (this->Ministers[title]->Siblings[i]->IsAlive() && this->Ministers[title]->Siblings[i]->IsVisible() && this->Ministers[title]->Siblings[i]->Gender == MaleGender) {
785 this->SetMinister(title, this->Ministers[title]->Siblings[i]->GetFullName());
786 return;
787 }
788 }
789 for (size_t i = 0; i < this->Ministers[title]->Children.size(); ++i) { //check again for children, but now allow for inheritance regardless of gender
790 if (this->Ministers[title]->Children[i]->IsAlive() && this->Ministers[title]->Children[i]->IsVisible()) {
791 this->SetMinister(title, this->Ministers[title]->Children[i]->GetFullName());
792 return;
793 }
794 }
795 for (size_t i = 0; i < this->Ministers[title]->Siblings.size(); ++i) { //check again for siblings, but now allow for inheritance regardless of gender
796 if (this->Ministers[title]->Siblings[i]->IsAlive() && this->Ministers[title]->Siblings[i]->IsVisible()) {
797 this->SetMinister(title, this->Ministers[title]->Siblings[i]->GetFullName());
798 return;
799 }
800 }
801
802 // if no family successor was found, the title becomes extinct if it is only a titular one (an aristocratic title whose corresponding faction does not actually hold territory)
803 if (!this->CanHaveSuccession(title, false) || title != CharacterTitleHeadOfState) {
804 this->Ministers[title] = nullptr;
805 return;
806 }
807 }
808
809 CGrandStrategyHero *best_candidate = nullptr;
810 int best_score = 0;
811
812 for (size_t i = 0; i < GrandStrategyGame.Heroes.size(); ++i) {
813 if (
814 GrandStrategyGame.Heroes[i]->IsAlive()
815 && GrandStrategyGame.Heroes[i]->IsVisible()
816 && (
817 (GrandStrategyGame.Heroes[i]->Province != nullptr && GrandStrategyGame.Heroes[i]->Province->Owner == this)
818 || (GrandStrategyGame.Heroes[i]->Province == nullptr && GrandStrategyGame.Heroes[i]->ProvinceOfOrigin != nullptr && GrandStrategyGame.Heroes[i]->ProvinceOfOrigin->Owner == this)
819 )
820 && !GrandStrategyGame.Heroes[i]->Custom
821 && GrandStrategyGame.Heroes[i]->IsEligibleForTitle(title)
822 ) {
823 int score = GrandStrategyGame.Heroes[i]->GetTitleScore(title);
824 if (score > best_score) {
825 best_candidate = GrandStrategyGame.Heroes[i];
826 best_score = score;
827 }
828 }
829 }
830 if (best_candidate != nullptr) {
831 this->SetMinister(title, best_candidate->GetFullName());
832 return;
833 }
834
835 this->Ministers[title] = nullptr;
836 }
837
IsAlive()838 bool CGrandStrategyFaction::IsAlive()
839 {
840 return this->OwnedProvinces.size() > 0;
841 }
842
HasTechnologyClass(std::string technology_class_name)843 bool CGrandStrategyFaction::HasTechnologyClass(std::string technology_class_name)
844 {
845 if (this->Civilization == -1 || technology_class_name.empty()) {
846 return false;
847 }
848
849 int technology_id = PlayerRaces.GetFactionClassUpgrade(this->Faction, GetUpgradeClassIndexByName(technology_class_name));
850
851 if (technology_id != -1 && this->Technologies[technology_id] == true) {
852 return true;
853 }
854
855 return false;
856 }
857
CanHaveSuccession(int title,bool family_inheritance)858 bool CGrandStrategyFaction::CanHaveSuccession(int title, bool family_inheritance)
859 {
860 if (!this->IsAlive() && (title != CharacterTitleHeadOfState || !family_inheritance || PlayerRaces.Factions[this->Faction]->Type == FactionTypeTribe || this->GovernmentType != GovernmentTypeMonarchy)) { // head of state titles can be inherited even if their respective factions have no provinces, but if the line dies out then the title becomes extinct; tribal titles cannot be titular-only
861 return false;
862 }
863
864 return true;
865 }
866
IsConquestDesirable(CGrandStrategyProvince * province)867 bool CGrandStrategyFaction::IsConquestDesirable(CGrandStrategyProvince *province)
868 {
869 if (this->OwnedProvinces.size() == 1 && province->Owner == nullptr && PlayerRaces.Factions[this->Faction]->Type == FactionTypeTribe) {
870 if (province->GetDesirabilityRating() <= GrandStrategyGame.Provinces[this->OwnedProvinces[0]]->GetDesirabilityRating()) { // if conquering the province would trigger a migration, the conquest is only desirable if the province is worth more
871 return false;
872 }
873 }
874
875 return true;
876 }
877
GetTroopCostModifier()878 int CGrandStrategyFaction::GetTroopCostModifier()
879 {
880 int modifier = 0;
881
882 if (this->Ministers[CharacterTitleHeadOfState] != nullptr) {
883 modifier += this->Ministers[CharacterTitleHeadOfState]->GetTroopCostModifier();
884 }
885
886 if (this->Ministers[CharacterTitleWarMinister] != nullptr) {
887 modifier += this->Ministers[CharacterTitleWarMinister]->GetTroopCostModifier();
888 }
889
890 return modifier;
891 }
892
GetDiplomacyState(CGrandStrategyFaction * faction)893 int CGrandStrategyFaction::GetDiplomacyState(CGrandStrategyFaction *faction)
894 {
895 if (this->DiplomacyStates.find(faction) != this->DiplomacyStates.end()) {
896 return this->DiplomacyStates[faction];
897 } else {
898 return DiplomacyStatePeace;
899 }
900 }
901
GetDiplomacyStateProposal(CGrandStrategyFaction * faction)902 int CGrandStrategyFaction::GetDiplomacyStateProposal(CGrandStrategyFaction *faction)
903 {
904 if (this->DiplomacyStateProposals.find(faction) != this->DiplomacyStateProposals.end()) {
905 return this->DiplomacyStateProposals[faction];
906 } else {
907 return -1;
908 }
909 }
910
GetFullName()911 std::string CGrandStrategyFaction::GetFullName()
912 {
913 if (PlayerRaces.Factions[this->Faction]->Type == FactionTypeTribe) {
914 return PlayerRaces.Factions[this->Faction]->Name;
915 } else if (PlayerRaces.Factions[this->Faction]->Type == FactionTypePolity) {
916 // return this->GetTitle() + " of " + PlayerRaces.Factions[this->Faction]->Name;
917 }
918
919 return "";
920 }
921
GetRandomProvinceWeightedByPopulation()922 CGrandStrategyProvince *CGrandStrategyFaction::GetRandomProvinceWeightedByPopulation()
923 {
924 std::vector<int> potential_provinces;
925 for (size_t i = 0; i < this->OwnedProvinces.size(); ++i) {
926 int weight = std::max(1, GrandStrategyGame.Provinces[this->OwnedProvinces[i]]->TotalWorkers);
927 for (int j = 0; j < weight; ++j) {
928 potential_provinces.push_back(this->OwnedProvinces[i]);
929 }
930 }
931
932 if (potential_provinces.size() > 0) {
933 return GrandStrategyGame.Provinces[potential_provinces[SyncRand(potential_provinces.size())]];
934 } else {
935 return nullptr;
936 }
937 }
938
Die()939 void CGrandStrategyHero::Die()
940 {
941 //show message that the hero has died
942 /*
943 if (this->IsVisible()) {
944 if (GrandStrategyGame.PlayerFaction != nullptr && GrandStrategyGame.PlayerFaction->Ministers[CharacterTitleHeadOfState] == this) {
945 char buf[256];
946 snprintf(
947 buf, sizeof(buf), "if (GenericDialog ~= nil) then GenericDialog(\"%s\", \"%s\") end;",
948 (GrandStrategyGame.PlayerFaction->GetCharacterTitle(CharacterTitleHeadOfState, this->Gender) + " " + this->GetFullName() + " Dies").c_str(),
949 ("Tragic news spread throughout our realm. Our " + FullyDecapitalizeString(GrandStrategyGame.PlayerFaction->GetCharacterTitle(CharacterTitleHeadOfState, this->Gender)) + ", " + this->GetFullName() + ", has died! May his soul rest in peace.").c_str()
950 );
951 CclCommand(buf);
952 } else if (this->GetFaction() == GrandStrategyGame.PlayerFaction) {
953 char buf[256];
954 snprintf(
955 buf, sizeof(buf), "if (GenericDialog ~= nil) then GenericDialog(\"%s\", \"%s\") end;",
956 (this->GetBestDisplayTitle() + " " + this->GetFullName() + " Dies").c_str(),
957 ("My lord, the " + FullyDecapitalizeString(this->GetBestDisplayTitle()) + " " + this->GetFullName() + " has died!").c_str()
958 );
959 CclCommand(buf);
960 }
961 }
962 */
963
964 this->State = 0;
965
966 //check if the hero has government positions in a faction, and if so, remove it from that position
967 int titles_size = this->Titles.size();
968 for (int i = (titles_size - 1); i >= 0; --i) {
969 this->Titles[i].second->SetMinister(this->Titles[i].first, "");
970 }
971
972 this->Province = nullptr;
973 }
974
SetType(int unit_type_id)975 void CGrandStrategyHero::SetType(int unit_type_id)
976 {
977 //if the hero's unit type changed
978 if (unit_type_id != this->Type->Slot) {
979 this->Type = UnitTypes[unit_type_id];
980 }
981
982 this->UpdateAttributes();
983 }
984
IsAlive()985 bool CGrandStrategyHero::IsAlive()
986 {
987 return this->State != 0;
988 }
989
IsVisible()990 bool CGrandStrategyHero::IsVisible()
991 {
992 return this->Type->DefaultStat.Variables[GENDER_INDEX].Value == 0 || this->Gender == this->Type->DefaultStat.Variables[GENDER_INDEX].Value; // hero not visible if their unit type has a set gender which is different from the hero's (this is because of instances where i.e. females have a unit type that only has male portraits)
993 }
994
IsGenerated()995 bool CGrandStrategyHero::IsGenerated()
996 {
997 return !this->Custom && CCharacter::GetCharacter(this->GetFullName()) == nullptr;
998 }
999
IsEligibleForTitle(int title)1000 bool CGrandStrategyHero::IsEligibleForTitle(int title)
1001 {
1002 if (this->GetFaction()->GovernmentType == GovernmentTypeMonarchy && title == CharacterTitleHeadOfState && this->Type->Class != -1 && UnitTypeClasses[this->Type->Class] == "worker") { // commoners cannot become monarchs
1003 return false;
1004 } else if (this->GetFaction()->GovernmentType == GovernmentTypeTheocracy && title == CharacterTitleHeadOfState && this->Type->Class != -1 && UnitTypeClasses[this->Type->Class] != "priest") { // non-priests cannot rule theocracies
1005 return false;
1006 }
1007
1008 for (size_t i = 0; i < this->Titles.size(); ++i) {
1009 if (this->Titles[i].first == CharacterTitleHeadOfState && this->Titles[i].second->IsAlive() && title != CharacterTitleHeadOfState) { // if it is not a head of state title, and this character is already the head of state of a living faction, return false
1010 return false;
1011 } else if (this->Titles[i].first == CharacterTitleHeadOfGovernment && title != CharacterTitleHeadOfState) { // if is already a head of government, don't accept ministerial titles of lower rank (that is, any but the title of head of state)
1012 return false;
1013 } else if (this->Titles[i].first != CharacterTitleHeadOfState && this->Titles[i].first != CharacterTitleHeadOfGovernment && title != CharacterTitleHeadOfState && title != CharacterTitleHeadOfGovernment) { // if is already a minister, don't accept another ministerial title of equal rank
1014 return false;
1015 }
1016 }
1017
1018 for (size_t i = 0; i < this->ProvinceTitles.size(); ++i) {
1019 if (this->ProvinceTitles[i].first != CharacterTitleHeadOfState && this->ProvinceTitles[i].first != CharacterTitleHeadOfGovernment && title != CharacterTitleHeadOfState && title != CharacterTitleHeadOfGovernment) { // if already has a government position, don't accept another ministerial title of equal rank
1020 return false;
1021 }
1022 }
1023
1024 return true;
1025 }
1026
GetTroopCostModifier()1027 int CGrandStrategyHero::GetTroopCostModifier()
1028 {
1029 int modifier = 0;
1030
1031 modifier += (this->GetAttributeModifier(IntelligenceAttribute) + this->GetAttributeModifier(this->GetMartialAttribute())) / 2 * -5 / 2; //-2.5% troop cost modifier per average of the intelligence modifier and the strength/dexterity one (depending on which one the character uses)
1032
1033 return modifier;
1034 }
1035
GetTitleScore(int title,CGrandStrategyProvince * province)1036 int CGrandStrategyHero::GetTitleScore(int title, CGrandStrategyProvince *province)
1037 {
1038 int score = 0;
1039 if (title == CharacterTitleHeadOfState) {
1040 score = ((this->Attributes[IntelligenceAttribute] + ((this->Attributes[this->GetMartialAttribute()] + this->Attributes[IntelligenceAttribute]) / 2) + this->Attributes[CharismaAttribute]) / 3) + 1;
1041 } else if (title == CharacterTitleHeadOfGovernment) {
1042 score = ((this->Attributes[IntelligenceAttribute] + ((this->Attributes[this->GetMartialAttribute()] + this->Attributes[IntelligenceAttribute]) / 2) + this->Attributes[CharismaAttribute]) / 3) + 1;
1043 } else if (title == CharacterTitleEducationMinister) {
1044 score = this->Attributes[IntelligenceAttribute];
1045 } else if (title == CharacterTitleFinanceMinister) {
1046 score = this->Attributes[IntelligenceAttribute];
1047 } else if (title == CharacterTitleWarMinister) {
1048 score = (this->Attributes[this->GetMartialAttribute()] + this->Attributes[IntelligenceAttribute]) / 2;
1049 } else if (title == CharacterTitleInteriorMinister) {
1050 score = this->Attributes[IntelligenceAttribute];
1051 } else if (title == CharacterTitleJusticeMinister) {
1052 score = this->Attributes[IntelligenceAttribute];
1053 } else if (title == CharacterTitleForeignMinister) {
1054 score = (this->Attributes[CharismaAttribute] + this->Attributes[IntelligenceAttribute]) / 2;
1055 } else if (title == CharacterTitleGovernor) {
1056 score = ((this->Attributes[IntelligenceAttribute] + ((this->Attributes[this->GetMartialAttribute()] + this->Attributes[IntelligenceAttribute]) / 2) + this->Attributes[CharismaAttribute]) / 3);
1057 if (province != nullptr && (province == this->Province || province == this->ProvinceOfOrigin)) {
1058 score += 1;
1059 }
1060 }
1061
1062 if (this->Civilization->ID != this->GetFaction()->Civilization) {
1063 score -= 1; //characters of a different culture than the faction they are in have a smaller chance of getting a ministerial or gubernatorial position
1064 }
1065
1066 return score;
1067 }
1068
GetMinisterEffectsString(int title)1069 std::string CGrandStrategyHero::GetMinisterEffectsString(int title)
1070 {
1071 std::string minister_effects_string;
1072
1073 bool first = true;
1074
1075 if (title == CharacterTitleHeadOfState || title == CharacterTitleWarMinister) {
1076 int modifier = this->GetTroopCostModifier();
1077 if (modifier != 0) {
1078 if (!first) {
1079 minister_effects_string += ", ";
1080 } else {
1081 first = false;
1082 }
1083 if (modifier > 0) {
1084 minister_effects_string += "+";
1085 }
1086 minister_effects_string += std::to_string((long long) modifier) + "% Troop Cost";
1087 }
1088 }
1089
1090 return minister_effects_string;
1091 }
1092
GetBestDisplayTitle()1093 std::string CGrandStrategyHero::GetBestDisplayTitle()
1094 {
1095 std::string best_title = this->Type->Name;
1096 int best_title_type = MaxCharacterTitles;
1097 /*
1098 for (size_t i = 0; i < this->Titles.size(); ++i) {
1099 if (this->Titles[i].second != this->GetFaction()) {
1100 continue;
1101 }
1102 if (this->Titles[i].first < best_title_type) {
1103 best_title = this->GetFaction()->GetCharacterTitle(this->Titles[i].first, this->Gender);
1104 best_title_type = this->Titles[i].first;
1105 }
1106 }
1107 for (size_t i = 0; i < this->ProvinceTitles.size(); ++i) {
1108 if (this->ProvinceTitles[i].first < best_title_type) {
1109 best_title = this->GetFaction()->GetCharacterTitle(this->ProvinceTitles[i].first, this->Gender);
1110 best_title_type = this->ProvinceTitles[i].first;
1111 }
1112 }
1113 */
1114 return best_title;
1115 }
1116
GetFaction()1117 CGrandStrategyFaction *CGrandStrategyHero::GetFaction()
1118 {
1119 if (this->Province != nullptr) {
1120 return this->Province->Owner;
1121 } else {
1122 return this->ProvinceOfOrigin->Owner;
1123 }
1124
1125 return nullptr;
1126 }
1127
~CGrandStrategyEvent()1128 CGrandStrategyEvent::~CGrandStrategyEvent()
1129 {
1130 delete Conditions;
1131
1132 for (size_t i = 0; i < this->OptionConditions.size(); ++i) {
1133 delete this->OptionConditions[i];
1134 }
1135
1136 for (size_t i = 0; i < this->OptionEffects.size(); ++i) {
1137 delete this->OptionEffects[i];
1138 }
1139 }
1140
Trigger(CGrandStrategyFaction * faction)1141 void CGrandStrategyEvent::Trigger(CGrandStrategyFaction *faction)
1142 {
1143 // fprintf(stderr, "Triggering event \"%s\" for faction %s.\n", this->Name.c_str(), PlayerRaces.Factions[faction->Faction]->Name.c_str());
1144
1145 CclCommand("EventFaction = GetFactionFromName(\"" + PlayerRaces.Factions[faction->Faction]->Ident + "\");");
1146 CclCommand("GrandStrategyEvent(EventFaction, \"" + this->Name + "\");");
1147 CclCommand("EventFaction = nil;");
1148 CclCommand("EventProvince = nil;");
1149 CclCommand("SecondEventProvince = nil;");
1150
1151 if (!this->Persistent) {
1152 GrandStrategyGame.AvailableEvents.erase(std::remove(GrandStrategyGame.AvailableEvents.begin(), GrandStrategyGame.AvailableEvents.end(), this), GrandStrategyGame.AvailableEvents.end());
1153 }
1154 }
1155
CanTrigger(CGrandStrategyFaction * faction)1156 bool CGrandStrategyEvent::CanTrigger(CGrandStrategyFaction *faction)
1157 {
1158 // fprintf(stderr, "Checking for triggers for event \"%s\" for faction %s.\n", this->Name.c_str(), PlayerRaces.Factions[faction->Faction]->Name.c_str());
1159
1160 if (this->MinYear && GrandStrategyYear < this->MinYear) {
1161 return false;
1162 }
1163
1164 if (this->MaxYear && GrandStrategyYear > this->MaxYear) {
1165 return false;
1166 }
1167
1168 if (this->Conditions) {
1169 this->Conditions->pushPreamble();
1170 this->Conditions->run(1);
1171 if (this->Conditions->popBoolean() == false) {
1172 return false;
1173 }
1174 }
1175
1176 return true;
1177 }
1178
1179 /**
1180 ** Get the ID of a province
1181 */
GetProvinceId(std::string province_name)1182 int GetProvinceId(std::string province_name)
1183 {
1184 if (!province_name.empty()) {
1185 for (size_t i = 0; i < GrandStrategyGame.Provinces.size(); ++i) {
1186 if (GrandStrategyGame.Provinces[i]->Name == province_name) {
1187 return i;
1188 }
1189 }
1190 }
1191
1192 return -1;
1193 }
1194
SetProvinceOwner(std::string province_name,std::string civilization_name,std::string faction_name)1195 void SetProvinceOwner(std::string province_name, std::string civilization_name, std::string faction_name)
1196 {
1197 int province_id = GetProvinceId(province_name);
1198 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1199 int faction_id = PlayerRaces.GetFactionIndexByName(faction_name);
1200
1201 if (!civilization || province_id == -1 || !GrandStrategyGame.Provinces[province_id]) {
1202 return;
1203 }
1204
1205 GrandStrategyGame.Provinces[province_id]->SetOwner(civilization->ID, faction_id);
1206 }
1207
SetProvinceSettlementBuilding(std::string province_name,std::string settlement_building_ident,bool has_settlement_building)1208 void SetProvinceSettlementBuilding(std::string province_name, std::string settlement_building_ident, bool has_settlement_building)
1209 {
1210 int province_id = GetProvinceId(province_name);
1211 int settlement_building = UnitTypeIdByIdent(settlement_building_ident);
1212
1213 if (province_id != -1 && GrandStrategyGame.Provinces[province_id] && settlement_building != -1) {
1214 GrandStrategyGame.Provinces[province_id]->SetSettlementBuilding(settlement_building, has_settlement_building);
1215 }
1216 }
1217
SetProvinceUnitQuantity(std::string province_name,std::string unit_type_ident,int quantity)1218 void SetProvinceUnitQuantity(std::string province_name, std::string unit_type_ident, int quantity)
1219 {
1220 int province_id = GetProvinceId(province_name);
1221 int unit_type = UnitTypeIdByIdent(unit_type_ident);
1222
1223 if (province_id != -1 && GrandStrategyGame.Provinces[province_id] && unit_type != -1) {
1224 GrandStrategyGame.Provinces[province_id]->SetUnitQuantity(unit_type, quantity);
1225 }
1226 }
1227
ChangeProvinceUnitQuantity(std::string province_name,std::string unit_type_ident,int quantity)1228 void ChangeProvinceUnitQuantity(std::string province_name, std::string unit_type_ident, int quantity)
1229 {
1230 int province_id = GetProvinceId(province_name);
1231 int unit_type = UnitTypeIdByIdent(unit_type_ident);
1232
1233 if (province_id != -1 && GrandStrategyGame.Provinces[province_id] && unit_type != -1) {
1234 GrandStrategyGame.Provinces[province_id]->ChangeUnitQuantity(unit_type, quantity);
1235 }
1236 }
1237
SetProvinceHero(std::string province_name,std::string hero_full_name,int value)1238 void SetProvinceHero(std::string province_name, std::string hero_full_name, int value)
1239 {
1240 int province_id = GetProvinceId(province_name);
1241
1242 if (province_id != -1 && GrandStrategyGame.Provinces[province_id]) {
1243 GrandStrategyGame.Provinces[province_id]->SetHero(hero_full_name, value);
1244 }
1245 }
1246
SetProvinceFood(std::string province_name,int quantity)1247 void SetProvinceFood(std::string province_name, int quantity)
1248 {
1249 int province_id = GetProvinceId(province_name);
1250
1251 if (province_id != -1 && GrandStrategyGame.Provinces[province_id]) {
1252 GrandStrategyGame.Provinces[province_id]->PopulationGrowthProgress = std::max(0, quantity);
1253 }
1254 }
1255
ChangeProvinceFood(std::string province_name,int quantity)1256 void ChangeProvinceFood(std::string province_name, int quantity)
1257 {
1258 int province_id = GetProvinceId(province_name);
1259
1260 if (province_id != -1 && GrandStrategyGame.Provinces[province_id]) {
1261 GrandStrategyGame.Provinces[province_id]->PopulationGrowthProgress += quantity;
1262 GrandStrategyGame.Provinces[province_id]->PopulationGrowthProgress = std::max(0, GrandStrategyGame.Provinces[province_id]->PopulationGrowthProgress);
1263 }
1264 }
1265
AddProvinceClaim(std::string province_name,std::string civilization_name,std::string faction_name)1266 void AddProvinceClaim(std::string province_name, std::string civilization_name, std::string faction_name)
1267 {
1268 int province_id = GetProvinceId(province_name);
1269
1270 if (province_id != -1 && GrandStrategyGame.Provinces[province_id]) {
1271 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1272 if (civilization) {
1273 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1274 if (faction != -1) {
1275 GrandStrategyGame.Provinces[province_id]->AddFactionClaim(civilization->ID, faction);
1276 } else {
1277 fprintf(stderr, "Can't find %s faction (%s) to add claim to province %s.\n", faction_name.c_str(), civilization_name.c_str(), province_name.c_str());
1278 }
1279 } else {
1280 fprintf(stderr, "Can't find %s civilization to add the claim of its %s faction claim to province %s.\n", civilization_name.c_str(), faction_name.c_str(), province_name.c_str());
1281 }
1282 } else {
1283 fprintf(stderr, "Can't find %s province to add %s faction (%s) claim to.\n", province_name.c_str(), faction_name.c_str(), civilization_name.c_str());
1284 }
1285 }
1286
RemoveProvinceClaim(std::string province_name,std::string civilization_name,std::string faction_name)1287 void RemoveProvinceClaim(std::string province_name, std::string civilization_name, std::string faction_name)
1288 {
1289 int province_id = GetProvinceId(province_name);
1290
1291 if (province_id != -1 && GrandStrategyGame.Provinces[province_id]) {
1292 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1293 if (civilization) {
1294 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1295 if (faction != -1) {
1296 GrandStrategyGame.Provinces[province_id]->RemoveFactionClaim(civilization->ID, faction);
1297 }
1298 }
1299 }
1300 }
1301
InitializeGrandStrategyGame(bool show_loading)1302 void InitializeGrandStrategyGame(bool show_loading)
1303 {
1304 //initialize literary works
1305 for (size_t i = 0; i < AllUpgrades.size(); ++i) {
1306 if (AllUpgrades[i]->Work == -1 || AllUpgrades[i]->UniqueOnly) { // literary works that can only appear in unique items wouldn't be publishable
1307 continue;
1308 }
1309
1310 GrandStrategyGame.UnpublishedWorks.push_back(AllUpgrades[i]);
1311 }
1312 }
1313
FinalizeGrandStrategyInitialization()1314 void FinalizeGrandStrategyInitialization()
1315 {
1316 //initialize literary works
1317 int works_size = GrandStrategyGame.UnpublishedWorks.size();
1318 for (int i = (works_size - 1); i >= 0; --i) {
1319 if (GrandStrategyGame.UnpublishedWorks[i]->Year != 0 && GrandStrategyYear >= GrandStrategyGame.UnpublishedWorks[i]->Year) { //if the game is starting after the publication date of this literary work, remove it from the work list
1320 GrandStrategyGame.UnpublishedWorks.erase(std::remove(GrandStrategyGame.UnpublishedWorks.begin(), GrandStrategyGame.UnpublishedWorks.end(), GrandStrategyGame.UnpublishedWorks[i]), GrandStrategyGame.UnpublishedWorks.end());
1321 }
1322 }
1323
1324 for (size_t i = 0; i < GrandStrategyGame.Provinces.size(); ++i) {
1325 CGrandStrategyProvince *province = GrandStrategyGame.Provinces[i];
1326 CProvince *base_province = GetProvince(province->Name);
1327
1328 // add historical population from regions to provinces here, for a lack of a better place (all province's region belongings need to be defined before this takes place, so this can't happen during the province definitions)
1329 for (size_t j = 0; j < base_province->Regions.size(); ++j) {
1330 for (std::map<int, int>::iterator iterator = base_province->Regions[j]->HistoricalPopulation.begin(); iterator != base_province->Regions[j]->HistoricalPopulation.end(); ++iterator) {
1331 if (base_province->HistoricalPopulation.find(iterator->first) == base_province->HistoricalPopulation.end()) { // if the province doesn't have historical population information for a given year but the region does, then use the region's population quantity divided by the number of provinces the region has
1332 base_province->HistoricalPopulation[iterator->first] = iterator->second / base_province->Regions[j]->Provinces.size();
1333 }
1334 }
1335 }
1336
1337 for (std::map<int, int>::reverse_iterator iterator = base_province->HistoricalPopulation.rbegin(); iterator != base_province->HistoricalPopulation.rend(); ++iterator) {
1338 if (GrandStrategyYear >= iterator->first) {
1339 province->SetPopulation(iterator->second);
1340 break;
1341 }
1342 }
1343
1344 for (std::map<CUpgrade *, std::map<int, bool>>::iterator iterator = base_province->HistoricalModifiers.begin(); iterator != base_province->HistoricalModifiers.end(); ++iterator) {
1345 for (std::map<int, bool>::reverse_iterator second_iterator = iterator->second.rbegin(); second_iterator != iterator->second.rend(); ++second_iterator) {
1346 if (GrandStrategyYear >= second_iterator->first) {
1347 province->SetModifier(iterator->first, second_iterator->second);
1348 break;
1349 }
1350 }
1351 }
1352 }
1353 }
1354
SetGrandStrategyWorld(std::string world)1355 void SetGrandStrategyWorld(std::string world)
1356 {
1357 GrandStrategyWorld = world;
1358 }
1359
DoGrandStrategyTurn()1360 void DoGrandStrategyTurn()
1361 {
1362 GrandStrategyGame.DoTurn();
1363 }
1364
ProvinceBordersProvince(std::string province_name,std::string second_province_name)1365 bool ProvinceBordersProvince(std::string province_name, std::string second_province_name)
1366 {
1367 int province = GetProvinceId(province_name);
1368 int second_province = GetProvinceId(second_province_name);
1369
1370 return GrandStrategyGame.Provinces[province]->BordersProvince(GrandStrategyGame.Provinces[second_province]);
1371 }
1372
ProvinceBordersFaction(std::string province_name,std::string faction_civilization_name,std::string faction_name)1373 bool ProvinceBordersFaction(std::string province_name, std::string faction_civilization_name, std::string faction_name)
1374 {
1375 int province = GetProvinceId(province_name);
1376 CCivilization *civilization = CCivilization::GetCivilization(faction_civilization_name);
1377 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1378
1379 if (!civilization || faction == -1) {
1380 return false;
1381 }
1382
1383 return GrandStrategyGame.Provinces[province]->BordersFaction(civilization->ID, faction);
1384 }
1385
ProvinceHasBuildingClass(std::string province_name,std::string building_class)1386 bool ProvinceHasBuildingClass(std::string province_name, std::string building_class)
1387 {
1388 int province_id = GetProvinceId(province_name);
1389
1390 return GrandStrategyGame.Provinces[province_id]->HasBuildingClass(building_class);
1391 }
1392
GetProvinceCivilization(std::string province_name)1393 std::string GetProvinceCivilization(std::string province_name)
1394 {
1395 int province_id = GetProvinceId(province_name);
1396
1397 if (GrandStrategyGame.Provinces[province_id]->Civilization != -1) {
1398 return PlayerRaces.Name[GrandStrategyGame.Provinces[province_id]->Civilization];
1399 } else {
1400 return "";
1401 }
1402 }
1403
GetProvinceSettlementBuilding(std::string province_name,std::string building_ident)1404 bool GetProvinceSettlementBuilding(std::string province_name, std::string building_ident)
1405 {
1406 int province_id = GetProvinceId(province_name);
1407 int building_id = UnitTypeIdByIdent(building_ident);
1408
1409 return GrandStrategyGame.Provinces[province_id]->SettlementBuildings[building_id];
1410 }
1411
GetProvinceUnitQuantity(std::string province_name,std::string unit_type_ident)1412 int GetProvinceUnitQuantity(std::string province_name, std::string unit_type_ident)
1413 {
1414 int province_id = GetProvinceId(province_name);
1415 int unit_type = UnitTypeIdByIdent(unit_type_ident);
1416
1417 return GrandStrategyGame.Provinces[province_id]->Units[unit_type];
1418 }
1419
GetProvinceHero(std::string province_name,std::string hero_full_name)1420 int GetProvinceHero(std::string province_name, std::string hero_full_name)
1421 {
1422 int province_id = GetProvinceId(province_name);
1423
1424 if (province_id == -1) {
1425 fprintf(stderr, "Can't find %s province.\n", province_name.c_str());
1426 return 0;
1427 }
1428
1429 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
1430 if (hero) {
1431 if (hero->Province != nullptr && hero->Province->ID == province_id) {
1432 return hero->State;
1433 }
1434 } else {
1435 fprintf(stderr, "Hero \"%s\" doesn't exist.\n", hero_full_name.c_str());
1436 }
1437
1438 return 0;
1439 }
1440
GetProvinceMilitaryScore(std::string province_name,bool attacker,bool count_defenders)1441 int GetProvinceMilitaryScore(std::string province_name, bool attacker, bool count_defenders)
1442 {
1443 int province_id = GetProvinceId(province_name);
1444
1445 int military_score = 0;
1446 if (province_id != -1) {
1447 if (attacker) {
1448 military_score = GrandStrategyGame.Provinces[province_id]->AttackingMilitaryScore;
1449 } else if (count_defenders) {
1450 military_score = GrandStrategyGame.Provinces[province_id]->MilitaryScore;
1451 } else {
1452 military_score = GrandStrategyGame.Provinces[province_id]->OffensiveMilitaryScore;
1453 }
1454 }
1455
1456 return std::max(1, military_score); // military score must be at least one, since it is a divider in some instances, and we don't want to divide by 0
1457 }
1458
GetProvinceOwner(std::string province_name)1459 std::string GetProvinceOwner(std::string province_name)
1460 {
1461 int province_id = GetProvinceId(province_name);
1462
1463 if (province_id == -1 || GrandStrategyGame.Provinces[province_id]->Owner == nullptr) {
1464 return "";
1465 }
1466
1467 return PlayerRaces.Factions[GrandStrategyGame.Provinces[province_id]->Owner->Faction]->Ident;
1468 }
1469
SetFactionGovernmentType(std::string civilization_name,std::string faction_name,std::string government_type_name)1470 void SetFactionGovernmentType(std::string civilization_name, std::string faction_name, std::string government_type_name)
1471 {
1472 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1473
1474 int government_type_id = GetGovernmentTypeIdByName(government_type_name);
1475
1476 if (government_type_id == -1) {
1477 return;
1478 }
1479
1480 if (civilization) {
1481 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1482 if (faction != -1) {
1483 GrandStrategyGame.Factions[civilization->ID][faction]->GovernmentType = government_type_id;
1484 }
1485 }
1486 }
1487
SetFactionDiplomacyStateProposal(std::string civilization_name,std::string faction_name,std::string second_civilization_name,std::string second_faction_name,std::string diplomacy_state_name)1488 void SetFactionDiplomacyStateProposal(std::string civilization_name, std::string faction_name, std::string second_civilization_name, std::string second_faction_name, std::string diplomacy_state_name)
1489 {
1490 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1491 CCivilization *second_civilization = CCivilization::GetCivilization(second_civilization_name);
1492
1493 int diplomacy_state_id = GetDiplomacyStateIdByName(diplomacy_state_name);
1494
1495 if (civilization && second_civilization) {
1496 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1497 int second_faction = PlayerRaces.GetFactionIndexByName(second_faction_name);
1498 if (faction != -1 && second_faction != -1) {
1499 GrandStrategyGame.Factions[civilization->ID][faction]->DiplomacyStateProposals[GrandStrategyGame.Factions[second_civilization->ID][second_faction]] = diplomacy_state_id;
1500 }
1501 }
1502 }
1503
GetFactionDiplomacyStateProposal(std::string civilization_name,std::string faction_name,std::string second_civilization_name,std::string second_faction_name)1504 std::string GetFactionDiplomacyStateProposal(std::string civilization_name, std::string faction_name, std::string second_civilization_name, std::string second_faction_name)
1505 {
1506 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1507 CCivilization *second_civilization = CCivilization::GetCivilization(second_civilization_name);
1508
1509 if (civilization && second_civilization) {
1510 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1511 int second_faction = PlayerRaces.GetFactionIndexByName(second_faction_name);
1512 if (faction != -1 && second_faction != -1) {
1513 return GetDiplomacyStateNameById(GrandStrategyGame.Factions[civilization->ID][faction]->GetDiplomacyStateProposal(GrandStrategyGame.Factions[second_civilization->ID][second_faction]));
1514 }
1515 }
1516
1517 return "";
1518 }
1519
SetFactionTier(std::string civilization_name,std::string faction_name,std::string faction_tier_name)1520 void SetFactionTier(std::string civilization_name, std::string faction_name, std::string faction_tier_name)
1521 {
1522 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1523
1524 int faction_tier_id = GetFactionTierIdByName(faction_tier_name);
1525
1526 if (faction_tier_id == -1) {
1527 return;
1528 }
1529
1530 if (civilization) {
1531 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1532 if (faction != -1) {
1533 GrandStrategyGame.Factions[civilization->ID][faction]->FactionTier = faction_tier_id;
1534 }
1535 }
1536 }
1537
GetFactionTier(std::string civilization_name,std::string faction_name)1538 std::string GetFactionTier(std::string civilization_name, std::string faction_name)
1539 {
1540 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1541
1542 if (civilization) {
1543 int faction = PlayerRaces.GetFactionIndexByName(faction_name);
1544 if (faction != -1) {
1545 return GetFactionTierNameById(GrandStrategyGame.Factions[civilization->ID][faction]->FactionTier);
1546 }
1547 }
1548
1549 return "";
1550 }
1551
IsGrandStrategyUnit(const CUnitType & type)1552 bool IsGrandStrategyUnit(const CUnitType &type)
1553 {
1554 if (!type.BoolFlag[BUILDING_INDEX].value && type.DefaultStat.Variables[DEMAND_INDEX].Value > 0 && type.Class != -1 && UnitTypeClasses[type.Class] != "caravan") {
1555 return true;
1556 }
1557 return false;
1558 }
1559
IsMilitaryUnit(const CUnitType & type)1560 bool IsMilitaryUnit(const CUnitType &type)
1561 {
1562 if (IsGrandStrategyUnit(type) && type.Class != -1 && UnitTypeClasses[type.Class] != "worker") {
1563 return true;
1564 }
1565 return false;
1566 }
1567
SetFactionMinister(std::string civilization_name,std::string faction_name,std::string title_name,std::string hero_full_name)1568 void SetFactionMinister(std::string civilization_name, std::string faction_name, std::string title_name, std::string hero_full_name)
1569 {
1570 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1571 int faction = -1;
1572 if (civilization) {
1573 faction = PlayerRaces.GetFactionIndexByName(faction_name);
1574 }
1575 int title = GetCharacterTitleIdByName(title_name);
1576
1577 if (faction == -1 || title == -1) {
1578 return;
1579 }
1580
1581 GrandStrategyGame.Factions[civilization->ID][faction]->SetMinister(title, TransliterateText(hero_full_name));
1582 }
1583
GetFactionMinister(std::string civilization_name,std::string faction_name,std::string title_name)1584 std::string GetFactionMinister(std::string civilization_name, std::string faction_name, std::string title_name)
1585 {
1586 CCivilization *civilization = CCivilization::GetCivilization(civilization_name);
1587 int faction = -1;
1588 if (civilization) {
1589 faction = PlayerRaces.GetFactionIndexByName(faction_name);
1590 }
1591 int title = GetCharacterTitleIdByName(title_name);
1592
1593 if (faction == -1 || title == -1) {
1594 return "";
1595 }
1596
1597 if (GrandStrategyGame.Factions[civilization->ID][faction]->Ministers[title] != nullptr) {
1598 return GrandStrategyGame.Factions[civilization->ID][faction]->Ministers[title]->GetFullName();
1599 } else {
1600 return "";
1601 }
1602 }
1603
KillGrandStrategyHero(std::string hero_full_name)1604 void KillGrandStrategyHero(std::string hero_full_name)
1605 {
1606 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
1607 if (hero) {
1608 hero->Die();
1609 } else {
1610 fprintf(stderr, "Hero \"%s\" doesn't exist.\n", hero_full_name.c_str());
1611 }
1612 }
1613
GrandStrategyHeroExisted(std::string hero_full_name)1614 void GrandStrategyHeroExisted(std::string hero_full_name)
1615 {
1616 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
1617 if (hero) {
1618 hero->Existed = true;
1619 } else {
1620 fprintf(stderr, "Hero \"%s\" doesn't exist.\n", hero_full_name.c_str());
1621 }
1622 }
1623
GrandStrategyHeroIsAlive(std::string hero_full_name)1624 bool GrandStrategyHeroIsAlive(std::string hero_full_name)
1625 {
1626 CGrandStrategyHero *hero = GrandStrategyGame.GetHero(hero_full_name);
1627 if (hero) {
1628 return hero->IsAlive();
1629 } else {
1630 fprintf(stderr, "Hero \"%s\" doesn't exist.\n", hero_full_name.c_str());
1631 }
1632 return false;
1633 }
1634
GrandStrategyWorkCreated(std::string work_ident)1635 void GrandStrategyWorkCreated(std::string work_ident)
1636 {
1637 CUpgrade *work = CUpgrade::Get(work_ident);
1638 if (work) {
1639 GrandStrategyGame.UnpublishedWorks.erase(std::remove(GrandStrategyGame.UnpublishedWorks.begin(), GrandStrategyGame.UnpublishedWorks.end(), work), GrandStrategyGame.UnpublishedWorks.end()); // remove work from the vector, so that it doesn't get created again
1640 } else {
1641 fprintf(stderr, "Work \"%s\" doesn't exist.\n", work_ident.c_str());
1642 }
1643 }
1644
MakeGrandStrategyEventAvailable(std::string event_name)1645 void MakeGrandStrategyEventAvailable(std::string event_name)
1646 {
1647 CGrandStrategyEvent *event = GetGrandStrategyEvent(event_name);
1648 if (event) {
1649 GrandStrategyGame.AvailableEvents.push_back(event);
1650 } else {
1651 fprintf(stderr, "Grand strategy event \"%s\" doesn't exist.\n", event_name.c_str());
1652 }
1653 }
1654
GetGrandStrategyEventTriggered(std::string event_name)1655 bool GetGrandStrategyEventTriggered(std::string event_name)
1656 {
1657 CGrandStrategyEvent *event = GetGrandStrategyEvent(event_name);
1658 if (event) {
1659 return std::find(GrandStrategyGame.AvailableEvents.begin(), GrandStrategyGame.AvailableEvents.end(), event) == GrandStrategyGame.AvailableEvents.end();
1660 } else {
1661 fprintf(stderr, "Grand strategy event \"%s\" doesn't exist.\n", event_name.c_str());
1662 return false;
1663 }
1664 }
1665
CleanGrandStrategyEvents()1666 void CleanGrandStrategyEvents()
1667 {
1668 for (size_t i = 0; i < GrandStrategyEvents.size(); ++i) {
1669 delete GrandStrategyEvents[i];
1670 }
1671 GrandStrategyEvents.clear();
1672 GrandStrategyEventStringToPointer.clear();
1673 }
1674
GetGrandStrategyEvent(std::string event_name)1675 CGrandStrategyEvent *GetGrandStrategyEvent(std::string event_name)
1676 {
1677 if (GrandStrategyEventStringToPointer.find(event_name) != GrandStrategyEventStringToPointer.end()) {
1678 return GrandStrategyEventStringToPointer[event_name];
1679 }
1680
1681 return nullptr;
1682 }
1683
GetDiplomacyStateNameById(int diplomacy_state)1684 std::string GetDiplomacyStateNameById(int diplomacy_state)
1685 {
1686 if (diplomacy_state == DiplomacyStatePeace) {
1687 return "peace";
1688 } else if (diplomacy_state == DiplomacyStateWar) {
1689 return "war";
1690 } else if (diplomacy_state == DiplomacyStateAlliance) {
1691 return "alliance";
1692 } else if (diplomacy_state == DiplomacyStateVassal) {
1693 return "vassal";
1694 } else if (diplomacy_state == DiplomacyStateOverlord) {
1695 return "overlord";
1696 } else if (diplomacy_state == -1) {
1697 return "";
1698 }
1699
1700 return "";
1701 }
1702
GetDiplomacyStateIdByName(std::string diplomacy_state)1703 int GetDiplomacyStateIdByName(std::string diplomacy_state)
1704 {
1705 if (diplomacy_state == "peace") {
1706 return DiplomacyStatePeace;
1707 } else if (diplomacy_state == "war") {
1708 return DiplomacyStateWar;
1709 } else if (diplomacy_state == "alliance") {
1710 return DiplomacyStateAlliance;
1711 } else if (diplomacy_state == "vassal") {
1712 return DiplomacyStateVassal;
1713 } else if (diplomacy_state == "overlord") {
1714 return DiplomacyStateOverlord;
1715 }
1716
1717 return -1;
1718 }
1719
GetFactionTierNameById(int faction_tier)1720 std::string GetFactionTierNameById(int faction_tier)
1721 {
1722 if (faction_tier == FactionTierNoFactionTier) {
1723 return "no-faction-tier";
1724 } else if (faction_tier == FactionTierBarony) {
1725 return "barony";
1726 } else if (faction_tier == FactionTierCounty) {
1727 return "county";
1728 } else if (faction_tier == FactionTierDuchy) {
1729 return "duchy";
1730 } else if (faction_tier == FactionTierGrandDuchy) {
1731 return "grand-duchy";
1732 } else if (faction_tier == FactionTierKingdom) {
1733 return "kingdom";
1734 } else if (faction_tier == FactionTierEmpire) {
1735 return "empire";
1736 }
1737
1738 return "";
1739 }
1740
GetFactionTierIdByName(std::string faction_tier)1741 int GetFactionTierIdByName(std::string faction_tier)
1742 {
1743 if (faction_tier == "no-faction-tier") {
1744 return FactionTierNoFactionTier;
1745 } else if (faction_tier == "barony") {
1746 return FactionTierBarony;
1747 } else if (faction_tier == "county") {
1748 return FactionTierCounty;
1749 } else if (faction_tier == "duchy") {
1750 return FactionTierDuchy;
1751 } else if (faction_tier == "grand-duchy") {
1752 return FactionTierGrandDuchy;
1753 } else if (faction_tier == "kingdom") {
1754 return FactionTierKingdom;
1755 } else if (faction_tier == "empire") {
1756 return FactionTierEmpire;
1757 }
1758
1759 return -1;
1760 }
1761