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