1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2006 Andrea Paternesi
4 // Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015, 2017,
5 // 2020 Ben Asselstine
6 // Copyright (C) 2007, 2008 Ole Laursen
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // 02110-1301, USA.
22
23 #include <config.h>
24 #include <iostream>
25 #include <iomanip>
26 #include <fstream>
27 #include <errno.h>
28 #include <sigc++/functors/mem_fun.h>
29 #include <string.h>
30
31 #include "ucompose.hpp"
32 #include "GameScenario.h"
33 #include "MapGenerator.h"
34 #include "playerlist.h"
35 #include "FogMap.h"
36 #include "citylist.h"
37 #include "ruinlist.h"
38 #include "SightMap.h"
39 #include "rewardlist.h"
40 #include "templelist.h"
41 #include "bridgelist.h"
42 #include "portlist.h"
43 #include "roadlist.h"
44 #include "stonelist.h"
45 #include "signpostlist.h"
46 #include "city.h"
47 #include "ruin.h"
48 #include "File.h"
49 #include "armysetlist.h"
50 #include "tilesetlist.h"
51 #include "citysetlist.h"
52 #include "shieldsetlist.h"
53 #include "stacklist.h"
54 #include "stack.h"
55 #include "GameMap.h"
56 #include "player.h"
57 #include "Configuration.h"
58 #include "real_player.h"
59 #include "ai_dummy.h"
60 #include "AI_Diplomacy.h"
61 #include "AI_Analysis.h"
62 #include "ai_fast.h"
63 #include "counter.h"
64 #include "army.h"
65 #include "QuestsManager.h"
66 #include "Itemlist.h"
67 #include "vectoredunitlist.h"
68 #include "history.h"
69 #include "xmlhelper.h"
70 #include "tarhelper.h"
71 #include "stacktile.h"
72 #include "file-compat.h"
73 #include "Item.h"
74 #include "rnd.h"
75 #include "game-actionlist.h"
76 #include "ScenarioMedia.h"
77 #include "herotemplates.h"
78 #include "heroproto.h"
79 #include "keeper.h"
80
81 Glib::ustring GameScenario::d_tag = "scenario";
82 Glib::ustring GameScenario::d_top_tag = PACKAGE;
83
84 sigc::signal<void> GameScenario::load_tick;
85 sigc::signal<void> GameScenario::load_finish;
86
87 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
88 #define debug(x)
89
GameScenario(Glib::ustring name,Glib::ustring comment,GameScenario::PlayMode playmode)90 GameScenario::GameScenario(Glib::ustring name,Glib::ustring comment,
91 GameScenario::PlayMode playmode)
92 :TarFile(name, MAP_EXT), d_name(name),d_comment(comment), d_copyright(""),
93 d_license(""), d_playmode(playmode), inhibit_autosave_removal(false),
94 loaded_game_filename("")
95 {
96 Armysetlist::getInstance();
97 Tilesetlist::getInstance();
98 Shieldsetlist::getInstance();
99
100 if (fl_counter == 0)
101 fl_counter = new FL_Counter();
102
103 setNewRandomId();
104 }
105
106 //savegame has an absolute path
GameScenario(Glib::ustring savegame,bool & broken)107 GameScenario::GameScenario(Glib::ustring savegame, bool& broken)
108 :TarFile (File::get_basename (savegame, false),
109 File::get_extension (savegame)),
110 d_playmode(GameScenario::HOTSEAT), inhibit_autosave_removal(false),
111 loaded_game_filename("")
112 {
113 Tar_Helper t(savegame, std::ios::in, broken);
114 load_tick.emit ();
115 if (broken == false)
116 {
117 loaded_game_filename = savegame;
118 loadArmysets(&t);
119 load_tick.emit ();
120 loadTilesets(&t);
121 load_tick.emit ();
122 loadCitysets(&t);
123 load_tick.emit ();
124 loadShieldsets(&t);
125 load_tick.emit ();
126 std::list<Glib::ustring> ext;
127 ext.push_back(MAP_EXT);
128 ext.push_back(SAVE_EXT);
129 Glib::ustring filename = t.getFirstFile(ext, broken);
130 XML_Helper helper(filename, std::ios::in);
131 broken = loadWithHelper(helper, File::get_dirname(savegame));
132 load_tick.emit ();
133 ScenarioMedia::getInstance()->instantiateImages(t, broken);
134 load_tick.emit ();
135 ScenarioMedia::getInstance()->copySounds(t, broken);
136 load_tick.emit ();
137 helper.close();
138 File::erase(filename);
139 t.Close();
140 if (broken)
141 cleanup();
142 load_finish.emit();
143 }
144 else
145 {
146 t.Close();
147 cleanup();
148 }
149 }
150
loadArmysets(Tar_Helper * t)151 bool GameScenario::loadArmysets(Tar_Helper *t)
152 {
153 bool broken = false;
154 std::list<Glib::ustring> armysets = t->getFilenames(Armyset::file_extension);
155 for (std::list<Glib::ustring>::iterator it = armysets.begin();
156 it != armysets.end(); it++)
157 {
158 guint32 id = Armysetlist::getInstance()->import(t, *it, broken);
159 if (!broken)
160 Armysetlist::getInstance()->get(id)->instantiateImages(true, broken);
161 }
162 return !broken;
163 }
164
loadTilesets(Tar_Helper * t)165 bool GameScenario::loadTilesets(Tar_Helper *t)
166 {
167 bool broken = false;
168 std::list<Glib::ustring> tilesets = t->getFilenames(Tileset::file_extension);
169 for (auto it: tilesets)
170 {
171 guint32 id = Tilesetlist::getInstance()->import(t, it, broken);
172 if (!broken)
173 Tilesetlist::getInstance()->get(id)->instantiateImages(true, broken);
174 }
175 return !broken;
176 }
177
loadCitysets(Tar_Helper * t)178 bool GameScenario::loadCitysets(Tar_Helper *t)
179 {
180 bool broken = false;
181 std::list<Glib::ustring> citysets = t->getFilenames(Cityset::file_extension);
182 for (auto it: citysets)
183 {
184 guint32 id = Citysetlist::getInstance()->import(t, it, broken);
185 if (!broken)
186 Citysetlist::getInstance()->get(id)->instantiateImages(true, broken);
187 }
188 return !broken;
189 }
190
loadShieldsets(Tar_Helper * t)191 bool GameScenario::loadShieldsets(Tar_Helper *t)
192 {
193 bool broken = false;
194 std::list<Glib::ustring> shieldsets =
195 t->getFilenames(Shieldset::file_extension);
196 for (auto it: shieldsets)
197 {
198 guint32 id = Shieldsetlist::getInstance()->import(t, it, broken);
199 if (!broken)
200 Shieldsetlist::getInstance()->get(id)->instantiateImages(true, broken);
201 }
202 return !broken;
203 }
204
quickStartEvenlyDivided()205 void GameScenario::quickStartEvenlyDivided()
206 {
207 Playerlist *plist = Playerlist::getInstance();
208 Vector <int> pos;
209 // no neutral cities
210 // divvy up the neutral cities among other non-neutral players
211 int cities_left = Citylist::getInstance()->size() - plist->size() + 1;
212 unsigned int citycount[MAX_PLAYERS];
213 memset (citycount, 0, sizeof (citycount));
214 Playerlist::iterator pit = plist->begin();
215
216 while (cities_left > 0)
217 {
218 if (*pit != plist->getNeutral())
219 {
220 citycount[(*pit)->getId()]++;
221 cities_left--;
222 }
223
224 pit++;
225 if (pit == plist->end())
226 pit = plist->begin();
227 }
228
229 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
230 {
231 for (unsigned int j = 0; j < citycount[i]; j++)
232 {
233 Player *p = plist->getPlayer(i);
234 if (!p)
235 continue;
236 if (p == plist->getNeutral())
237 continue;
238 pos = Citylist::getInstance()->getCapitalCity(p)->getPos();
239 City *c = Citylist::getInstance()->getNearestNeutralCity(pos);
240 if (c)
241 {
242 //does the city contain any stacks yet?
243 //change their allegience to us.
244 for (unsigned int x = 0 ; x < c->getSize(); x++)
245 {
246 for (unsigned int y = 0; y < c->getSize(); y++)
247 {
248 StackTile *stile =
249 GameMap::getStacks(c->getPos() + Vector<int>(x,y));
250 std::vector<Stack*> stks = stile->getStacks();
251 for (std::vector<Stack *>::iterator k = stks.begin();
252 k != stks.end(); k++)
253 Stacklist::changeOwnership(*k, p);
254 }
255 }
256
257 //now give the city to us.
258 p->conquerCity(c, NULL);
259 }
260 }
261 }
262 }
263
quickStartAIHeadStart()264 void GameScenario::quickStartAIHeadStart()
265 {
266 float head_start_factor = 0.05;
267 //each AI player gets this percent of total cities.
268
269 Playerlist *plist = Playerlist::getInstance();
270 Vector <int> pos;
271
272 unsigned int citycount = Citylist::getInstance()->size() * head_start_factor;
273 if (citycount == 0)
274 citycount = 1;
275 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
276 {
277 for (unsigned int j = 0; j < citycount; j++)
278 {
279 Player *p = plist->getPlayer(i);
280 if (!p)
281 continue;
282 if (p == plist->getNeutral())
283 continue;
284 if (p->getType() == Player::HUMAN)
285 continue;
286 pos = Citylist::getInstance()->getCapitalCity(p)->getPos();
287 City *c = Citylist::getInstance()->getNearestNeutralCity(pos);
288 if (c)
289 {
290 //does the city contain any stacks yet?
291 //change their allegience to us.
292 for (unsigned int x = 0 ; x < c->getSize(); x++)
293 {
294 for (unsigned int y = 0; y < c->getSize(); y++)
295 {
296 StackTile *stile =
297 GameMap::getStacks(c->getPos() + Vector<int>(x,y));
298 std::vector<Stack*> stks = stile->getStacks();
299 for (std::vector<Stack *>::iterator k = stks.begin();
300 k != stks.end(); k++)
301 Stacklist::changeOwnership(*k, p);
302 }
303 }
304
305 //now give the city to us.
306 p->conquerCity(c, NULL);
307 }
308 }
309 }
310 }
311
setupFog(bool hidden_map)312 bool GameScenario::setupFog(bool hidden_map)
313 {
314 for (auto it: *Playerlist::getInstance())
315 {
316 if (hidden_map)
317 it->getFogMap()->fill(FogMap::CLOSED);
318 else
319 it->getFogMap()->fill(FogMap::OPEN);
320 }
321 return true;
322 }
323
setupStacks(bool hidden_map)324 bool GameScenario::setupStacks(bool hidden_map)
325 {
326 if (!hidden_map)
327 return true;
328 for (Playerlist::iterator it = Playerlist::getInstance()->begin();
329 it != Playerlist::getInstance()->end(); it++)
330 {
331 if ((*it) == Playerlist::getInstance()->getNeutral())
332 continue;
333 for (Stacklist::iterator sit = (*it)->getStacklist()->begin();
334 sit != (*it)->getStacklist()->end(); sit++)
335 (*sit)->deFog();
336 }
337 return true;
338 }
339
setupMapRewards()340 bool GameScenario::setupMapRewards()
341 {
342 debug("GameScenario::setupMapRewards")
343 //okay, let's make some maps
344 //split the terrain into a 3x3 grid
345 Vector<int> step = Vector<int>(GameMap::getWidth() / 3,
346 GameMap::getHeight() / 3);
347 Reward_Map *reward = new Reward_Map(Vector<int>(step.x * 0, 0),
348 _("Northwestern map"), step.x, step.y);
349 Rewardlist::getInstance()->push_back(reward);
350 reward = new Reward_Map(Vector<int>(step.x * 1, 0),
351 _("Northern map"), step.x, step.y);
352 Rewardlist::getInstance()->push_back(reward);
353 reward = new Reward_Map(Vector<int>(step.x * 2, 0),
354 _("Northeastern map"), step.x, step.y);
355 Rewardlist::getInstance()->push_back(reward);
356 reward = new Reward_Map(Vector<int>(step.x * 0, step.y * 1),
357 _("Western map"), step.x, step.y);
358 Rewardlist::getInstance()->push_back(reward);
359 reward = new Reward_Map(Vector<int>(step.x * 1, step.y * 1),
360 _("Central map"), step.x, step.y);
361 Rewardlist::getInstance()->push_back(reward);
362 reward = new Reward_Map(Vector<int>(step.x * 2, step.y * 1),
363 _("Eastern map"), step.x, step.y);
364 Rewardlist::getInstance()->push_back(reward);
365 reward = new Reward_Map(Vector<int>(step.x * 0, step.y * 2),
366 _("Southwestern map"), step.x, step.y);
367 Rewardlist::getInstance()->push_back(reward);
368 reward = new Reward_Map(Vector<int>(step.x * 1, step.y * 2),
369 _("Southern map"), step.x, step.y);
370 Rewardlist::getInstance()->push_back(reward);
371 reward = new Reward_Map(Vector<int>(step.x * 2, step.y * 2),
372 _("Southeastern map"), step.x, step.y);
373 Rewardlist::getInstance()->push_back(reward);
374 return true;
375 }
376
setupRuinOccupants()377 bool GameScenario::setupRuinOccupants()
378 {
379 debug("GameScenario::setupRuinOccupants")
380 for (Ruinlist::iterator it = Ruinlist::getInstance()->begin();
381 it != Ruinlist::getInstance()->end(); it++)
382 {
383 if ((*it)->getOccupant () == NULL)
384 {
385 const ArmyProto *a = Keeper::randomRuinDefender ();
386 Keeper *keeper = new Keeper (a, (*it)->getPos ());
387 (*it)->setOccupant (keeper);
388 }
389 }
390 return true;
391 }
392
setupRuinRewards(int difficulty)393 bool GameScenario::setupRuinRewards(int difficulty)
394 {
395 debug("GameScenario::setupRuinRewards")
396
397 //the more difficult the scenario is, the more likely we are to have
398 //hidden ruins
399 guint32 chance = 0;
400 if (difficulty <= 70)
401 chance = 1;
402 else if (difficulty <= 80)
403 chance = 2;
404 else if (difficulty <= 90)
405 chance = 3;
406 else
407 chance = 4;
408
409 guint32 num_hidden = 0;
410 for (auto i : *Ruinlist::getInstance ())
411 if (i->isHidden ())
412 num_hidden++;
413 guint32 num_not_hidden = Ruinlist::getInstance ()->size () - num_hidden;
414 // first, mark some ruins as hidden for rewards
415 // only til we have as many hidden ruins as we have non-hidden ruins
416 for (Ruinlist::iterator it = Ruinlist::getInstance()->begin();
417 it != Ruinlist::getInstance()->end(); it++)
418 {
419 if ((*it)->isHidden () == false && Rnd::rand() % 100 < chance &&
420 (*it)->hasSage() == false && (*it)->getReward() == NULL &&
421 num_hidden < num_not_hidden)
422 {
423 (*it)->setHidden (true);
424 num_hidden++;
425 num_not_hidden--;
426 }
427 }
428
429 // now we populate the rewards
430 for (Ruinlist::iterator it = Ruinlist::getInstance()->begin();
431 it != Ruinlist::getInstance()->end(); it++)
432 {
433 if ((*it)->isHidden() == true)
434 {
435 //add it to the reward list
436 Reward_Ruin *newReward = new Reward_Ruin((*it)); //make a reward
437 newReward->setName(newReward->getDescription());
438 Rewardlist::getInstance()->push_back(newReward); //add it
439 }
440 else
441 {
442 if ((*it)->hasSage() == false && (*it)->getReward() == NULL)
443 (*it)->populateWithRandomReward();
444 }
445 }
446 return true;
447 }
448
setupItemRewards()449 bool GameScenario::setupItemRewards()
450 {
451 guint32 count = 0;
452 debug("GameScenario::setupItemRewards")
453 for (auto iter : *Itemlist::getInstance())
454 {
455 const ItemProto* templateItem = iter.second;
456 Item *newItem = new Item(*templateItem, count); //instantiate it
457 Reward_Item *newReward = new Reward_Item(newItem); //make a reward
458 delete newItem;
459 newReward->setName(newReward->getDescription());
460 Rewardlist::getInstance()->push_back(newReward); //add it
461 count++;
462 }
463
464 return true;
465 }
466
setupRewards(bool hidden_map,int difficulty)467 bool GameScenario::setupRewards(bool hidden_map, int difficulty)
468 {
469 if (Rewardlist::getInstance()->size() != 0)
470 return true;
471 setupItemRewards();
472 setupRuinOccupants ();
473 setupRuinRewards(difficulty);
474 if (hidden_map)
475 setupMapRewards();
476 return true;
477 }
478
setupCities(GameParameters::QuickStartPolicy quick_start,GameParameters::BuildProductionMode build)479 bool GameScenario::setupCities(GameParameters::QuickStartPolicy quick_start,
480 GameParameters::BuildProductionMode build)
481 {
482 debug("GameScenario::setupCities")
483
484 for (Playerlist::iterator it = Playerlist::getInstance()->begin();
485 it != Playerlist::getInstance()->end(); it++)
486 {
487 if ((*it) == Playerlist::getInstance()->getNeutral())
488 continue;
489 City *city = Citylist::getInstance()->getCapitalCity(*it);
490 if (city)
491 {
492 city->deFog(city->getOwner());
493 (*it)->conquerCity(city, NULL);
494 }
495 }
496
497 if (quick_start == GameParameters::EVENLY_DIVIDED)
498 quickStartEvenlyDivided();
499 else if (quick_start == GameParameters::AI_HEAD_START)
500 quickStartAIHeadStart();
501
502 for (Citylist::iterator it = Citylist::getInstance()->begin();
503 it != Citylist::getInstance()->end(); it++)
504 {
505 if ((*it)->isBurnt())
506 continue;
507 if ((*it)->getOwner() == Playerlist::getInstance()->getNeutral())
508 {
509 switch (GameScenario::s_neutral_cities)
510 {
511 case GameParameters::AVERAGE:
512 (*it)->produceWeakestProductionBase();
513 break;
514 case GameParameters::STRONG:
515 (*it)->produceStrongestProductionBase();
516 break;
517 case GameParameters::ACTIVE:
518 if (Rnd::rand () % 100 > 20)
519 (*it)->produceStrongestProductionBase();
520 else
521 (*it)->produceWeakestProductionBase();
522 break;
523 case GameParameters::DEFENSIVE:
524 (*it)->produceWeakestQuickestArmyInArmyset();
525 (*it)->produceWeakestQuickestArmyInArmyset();
526 break;
527 }
528 (*it)->setActiveProductionSlot(-1);
529 }
530 else
531 {
532 if ((*it)->isCapital())
533 (*it)->produceStrongestProductionBase();
534 else
535 (*it)->produceWeakestProductionBase();
536
537 (*it)->setActiveProductionSlot(0);
538 }
539 }
540
541 //set up build production
542 std::list<City*> cities;
543 for (Citylist::iterator it = Citylist::getInstance()->begin();
544 it != Citylist::getInstance()->end(); it++)
545 {
546 if ((*it)->isBurnt())
547 continue;
548 if ((*it)->isCapital())
549 continue;
550 if ((*it)->getBuildProduction() == true)
551 continue;
552 cities.push_back(*it);
553 }
554 switch (build)
555 {
556 case GameParameters::BUILD_PRODUCTION_ALWAYS:
557 for (Citylist::iterator it = Citylist::getInstance()->begin();
558 it != Citylist::getInstance()->end(); it++)
559 {
560 if ((*it)->isBurnt())
561 continue;
562 (*it)->setBuildProduction(true);
563 }
564 break;
565 case GameParameters::BUILD_PRODUCTION_USUALLY:
566 {
567 //usually means 66% have their build production turned on.
568 int target = (double)Citylist::getInstance()->size() * 0.33;
569 int to_turn_off = cities.size() - target;
570 if (to_turn_off > 0)
571 {
572 for (Citylist::iterator it = Citylist::getInstance()->begin();
573 it != Citylist::getInstance()->end(); it++)
574 {
575 if ((*it)->isBurnt())
576 continue;
577 if ((*it)->isCapital())
578 continue;
579 if ((*it)->getBuildProduction() == false)
580 continue;
581 (*it)->setBuildProduction (false);
582 to_turn_off--;
583 if (to_turn_off == 0)
584 break;
585 }
586 }
587 }
588 break;
589 case GameParameters::BUILD_PRODUCTION_SELDOM:
590 {
591 //seldom means 90% have their build production turned off.
592 int target = (double)Citylist::getInstance()->size() * 0.90;
593 int to_turn_off = target - cities.size ();
594 if (to_turn_off > 0)
595 {
596 for (Citylist::iterator it = Citylist::getInstance()->begin();
597 it != Citylist::getInstance()->end(); it++)
598 {
599 if ((*it)->isBurnt())
600 continue;
601 if ((*it)->isCapital())
602 continue;
603 if ((*it)->getBuildProduction() == false)
604 continue;
605 (*it)->setBuildProduction (false);
606 to_turn_off--;
607 if (to_turn_off == 0)
608 break;
609 }
610 }
611 }
612 break;
613 case GameParameters::BUILD_PRODUCTION_NEVER:
614 for (Citylist::iterator it = Citylist::getInstance()->begin();
615 it != Citylist::getInstance()->end(); it++)
616 {
617 if ((*it)->isBurnt())
618 continue;
619 (*it)->setBuildProduction(false);
620 }
621 break;
622 }
623
624 return true;
625 }
626
setupDiplomacy(bool diplomacy)627 void GameScenario::setupDiplomacy(bool diplomacy)
628 {
629 for (auto pit: *Playerlist::getInstance())
630 {
631 if (Playerlist::getInstance()->getNeutral() == pit)
632 continue;
633 for (auto it: *Playerlist::getInstance())
634 {
635 if (Playerlist::getInstance()->getNeutral() == it)
636 continue;
637 if (pit == it)
638 continue;
639 if (diplomacy == false)
640 {
641 pit->proposeDiplomacy(Player::PROPOSE_WAR, it);
642 pit->declareDiplomacy(Player::AT_WAR, it, false);
643 }
644 else
645 {
646 pit->proposeDiplomacy(Player::NO_PROPOSAL, it);
647 pit->declareDiplomacy(Player::AT_PEACE, it, false);
648 }
649 }
650 }
651 if (diplomacy)
652 Playerlist::getInstance()->calculateDiplomaticRankings();
653 }
654
loadWithHelper(XML_Helper & helper,Glib::ustring dir)655 bool GameScenario::loadWithHelper(XML_Helper& helper, Glib::ustring dir)
656 {
657 setDirectory(dir);
658 Armysetlist::getInstance();
659 Tilesetlist::getInstance();
660 Shieldsetlist::getInstance();
661
662 bool broken = false;
663
664 helper.registerTag(d_top_tag, sigc::mem_fun(this, &GameScenario::load));
665 helper.registerTag(d_tag, sigc::mem_fun(this, &GameScenario::load));
666 helper.registerTag(Itemlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
667 helper.registerTag(Playerlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
668 helper.registerTag(GameMap::d_tag, sigc::mem_fun(this, &GameScenario::load));
669 helper.registerTag(Citylist::d_tag, sigc::mem_fun(this, &GameScenario::load));
670 helper.registerTag(Templelist::d_tag, sigc::mem_fun(this, &GameScenario::load));
671 helper.registerTag(Ruinlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
672 helper.registerTag(Rewardlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
673 helper.registerTag(Signpostlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
674 helper.registerTag(Roadlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
675 helper.registerTag(Stonelist::d_tag, sigc::mem_fun(this, &GameScenario::load));
676 helper.registerTag(FL_Counter::d_tag, sigc::mem_fun(this, &GameScenario::load));
677 helper.registerTag(QuestsManager::d_tag, sigc::mem_fun(this, &GameScenario::load));
678 helper.registerTag(Bridgelist::d_tag, sigc::mem_fun(this, &GameScenario::load));
679 helper.registerTag(Portlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
680 helper.registerTag(VectoredUnitlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
681 helper.registerTag(GameActionlist::d_tag, sigc::mem_fun(this, &GameScenario::load));
682 helper.registerTag(ScenarioMedia::d_tag, sigc::mem_fun(this, &GameScenario::load));
683 helper.registerTag(HeroTemplates::d_tag, sigc::mem_fun(this, &GameScenario::load));
684
685 if (!helper.parseXML())
686 broken = true;
687
688 if (!broken)
689 {
690 GameMap::getInstance()->updateStackPositions();
691 GameMap::getInstance()->calculateBlockedAvenues();
692 }
693
694 return broken;
695 }
696
697
~GameScenario()698 GameScenario::~GameScenario()
699 {
700 cleanup();
701 if (Configuration::s_autosave_policy == 1 &&
702 inhibit_autosave_removal == false)
703 {
704 Glib::ustring filename = File::getSaveFile("autosave" + SAVE_EXT);
705 File::erase(filename);
706 }
707 clean_tmp_dir();
708 }
709
getName() const710 Glib::ustring GameScenario::getName() const
711 {
712 return d_name;
713 }
714
getComment() const715 Glib::ustring GameScenario::getComment() const
716 {
717 return d_comment;
718 }
719
dump(Glib::ustring filename,Glib::ustring extension) const720 bool GameScenario::dump(Glib::ustring filename, Glib::ustring extension) const
721 {
722 bool retval = true;
723 Glib::ustring goodfilename = File::add_ext_if_necessary(filename, extension);
724 debug("saving game to " + goodfilename);
725
726 Glib::ustring tmpfile = File::get_tmp_file();
727 XML_Helper helper(tmpfile, std::ios::out);
728 retval &= saveWithHelper(helper);
729 helper.close();
730
731 if (retval == false)
732 return false;
733
734 bool broken = false;
735 Tar_Helper t(goodfilename, std::ios::out, broken);
736 if (broken == true)
737 return false;
738
739 t.saveFile(tmpfile, File::get_basename(goodfilename, true));
740 File::erase(tmpfile);
741
742 Cityset *cs = GameMap::getCityset();
743 t.saveFile(cs->getConfigurationFile());
744
745 Shieldset *ss = GameMap::getShieldset();
746 t.saveFile(ss->getConfigurationFile());
747
748 Tileset *ts = GameMap::getTileset();
749 t.saveFile(ts->getConfigurationFile());
750
751 std::list<guint32> armysets;
752 for (auto it: *Playerlist::getInstance())
753 {
754 guint32 armyset = it->getArmyset();
755 if (std::find(armysets.begin(), armysets.end(), armyset) == armysets.end())
756 armysets.push_back(armyset);
757 }
758
759 for (auto it: armysets)
760 {
761 Armyset *as = Armysetlist::getInstance()->get(it);
762 t.saveFile(as->getConfigurationFile());
763 }
764
765 return true;
766 }
767
saveGame(Glib::ustring filename,Glib::ustring extension) const768 bool GameScenario::saveGame(Glib::ustring filename, Glib::ustring extension) const
769 {
770 bool retval = true;
771 Glib::ustring goodfilename = File::add_ext_if_necessary(filename, extension);
772 debug("saving game to " + goodfilename);
773
774 Glib::ustring tmpfile = File::get_tmp_file();
775 XML_Helper helper(tmpfile, std::ios::out);
776 retval &= saveWithHelper(helper);
777 helper.close();
778
779 if (retval == false)
780 return false;
781
782 Glib::ustring tmptar = File::get_tmp_file() + ".tar";
783 retval = saveTar(tmpfile, tmptar, goodfilename, true);
784
785 return retval;
786 }
787
saveWithHelper(XML_Helper & helper) const788 bool GameScenario::saveWithHelper(XML_Helper &helper) const
789 {
790 bool retval = true;
791
792 //start writing
793 retval &= helper.begin(LORDSAWAR_SAVEGAME_VERSION);
794 retval &= helper.openTag(d_top_tag);
795
796 //if retval is still true it propably doesn't change throughout the rest
797 //now save the single object's data
798 retval &= fl_counter->save(&helper);
799 retval &= Itemlist::getInstance()->save(&helper);
800 retval &= Playerlist::getInstance()->save(&helper);
801 retval &= GameMap::getInstance()->save(&helper);
802 retval &= Citylist::getInstance()->save(&helper);
803 retval &= Templelist::getInstance()->save(&helper);
804 retval &= Ruinlist::getInstance()->save(&helper);
805 retval &= Rewardlist::getInstance()->save(&helper);
806 retval &= Signpostlist::getInstance()->save(&helper);
807 retval &= Roadlist::getInstance()->save(&helper);
808 retval &= Stonelist::getInstance()->save(&helper);
809 retval &= Portlist::getInstance()->save(&helper);
810 retval &= Bridgelist::getInstance()->save(&helper);
811 retval &= QuestsManager::getInstance()->save(&helper);
812 retval &= VectoredUnitlist::getInstance()->save(&helper);
813 retval &= GameActionlist::getInstance()->save(&helper);
814 if (HeroTemplates::getInstance()->isDefault () == false)
815 retval &= HeroTemplates::getInstance()->save(&helper);
816
817 //save the private GameScenario data last due to dependencies
818 retval &= helper.openTag(GameScenario::d_tag);
819 retval &= helper.saveData("id", d_id);
820 retval &= helper.saveData("name", d_name);
821 retval &= helper.saveData("comment", d_comment);
822 retval &= helper.saveData("copyright", d_copyright);
823 retval &= helper.saveData("license", d_license);
824 retval &= helper.saveData("turn", s_round);
825 retval &= helper.saveData("view_enemies", s_see_opponents_stacks);
826 retval &= helper.saveData("view_production", s_see_opponents_production);
827 Glib::ustring quest_policy_str = Configuration::questPolicyToString(GameParameters::QuestPolicy(s_play_with_quests));
828 retval &= helper.saveData("quests", quest_policy_str);
829 retval &= helper.saveData("hidden_map", s_hidden_map);
830 retval &= helper.saveData("diplomacy", s_diplomacy);
831 retval &= helper.saveData("cusp_of_war", s_cusp_of_war);
832 Glib::ustring neutral_cities_str = Configuration::neutralCitiesToString(GameParameters::NeutralCities(s_neutral_cities));
833 retval &= helper.saveData("neutral_cities", neutral_cities_str);
834 Glib::ustring razing_cities_str = Configuration::razingCitiesToString(GameParameters::RazingCities(s_razing_cities));
835 retval &= helper.saveData("razing_cities", razing_cities_str);
836 Glib::ustring vectoring_mode_str = Configuration::vectoringModeToString(GameParameters::VectoringMode(s_vectoring_mode));
837 retval &= helper.saveData("vectoring_mode", vectoring_mode_str);
838 Glib::ustring build_prod_mode_str = Configuration::buildProductionModeToString(GameParameters::BuildProductionMode(s_build_production_mode));
839 retval &= helper.saveData("build_production_mode", build_prod_mode_str);
840 Glib::ustring sacking_mode_str = Configuration::sackingModeToString(GameParameters::SackingMode(s_sacking_mode));
841 retval &= helper.saveData("sacking_mode", sacking_mode_str);
842 retval &= helper.saveData("intense_combat", s_intense_combat);
843 retval &= helper.saveData("military_advisor", s_military_advisor);
844 retval &= helper.saveData("random_turns", s_random_turns);
845 retval &= helper.saveData("surrender_already_offered",
846 s_surrender_already_offered);
847 Glib::ustring playmode_str = playModeToString(GameScenario::PlayMode(d_playmode));
848 retval &= helper.saveData("playmode", playmode_str);
849
850 retval &= helper.closeTag();
851
852 retval &= ScenarioMedia::getInstance()->save(&helper);
853
854 retval &= helper.closeTag();
855
856 return retval;
857 }
858
load(Glib::ustring tag,XML_Helper * helper)859 bool GameScenario::load(Glib::ustring tag, XML_Helper* helper)
860 {
861 if (tag == d_top_tag)
862 {
863 if (helper->getVersion() != LORDSAWAR_SAVEGAME_VERSION)
864 {
865 std::cerr << String::ucompose(_("saved game file has wrong version. Expecting %1 but got %2."), LORDSAWAR_SAVEGAME_VERSION, helper->getVersion()) << std::endl;
866 return false;
867 }
868 return true;
869 }
870 if (tag == GameScenario::d_tag)
871 {
872 debug("loading scenario")
873
874 helper->getData(d_id, "id");
875 helper->getData(d_name, "name");
876 helper->getData(d_comment, "comment");
877 helper->getData(d_copyright, "copyright");
878 helper->getData(d_license, "license");
879 helper->getData(s_round, "turn");
880 helper->getData(s_see_opponents_stacks, "view_enemies");
881 helper->getData(s_see_opponents_production, "view_production");
882 Glib::ustring quest_policy_str;
883 helper->getData(quest_policy_str, "quests");
884 s_play_with_quests = Configuration::questPolicyFromString(quest_policy_str);
885 helper->getData(s_hidden_map, "hidden_map");
886 helper->getData(s_diplomacy, "diplomacy");
887 helper->getData(s_cusp_of_war, "cusp_of_war");
888 Glib::ustring neutral_cities_str;
889 helper->getData(neutral_cities_str, "neutral_cities");
890 s_neutral_cities = Configuration::neutralCitiesFromString(neutral_cities_str);
891 Glib::ustring razing_cities_str;
892 helper->getData(razing_cities_str, "razing_cities");
893 s_razing_cities = Configuration::razingCitiesFromString(razing_cities_str);
894 Glib::ustring vectoring_mode_str;
895 helper->getData(vectoring_mode_str, "vectoring_mode");
896 s_vectoring_mode = Configuration::vectoringModeFromString(vectoring_mode_str);
897 Glib::ustring build_prod_mode_str;
898 helper->getData(build_prod_mode_str, "build_production_mode");
899 s_build_production_mode = Configuration::buildProductionModeFromString(build_prod_mode_str);
900 Glib::ustring sacking_mode_str;
901 helper->getData(sacking_mode_str, "sacking_mode");
902 s_sacking_mode = Configuration::sackingModeFromString(sacking_mode_str);
903 helper->getData(s_intense_combat, "intense_combat");
904 helper->getData(s_military_advisor, "military_advisor");
905 helper->getData(s_random_turns, "random_turns");
906 helper->getData(s_surrender_already_offered,
907 "surrender_already_offered");
908 Glib::ustring playmode_str;
909 helper->getData(playmode_str, "playmode");
910 d_playmode = GameScenario::playModeFromString(playmode_str);
911
912 return true;
913 }
914
915 if (tag == FL_Counter::d_tag)
916 {
917 debug("loading counter")
918 fl_counter = new FL_Counter(helper);
919 return true;
920 }
921
922 if (tag == Itemlist::d_tag)
923 {
924 debug("loading items");
925 Itemlist::getInstance(helper);
926 return true;
927 }
928
929 if (tag == Playerlist::d_tag)
930 {
931 debug("loading players");
932 Playerlist::getInstance(helper);
933 return true;
934 }
935
936 if (tag == GameMap::d_tag)
937 {
938 debug("loading map")
939 GameMap::getInstance(helper);
940 return true;
941 }
942
943 if (tag == Citylist::d_tag)
944 {
945 debug("loading cities")
946
947 Citylist::getInstance(helper);
948 return true;
949 }
950
951 if (tag == Templelist::d_tag)
952 {
953 debug("loading temples")
954 Templelist::getInstance(helper);
955 return true;
956 }
957
958 if (tag == Ruinlist::d_tag)
959 {
960 debug("loading ruins")
961 Ruinlist::getInstance(helper);
962 return true;
963 }
964
965 if (tag == Rewardlist::d_tag)
966 {
967 debug("loading rewards")
968 Rewardlist::getInstance(helper);
969 return true;
970 }
971
972 if (tag == Signpostlist::d_tag)
973 {
974 debug("loading signposts")
975 Signpostlist::getInstance(helper);
976 return true;
977 }
978
979 if (tag == Roadlist::d_tag)
980 {
981 debug("loading roads")
982 Roadlist::getInstance(helper);
983 return true;
984 }
985
986 if (tag == Stonelist::d_tag)
987 {
988 debug("loading stones")
989 Stonelist::getInstance(helper);
990 return true;
991 }
992
993 if (tag == QuestsManager::d_tag)
994 {
995 debug("loading quests")
996 QuestsManager::getInstance(helper);
997 return true;
998 }
999
1000 if (tag == VectoredUnitlist::d_tag)
1001 {
1002 debug("loading vectored units")
1003 VectoredUnitlist::getInstance(helper);
1004 return true;
1005 }
1006
1007 if (tag == Portlist::d_tag)
1008 {
1009 debug("loading ports")
1010 Portlist::getInstance(helper);
1011 return true;
1012 }
1013
1014 if (tag == Bridgelist::d_tag)
1015 {
1016 debug("loading bridges")
1017 Bridgelist::getInstance(helper);
1018 return true;
1019 }
1020
1021 if (tag == GameActionlist::d_tag)
1022 {
1023 GameActionlist::getInstance(helper);
1024 return true;
1025 }
1026
1027 if (tag == ScenarioMedia::d_tag)
1028 {
1029 ScenarioMedia::getInstance(helper);
1030 return true;
1031 }
1032
1033 if (tag == HeroTemplates::d_tag)
1034 {
1035 HeroTemplates::getInstance(helper);
1036 return true;
1037 }
1038 return false;
1039 }
1040
autoSave()1041 bool GameScenario::autoSave()
1042 {
1043 Glib::ustring filename = "";
1044 if (Configuration::s_autosave_policy == 2)
1045 filename = String::ucompose("autosave-%1%2", Glib::ustring::format(std::setfill(L'0'), std::setw(3), s_round - 1), SAVE_EXT);
1046 else if (Configuration::s_autosave_policy == 1)
1047 filename = "autosave" + SAVE_EXT;
1048 else
1049 return true;
1050 // autosave to the file "autosave.sav".
1051 //
1052 // We first save to a temporary file, then rename it.
1053 // This avoids screwing up the autosave if something goes wrong
1054 // (and we have a savefile for debugging)
1055 //
1056 // We can be somewhat assured the rename works, because we are renaming
1057 // from ~/.cache/lordsawar/<file> to ~/.local/share/lordsawar/<file>
1058 //
1059 Glib::ustring tmpfile = File::get_tmp_file (SAVE_EXT);
1060 if (!saveGame(tmpfile))
1061 {
1062 std::cerr<< "Autosave failed, see " << tmpfile << std::endl;
1063 return false;
1064 }
1065 //erase the old autosave file if any, and then plop our new one in place.
1066 File::erase(File::getSaveFile(filename));
1067 if (File::rename(tmpfile, File::getSaveFile(filename)) == false)
1068 {
1069 char* err = strerror(errno);
1070 std::cerr << String::ucompose(_("Error! can't rename the temporary file `%1' to the autosave file `%2'. %3"), tmpfile, File::getSaveFile(filename), err) << std::endl;
1071 return false;
1072 }
1073 return true;
1074 }
1075
nextRound()1076 void GameScenario::nextRound()
1077 {
1078 s_round++;
1079 autoSave();
1080 }
1081
playModeToString(const GameScenario::PlayMode mode)1082 Glib::ustring GameScenario::playModeToString(const GameScenario::PlayMode mode)
1083 {
1084 switch (mode)
1085 {
1086 case GameScenario::HOTSEAT: return "GameScenario::HOTSEAT";
1087 case GameScenario::NETWORKED: return "GameScenario::NETWORKED";
1088 }
1089 return "GameScenario::HOTSEAT";
1090 }
1091
playModeFromString(const Glib::ustring str)1092 GameScenario::PlayMode GameScenario::playModeFromString(const Glib::ustring str)
1093 {
1094 if (str.size() > 0 && isdigit(str.c_str()[0]))
1095 return GameScenario::PlayMode(atoi(str.c_str()));
1096 if (str == "GameScenario::HOTSEAT") return GameScenario::HOTSEAT;
1097 else if (str == "GameScenario::NETWORKED")
1098 return GameScenario::NETWORKED;
1099 return GameScenario::HOTSEAT;
1100 }
1101
setNewRandomId()1102 void GameScenario::setNewRandomId()
1103 {
1104 d_id = generate_guid();
1105 }
1106
validate(std::list<Glib::ustring> & errors,std::list<Glib::ustring> & warnings)1107 bool GameScenario::validate(std::list<Glib::ustring> &errors, std::list<Glib::ustring> &warnings)
1108 {
1109 Glib::ustring s;
1110 guint32 num = Playerlist::getInstance()->countPlayersAlive();
1111 if (num < 2)
1112 errors.push_back(_("There must be at least 2 players in the scenario."));
1113
1114 num = Citylist::getInstance()->countCities();
1115 if (num < 2)
1116 errors.push_back(_("There must be at least 2 cities in the scenario."));
1117
1118 if (getName() == _("Untitled"))
1119 errors.push_back(_("The scenario does not have a name."));
1120
1121 for (auto it: *Playerlist::getInstance())
1122 {
1123 if (it == Playerlist::getInstance()->getNeutral())
1124 continue;
1125 if (it->isDead() == true)
1126 continue;
1127 if (Citylist::getInstance()->getCapitalCity(it) == NULL ||
1128 Citylist::getInstance()->getCapitalCity(it)->isBurnt() == true)
1129 {
1130 s = String::ucompose
1131 (_("The player called `%1' lacks a capital city."),
1132 it->getName().c_str());
1133 errors.push_back(s);
1134 break;
1135 }
1136 std::vector<HeroProto*> heroes =
1137 HeroTemplates::getInstance()->getHeroes (it->getId());
1138 guint32 num_heroes = heroes.size ();
1139 for (auto h : heroes)
1140 delete h;
1141 if (num_heroes == 0)
1142 {
1143 s = String::ucompose (_("The player called `%1' lacks a hero."),
1144 it->getName().c_str());
1145 errors.push_back(s);
1146 break;
1147 }
1148 }
1149
1150 guint32 count = 0;
1151 for (auto it: *Citylist::getInstance())
1152 {
1153 if (it->isUnnamed() == true)
1154 count++;
1155 }
1156 if (count > 0)
1157 {
1158 s = String::ucompose(ngettext("There is %1 unnamed city", "There are %1 unnamed cities", count), count);
1159 warnings.push_back(s);
1160 }
1161
1162 count = 0;
1163
1164 for (auto it: *Ruinlist::getInstance())
1165 {
1166 if (it->isUnnamed() == true)
1167 count++;
1168 }
1169 if (count > 0)
1170 {
1171 s = String::ucompose(ngettext("There is %1 unnamed ruin", "There are %1 unnamed ruins", count), count);
1172 warnings.push_back(s);
1173 }
1174
1175 for (auto it: *Ruinlist::getInstance())
1176 {
1177 if (it->getOccupant () && it->getOccupant ()->getName () == "" &&
1178 it->getOccupant()->getStack ())
1179 {
1180 s = String::ucompose("%1 has an unnamed keeper", it->getName ());
1181 errors.push_back(s);
1182 }
1183 }
1184
1185 count = 0;
1186 for (auto it: *Templelist::getInstance())
1187 {
1188 if (it->isUnnamed() == true)
1189 count++;
1190 }
1191 if (count > 0)
1192 {
1193 s = String::ucompose(ngettext("There is %1 unnamed temple", "There are %1 unnamed temples", count), count);
1194 warnings.push_back(s);
1195 }
1196
1197 count = 0;
1198 for (auto it: *Playerlist::getInstance()->getNeutral()->getStacklist())
1199 {
1200 if (Citylist::getInstance()->getObjectAt(it->getPos()) == NULL)
1201 count++;
1202 }
1203 if (count > 0)
1204 {
1205 s = String::ucompose(ngettext("There is %1 neutral stack not in a city", "There are %1 neutral stacks not in cities", count), count);
1206 warnings.push_back(s);
1207 }
1208
1209
1210 GameMap::getInstance()->calculateBlockedAvenues();
1211 if (GameMap::getInstance()->checkCityAccessibility() == false)
1212 errors.push_back(_("Not all cities are reachable by a non-flying unit."));
1213
1214 //any ports or bridges on land?
1215 if (GameMap::checkBuildingTerrain(Maptile::PORT, true))
1216 errors.push_back(_("One or more ports are on land."));
1217 if (GameMap::checkBuildingTerrain(Maptile::BRIDGE, true))
1218 errors.push_back(_("One or more bridges are on land."));
1219 //any cities, roads, temples, ruins, signs on water?
1220 if (GameMap::checkBuildingTerrain(Maptile::CITY, false))
1221 errors.push_back(_("One or more cities are on water."));
1222 if (GameMap::checkBuildingTerrain(Maptile::ROAD, false))
1223 errors.push_back(_("One or more roads are on water."));
1224 if (GameMap::checkBuildingTerrain(Maptile::RUIN, false))
1225 errors.push_back(_("One or more ruins are on water."));
1226 if (GameMap::checkBuildingTerrain(Maptile::TEMPLE, false))
1227 errors.push_back(_("One or more temples are on water."));
1228 if (GameMap::checkBuildingTerrain(Maptile::SIGNPOST, false))
1229 errors.push_back(_("One or more signs are on water."));
1230
1231 for (auto it: *Itemlist::getInstance())
1232 {
1233 ItemProto *i = it.second;
1234 if (i->getBonus (ItemProto::BANISH_WORMS) &&
1235 i->hasArmyTypeToKill () == false)
1236 errors.push_back(String::ucompose (_("%1 doesn't have an army type specified for Kill All Units Of Giant Worms"), i->getName ()));
1237
1238 if (i->getBonus (ItemProto::SUMMON_MONSTER) &&
1239 i->hasArmyTypeToSummon () == false)
1240 errors.push_back(String::ucompose (_("%1 doesn't have an army type specified for Summon Monster"), i->getName ()));
1241
1242 if (i->getBonus (ItemProto::RAISE_DEFENDERS) &&
1243 i->hasArmyTypeToRaise () == false)
1244 errors.push_back(String::ucompose (_("%1 doesn't have an army type specified for Raise Defenders In City"), i->getName ()));
1245 }
1246
1247 if (errors.size() == 0)
1248 return true;
1249 return false;
1250 }
1251
initialize(GameParameters g)1252 void GameScenario::initialize(GameParameters g)
1253 {
1254 Playerlist::getInstance()->clearAllActions();
1255 setupFog(g.hidden_map);
1256 setupCities(g.quick_start, g.build_production_mode);
1257 setupStacks(g.hidden_map);
1258 setupRewards(g.hidden_map, g.difficulty);
1259 setupDiplomacy(g.diplomacy);
1260 if (s_random_turns)
1261 Playerlist::getInstance()->randomizeOrder();
1262 nextRound();
1263 if (d_playmode == GameScenario::NETWORKED)
1264 {
1265 GameMap::getInstance()->clearStackPositions();
1266 Playerlist::getInstance()->turnHumansIntoNetworkPlayers();
1267 }
1268 else
1269 autoSave();
1270 GameMap::getInstance()->updateStackPositions();
1271
1272 if (d_name == "AutoGenerated")
1273 {
1274 if (GameMap::getInstance()->checkCityAccessibility() == false)
1275 exit (0);
1276 }
1277 }
1278
1279 //! Grabs the game option information out of a scenario file.
1280 class ParamLoader
1281 {
1282 public:
ParamLoader(Glib::ustring filename,bool & broken)1283 ParamLoader(Glib::ustring filename, bool &broken) {
1284 Tar_Helper t(filename, std::ios::in, broken);
1285 if (broken)
1286 return;
1287 std::list<Glib::ustring> ext;
1288 ext.push_back(MAP_EXT);
1289 ext.push_back(SAVE_EXT);
1290 Glib::ustring tmpfile = t.getFirstFile(ext, broken);
1291 XML_Helper helper(tmpfile, std::ios::in);
1292 helper.registerTag(GameMap::d_tag,
1293 sigc::mem_fun(this, &ParamLoader::loadParam));
1294 helper.registerTag(GameScenario::d_tag,
1295 sigc::mem_fun(this, &ParamLoader::loadParam));
1296 helper.registerTag(Playerlist::d_tag,
1297 sigc::mem_fun(this, &ParamLoader::loadParam));
1298 helper.registerTag(Player::d_tag,
1299 sigc::mem_fun(this, &ParamLoader::loadParam));
1300 bool retval = helper.parseXML();
1301 helper.close();
1302 File::erase(tmpfile);
1303 if (broken == false)
1304 broken = !retval;
1305 }
loadParam(Glib::ustring tag,XML_Helper * helper)1306 bool loadParam(Glib::ustring tag, XML_Helper* helper)
1307 {
1308 if (tag == Playerlist::d_tag)
1309 {
1310 helper->getData(d_neutral, "neutral");
1311 return true;
1312 }
1313 if (tag == Player::d_tag)
1314 {
1315 int type;
1316 int id;
1317 Glib::ustring name;
1318 GameParameters::Player p;
1319 helper->getData(id, "id");
1320 p.id = id;
1321 helper->getData(type, "type");
1322 switch (Player::Type(type))
1323 {
1324 case Player::HUMAN:
1325 p.type = GameParameters::Player::HUMAN;
1326 break;
1327 case Player::AI_FAST:
1328 p.type = GameParameters::Player::EASY;
1329 break;
1330 case Player::AI_DUMMY:
1331 p.type = GameParameters::Player::EASY;
1332 break;
1333 case Player::AI_SMART:
1334 p.type = GameParameters::Player::HARD;
1335 break;
1336 case Player::NETWORKED:
1337 p.type = GameParameters::Player::HUMAN;
1338 break;
1339 }
1340 helper->getData(name, "name");
1341 p.name = name;
1342 if (p.id != d_neutral) //is not neutral
1343 game_params.players.push_back(p);
1344 else
1345 {
1346 int armyset_id;
1347 helper->getData(armyset_id, "armyset");
1348 Armyset *armyset = Armysetlist::getInstance()->get(armyset_id);
1349 game_params.army_theme = armyset->getBaseName();
1350 }
1351
1352 return true;
1353 }
1354 if (tag == GameMap::d_tag)
1355 {
1356 helper->getData(game_params.shield_theme, "shieldset");
1357 helper->getData(game_params.tile_theme, "tileset");
1358 helper->getData(game_params.city_theme, "cityset");
1359 return true;
1360 }
1361 if (tag == GameScenario::d_tag)
1362 {
1363 helper->getData(game_params.see_opponents_stacks,
1364 "view_enemies");
1365 helper->getData(game_params.see_opponents_production,
1366 "view_production");
1367 Glib::ustring quest_policy_str;
1368 helper->getData(quest_policy_str, "quests");
1369 game_params.play_with_quests =
1370 Configuration::questPolicyFromString(quest_policy_str);
1371 helper->getData(game_params.hidden_map, "hidden_map");
1372 helper->getData(game_params.diplomacy, "diplomacy");
1373 helper->getData(game_params.cusp_of_war, "cusp_of_war");
1374 Glib::ustring neutral_cities_str;
1375 helper->getData(neutral_cities_str, "neutral_cities");
1376 game_params.neutral_cities =
1377 Configuration::neutralCitiesFromString(neutral_cities_str);
1378 Glib::ustring razing_cities_str;
1379 helper->getData(razing_cities_str, "razing_cities");
1380 game_params.razing_cities =
1381 Configuration::razingCitiesFromString(razing_cities_str);
1382 Glib::ustring vectoring_mode_str;
1383 helper->getData(vectoring_mode_str, "vectoring_mode");
1384 game_params.vectoring_mode =
1385 Configuration::vectoringModeFromString(vectoring_mode_str);
1386 helper->getData(game_params.intense_combat,
1387 "intense_combat");
1388 helper->getData(game_params.military_advisor,
1389 "military_advisor");
1390 helper->getData(game_params.random_turns, "random_turns");
1391 return true;
1392 }
1393 return false;
1394 };
1395 GameParameters game_params;
1396 guint32 d_neutral;
1397 };
1398
loadGameParameters(Glib::ustring filename,bool & broken)1399 GameParameters GameScenario::loadGameParameters(Glib::ustring filename, bool &broken)
1400 {
1401 ParamLoader loader(filename, broken);
1402
1403 return loader.game_params;
1404 }
1405
1406 //! Grab the type of game from a saved-game file. Either networked or hotseat.
1407 class PlayModeLoader
1408 {
1409 public:
PlayModeLoader(Glib::ustring filename,bool & broken)1410 PlayModeLoader(Glib::ustring filename, bool &broken) {
1411 play_mode = GameScenario::HOTSEAT;
1412 Tar_Helper t(filename, std::ios::in, broken);
1413 if (broken)
1414 return;
1415 Glib::ustring file = File::get_basename(filename, true);
1416 std::list<Glib::ustring> ext;
1417 ext.push_back(MAP_EXT);
1418 ext.push_back(SAVE_EXT);
1419 Glib::ustring tmpfile = t.getFirstFile(ext, broken);
1420 if (tmpfile == "")
1421 {
1422 broken = true;
1423 return;
1424 }
1425 XML_Helper helper(tmpfile, std::ios::in);
1426 helper.registerTag(GameScenario::d_tag,
1427 sigc::mem_fun(this, &PlayModeLoader::loadParam));
1428 bool retval = helper.parseXML();
1429 helper.close();
1430 File::erase(tmpfile);
1431 if (broken == false)
1432 broken = !retval;
1433 }
loadParam(Glib::ustring tag,XML_Helper * helper)1434 bool loadParam(Glib::ustring tag, XML_Helper* helper)
1435 {
1436 if (tag == GameScenario::d_tag)
1437 {
1438 Glib::ustring playmode_str;
1439 helper->getData(playmode_str, "playmode");
1440 play_mode = GameScenario::playModeFromString(playmode_str);
1441 return true;
1442 }
1443 return false;
1444 };
1445 GameScenario::PlayMode play_mode;
1446 };
1447
loadPlayMode(Glib::ustring filename,bool & broken)1448 GameScenario::PlayMode GameScenario::loadPlayMode(Glib::ustring filename, bool &broken)
1449 {
1450 PlayModeLoader loader(filename, broken);
1451 if (broken)
1452 return HOTSEAT;
1453 return loader.play_mode;
1454 }
1455
1456 //! Read in some basic information about a scenario from a scenario file.
1457 class DetailsLoader
1458 {
1459 public:
DetailsLoader(Glib::ustring filename,bool & broken)1460 DetailsLoader(Glib::ustring filename, bool &broken) {
1461 player_count = 0; city_count = 0; name = ""; comment = "";
1462 Tar_Helper tar(filename, std::ios::in, broken);
1463 if (broken)
1464 return;
1465 std::list<Glib::ustring> ext;
1466 ext.push_back(MAP_EXT);
1467 ext.push_back(SAVE_EXT);
1468 Glib::ustring tmpfile = tar.getFirstFile(ext, broken);
1469 XML_Helper helper(tmpfile, std::ios::in);
1470 helper.registerTag(GameScenario::d_tag,
1471 sigc::mem_fun(this, &DetailsLoader::loadDetails));
1472 helper.registerTag(Player::d_tag,
1473 sigc::mem_fun(this, &DetailsLoader::loadDetails));
1474 helper.registerTag(City::d_tag,
1475 sigc::mem_fun(this, &DetailsLoader::loadDetails));
1476 bool retval = helper.parseXML();
1477 helper.close();
1478 File::erase(tmpfile);
1479 if (!broken)
1480 broken = !retval;
1481 }
1482
loadDetails(Glib::ustring tag,XML_Helper * helper)1483 bool loadDetails(Glib::ustring tag, XML_Helper* helper)
1484 {
1485 if (tag == GameScenario::d_tag)
1486 {
1487 helper->getData(name, "name");
1488 helper->getData(comment, "comment");
1489 helper->getData(id, "id");
1490 return true;
1491 }
1492 if (tag == Player::d_tag)
1493 {
1494 player_count++;
1495 return true;
1496 }
1497 if (tag == City::d_tag)
1498 {
1499 city_count++;
1500 return true;
1501 }
1502 return false;
1503 };
1504 Tar_Helper *t;
1505 Glib::ustring name, comment;
1506 guint32 player_count, city_count;
1507 Glib::ustring id;
1508 };
1509
loadDetails(Glib::ustring filename,bool & broken,guint32 & player_count,guint32 & city_count,Glib::ustring & name,Glib::ustring & comment,Glib::ustring & id)1510 void GameScenario::loadDetails(Glib::ustring filename, bool &broken, guint32 &player_count, guint32 &city_count, Glib::ustring &name, Glib::ustring &comment, Glib::ustring &id)
1511 {
1512 DetailsLoader loader(filename, broken);
1513 if (broken == false)
1514 {
1515 player_count = loader.player_count;
1516 city_count = loader.city_count;
1517 name = loader.name;
1518 comment = loader.comment;
1519 id = loader.id;
1520 }
1521 return;
1522 }
1523
clean_tmp_dir() const1524 void GameScenario::clean_tmp_dir() const
1525 {
1526 if (loaded_game_filename != "")
1527 Tar_Helper::clean_tmp_dir(loaded_game_filename);
1528 }
1529
generate_guid()1530 Glib::ustring GameScenario::generate_guid()
1531 {
1532 char buf[40];
1533 //this is a very poor guid generator.
1534 snprintf (buf, sizeof (buf), "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", Rnd::rand(), Rnd::rand() % 4096, Rnd::rand() % 4096, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256, Rnd::rand() % 256);
1535
1536 return Glib::ustring(buf);
1537 }
1538
cleanup()1539 void GameScenario::cleanup()
1540 {
1541 Itemlist::deleteInstance();
1542 Playerlist::deleteInstance();
1543 Citylist::deleteInstance();
1544 Templelist::deleteInstance();
1545 Ruinlist::deleteInstance();
1546 Rewardlist::deleteInstance();
1547 Signpostlist::deleteInstance();
1548 Portlist::deleteInstance();
1549 Bridgelist::deleteInstance();
1550 Roadlist::deleteInstance();
1551 Stonelist::deleteInstance();
1552 QuestsManager::deleteInstance();
1553 VectoredUnitlist::deleteInstance();
1554 GameMap::deleteInstance();
1555 GameActionlist::deleteInstance();
1556 ScenarioMedia::deleteInstance();
1557 HeroTemplates::deleteInstance ();
1558 if (fl_counter)
1559 {
1560 delete fl_counter;
1561 fl_counter = 0;
1562 }
1563 GameScenarioOptions::s_round = 0;
1564 }
1565
upgrade(Glib::ustring filename,Glib::ustring old_version,Glib::ustring new_version)1566 bool GameScenario::upgrade(Glib::ustring filename, Glib::ustring old_version, Glib::ustring new_version)
1567 {
1568 return FileCompat::getInstance()->upgrade(filename, old_version, new_version,
1569 FileCompat::GAMESCENARIO,
1570 d_top_tag);
1571 }
1572
support_backward_compatibility()1573 void GameScenario::support_backward_compatibility()
1574 {
1575 FileCompat::getInstance()->support_type (FileCompat::GAMESCENARIO, MAP_EXT,
1576 d_top_tag, true);
1577 FileCompat::getInstance()->support_type (FileCompat::GAMESCENARIO, SAVE_EXT,
1578 d_top_tag, true);
1579 FileCompat::getInstance()->support_version
1580 (FileCompat::GAMESCENARIO, "0.2.1", "0.3.2",
1581 sigc::ptr_fun(&GameScenario::upgrade));
1582 FileCompat::getInstance()->support_version
1583 (FileCompat::GAMESCENARIO, "0.2.0", "0.2.1",
1584 sigc::ptr_fun(&GameScenario::upgrade));
1585 }
1586
1587