initial commit, lordsawar source, slightly modified
[lordsawar] / src / gui / history-report-dialog.cpp
1 //  Copyright (C) 2007, 2008, 2009 Ben Asselstine
2 //
3 //  This program is free software; you can redistribute it and/or modify
4 //  it under the terms of the GNU General Public License as published by
5 //  the Free Software Foundation; either version 3 of the License, or
6 //  (at your option) any later version.
7 //
8 //  This program is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //  GNU Library General Public License for more details.
12 //
13 //  You should have received a copy of the GNU General Public License
14 //  along with this program; if not, write to the Free Software
15 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
16 //  02110-1301, USA.
17
18 #include <config.h>
19
20 #include <gtkmm.h>
21 #include <sigc++/functors/mem_fun.h>
22
23 #include "history-report-dialog.h"
24
25 #include "glade-helpers.h"
26 #include "image-helpers.h"
27 #include "input-helpers.h"
28 #include "line-chart.h"
29 #include "report-dialog.h"
30 #include "ucompose.hpp"
31 #include "defs.h"
32 #include "File.h"
33 #include "GameMap.h"
34 #include "citylist.h"
35 #include "ruinlist.h"
36 #include "city.h"
37 #include "ruin.h"
38 #include "playerlist.h"
39 #include "history.h"
40 #include "network-history.h"
41 #include "GraphicsCache.h"
42 #include "boxcompose.h"
43
44 HistoryReportDialog::HistoryReportDialog(Player *p, HistoryReportType type)
45 {
46   d_player = p;
47   Glib::RefPtr<Gtk::Builder> xml
48     = Gtk::Builder::create_from_file(get_glade_path()
49                                 + "/history-report-dialog.ui");
50
51   xml->get_widget("dialog", dialog);
52   decorate(dialog);
53
54   generatePastCitylists();
55   generatePastRuinlists();
56   generatePastEventlists();
57
58   xml->get_widget("map_image", map_image);
59   historymap = new HistoryMap(Citylist::getInstance(), Ruinlist::getInstance());
60   historymap->map_changed.connect
61     (sigc::mem_fun(this, &HistoryReportDialog::on_map_changed));
62
63   xml->get_widget("turn_scale", turn_scale);
64   set_title(_("History"));
65   turn_scale->set_range(1, past_citylists.size());
66   turn_scale->set_value(past_citylists.size());
67
68   turn_scale->signal_value_changed().connect
69     (sigc::bind(sigc::mem_fun(this, &HistoryReportDialog::on_turn_changed),
70                 turn_scale));
71
72   xml->get_widget("history_notebook", history_notebook);
73   history_notebook->set_current_page(type);
74   history_notebook->signal_switch_page().connect(
75         sigc::mem_fun(*this, &HistoryReportDialog::on_switch_page));
76
77   xml->get_widget("city_label", city_label);
78   xml->get_widget("ruin_label", ruin_label);
79   xml->get_widget("gold_label", gold_label);
80   xml->get_widget("winner_label", winner_label);
81
82   //events_list = Gtk::ListStore::create(events_columns);
83   //xml->get_widget("treeview", events_treeview);
84   //events_treeview->set_model(events_list);
85   //events_treeview->append_column("", events_columns.box);
86   //events_treeview->append_column("", events_columns.desc);
87
88   xml->get_widget("events_list_box", events_list_box);
89   Gtk::Button *close_button;
90   xml->get_widget("close_button", close_button);
91   close_button->signal_clicked().connect
92     (sigc::mem_fun(*this, &HistoryReportDialog::on_close_button));
93   closing = false;
94
95   xml->get_widget("city_alignment", city_alignment);
96   xml->get_widget("ruin_alignment", ruin_alignment);
97   xml->get_widget("gold_alignment", gold_alignment);
98   xml->get_widget("winner_alignment", winner_alignment);
99
100   Playerlist::iterator pit = Playerlist::getInstance()->begin();
101   Gdk::Color colour;
102   for (; pit != Playerlist::getInstance()->end(); ++pit)
103     {
104       if (*pit == Playerlist::getInstance()->getNeutral())
105         continue;
106       colour = (*pit)->getColor();
107       if (*pit == d_player)
108         d_colours.push_front(colour);
109       else
110         d_colours.push_back(colour);
111     }
112
113   generatePastCityCounts();
114   city_chart = new LineChart(past_citycounts, d_colours, 
115                              Citylist::getInstance()->size(),
116                              _("Cities"), _("Turns"));
117   city_alignment->add(*manage(city_chart));
118
119   generatePastRuinCounts();
120   ruin_chart = new LineChart(past_ruincounts, d_colours, 
121                              Ruinlist::getInstance()->size(),
122                              _("Explored Ruins"), _("Turns"));
123   ruin_alignment->add(*manage(ruin_chart));
124
125   generatePastGoldCounts();
126   gold_chart = new LineChart(past_goldcounts, d_colours, 0, 
127                              _("Gold Pieces"), _("Turns"));
128   gold_alignment->add(*manage(gold_chart));
129
130   generatePastWinningCounts();
131   rank_chart = new LineChart(past_rankcounts, d_colours, 100,
132                              _("Score"), _("Turns"));
133   winner_alignment->add(*manage(rank_chart));
134
135   fill_in_turn_info((guint32)turn_scale->get_value());
136 }
137
138 HistoryReportDialog::~HistoryReportDialog()
139 {
140   std::vector<std::list<NetworkHistory *> >::iterator it;
141   it = past_eventlists.begin();
142   for (; it != past_eventlists.end(); it++)
143     {
144       std::list<NetworkHistory*> hist = (*it);
145       std::list<NetworkHistory*>::iterator hit = hist.begin();
146       for (; hit != hist.end(); hit++)
147         delete (*hit);
148     }
149   delete dialog;
150   delete historymap;
151 }
152
153 void HistoryReportDialog::generatePastEventlists()
154 {
155   bool last_turn = false;
156   std::list<NetworkHistory*> *elist = new std::list<NetworkHistory*>();
157
158   //keep a set of pointers to remember how far we are into each player's history
159   std::list<History*> *hist[MAX_PLAYERS];
160   Playerlist::iterator pit = Playerlist::getInstance()->begin();
161   for (; pit != Playerlist::getInstance()->end(); ++pit)
162     {
163       if (*pit == Playerlist::getInstance()->getNeutral())
164         continue;
165       hist[(*pit)->getId()] = (*pit)->getHistorylist();
166     }
167   std::list<History*>::iterator hit[MAX_PLAYERS];
168   pit = Playerlist::getInstance()->begin();
169   for (; pit != Playerlist::getInstance()->end(); ++pit)
170     {
171       if (*pit == Playerlist::getInstance()->getNeutral())
172         continue;
173       hit[(*pit)->getId()] = hist[(*pit)->getId()]->begin();
174     }
175
176   unsigned int count = 0;
177   while (1)
178     {
179       //now we see what cities we took this turn
180       pit = Playerlist::getInstance()->begin();
181       for (; pit != Playerlist::getInstance()->end(); ++pit)
182         {
183           if (*pit == Playerlist::getInstance()->getNeutral())
184             continue;
185           //dump everything up to the next turn
186           guint32 id = (*pit)->getId();
187           if (hit[id] == hist[id]->end())
188             continue;
189           for (; hit[id] != hist[id]->end(); ++hit[id])
190             {
191               if ((*hit[id])->getType() == History::START_TURN)
192                 {
193                   hit[id]++;
194                   break;
195                 }
196               switch ((*hit[id])->getType())
197                 {
198                 case History::FOUND_SAGE: 
199                 case History::HERO_EMERGES:
200                 case History::HERO_QUEST_STARTED:
201                 case History::HERO_QUEST_COMPLETED:
202                 case History::HERO_KILLED_IN_CITY:
203                 case History::HERO_KILLED_IN_BATTLE:
204                 case History::HERO_KILLED_SEARCHING:
205                 case History::HERO_CITY_WON:
206                 case History::HERO_FINDS_ALLIES:
207                 case History::PLAYER_VANQUISHED:
208                 case History::DIPLOMATIC_TREACHERY:
209                 case History::DIPLOMATIC_WAR:
210                 case History::DIPLOMATIC_PEACE:
211                 case History::HERO_RUIN_EXPLORED:
212                   elist->push_back(new NetworkHistory(*hit[id], (*pit)->getId()));
213                   break;
214                 case History::START_TURN:
215                 case History::GOLD_TOTAL:
216                 case History::CITY_WON:
217                 case History::CITY_RAZED:
218                 case History::SCORE:
219                 case History::HERO_REWARD_RUIN:
220                 case History::END_TURN:
221                   break;
222                 }
223             }
224           if (hit[id] == hist[id]->end())
225             {
226               count++;
227               if (count == Playerlist::getInstance()->size() - 2)
228                 last_turn = true;
229             }
230         }
231       //and add it to the list
232       past_eventlists.push_back(*elist);
233       std::list<NetworkHistory*> *new_elist = new std::list<NetworkHistory*>();
234       elist = new_elist;
235       if (last_turn == true)
236         break;
237
238     }
239 }
240
241 void HistoryReportDialog::generatePastCitylists()
242 {
243   bool last_turn = false;
244
245   //keep a set of pointers to remember how far we are into each player's history
246   std::list<History*> *hist[MAX_PLAYERS];
247   Playerlist::iterator pit = Playerlist::getInstance()->begin();
248   for (; pit != Playerlist::getInstance()->end(); ++pit)
249     {
250       if (*pit == Playerlist::getInstance()->getNeutral())
251         continue;
252       hist[(*pit)->getId()] = (*pit)->getHistorylist();
253     }
254   std::list<History*>::iterator hit[MAX_PLAYERS];
255   pit = Playerlist::getInstance()->begin();
256   for (; pit != Playerlist::getInstance()->end(); ++pit)
257     {
258       if (*pit == Playerlist::getInstance()->getNeutral())
259         continue;
260       hit[(*pit)->getId()] = hist[(*pit)->getId()]->begin();
261     }
262
263   //start off with an initial city list where all cities are neutral owned
264   LocationList<City*> *clist = new LocationList<City*>();
265   Citylist *cl = Citylist::getInstance();
266   for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
267     clist->push_back(new City(**it));
268   for (LocationList<City*>::iterator it = clist->begin(); it != clist->end(); ++it)
269     {
270       (*it)->setOwner(Playerlist::getInstance()->getNeutral());
271       //is the city burned to begin with?
272       bool no_city_history = true;
273       pit = Playerlist::getInstance()->begin();
274       for (; pit != Playerlist::getInstance()->end(); ++pit)
275         if ((*pit)->conqueredCity(*it) == true)
276           no_city_history = false;
277       if ((*it)->isBurnt() == true && no_city_history)
278         (*it)->setBurnt(true);
279       else
280         (*it)->setBurnt(false);
281     }
282
283   unsigned int count = 0;
284   while (1)
285     {
286       //now we see what cities we took this turn
287       pit = Playerlist::getInstance()->begin();
288       for (; pit != Playerlist::getInstance()->end(); ++pit)
289         {
290           if (*pit == Playerlist::getInstance()->getNeutral())
291             continue;
292           //dump everything up to the next turn
293           guint32 id = (*pit)->getId();
294           if (hit[id] == hist[id]->end())
295             continue;
296           for (; hit[id] != hist[id]->end(); hit[id]++)
297             {
298               if ((*hit[id])->getType() == History::START_TURN)
299                 {
300                   hit[id]++;
301                   break;
302                 }
303               else if ((*hit[id])->getType() == History::CITY_WON)
304                 {
305                   guint32 city_id;
306                   city_id = dynamic_cast<History_CityWon*>(*hit[id])->getCityId();
307                   //find city with this city id in clist
308                   LocationList<City*>::iterator cit = clist->begin();
309                   for (; cit != clist->end(); ++cit)
310                     if ((*cit)->getId() == city_id)
311                       {
312                         (*cit)->setOwner(*pit);
313                         break;
314                       }
315                 }
316               else if ((*hit[id])->getType() == History::CITY_RAZED)
317                 {
318                   guint32 city_id;
319                   city_id = dynamic_cast<History_CityRazed*>(*hit[id])->getCityId();
320                   //find city with this city id in clist
321                   LocationList<City*>::iterator cit = clist->begin();
322                   for (; cit != clist->end(); ++cit)
323                     if ((*cit)->getId() == city_id)
324                       {
325                         //change the owner to neutral 
326                         (*cit)->setOwner(Playerlist::getInstance()->getNeutral());
327                         (*cit)->setBurnt(true);
328                         break;
329                       }
330                 }
331             }
332           if (hit[id] == hist[id]->end())
333             {
334               count++;
335               if (count == Playerlist::getInstance()->size() - 2)
336                 last_turn = true;
337             }
338         }
339       //and add it to the list
340       past_citylists.push_back(clist);
341       LocationList<City*> *new_clist = new LocationList<City*>();
342       for (LocationList<City*>::iterator it = clist->begin(); 
343            it != clist->end(); ++it)
344         new_clist->push_back(new City(**it));
345       clist = new_clist;
346       if (last_turn == true)
347         break;
348
349     }
350   past_citylists.erase(--past_citylists.end());
351 }
352
353 void HistoryReportDialog::set_parent_window(Gtk::Window &parent)
354 {
355   dialog->set_transient_for(parent);
356   //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
357 }
358
359 void HistoryReportDialog::hide()
360 {
361   dialog->hide();
362 }
363
364 void HistoryReportDialog::run()
365 {
366   historymap->resize();
367   historymap->draw(Playerlist::getActiveplayer());
368
369   dialog->show_all();
370   dialog->run();
371 }
372
373 void HistoryReportDialog::on_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
374 {
375   map_image->property_pixmap() = map;
376 }
377
378 void HistoryReportDialog::on_turn_changed(Gtk::Scale *scale)
379 {
380   //tell the historymap to show another set of cities
381   guint32 turn = (guint32)turn_scale->get_value();
382   if (turn > past_citylists.size() - 1)
383     historymap->updateCities(Citylist::getInstance(), Ruinlist::getInstance());
384   else
385     historymap->updateCities(past_citylists[turn], past_ruinlists[turn]);
386   city_chart->set_x_indicator(turn);
387   ruin_chart->set_x_indicator(turn);
388   gold_chart->set_x_indicator(turn);
389   rank_chart->set_x_indicator(turn);
390   fill_in_turn_info(turn);
391 }
392
393 void HistoryReportDialog::update_window_title()
394 {
395   switch (history_notebook->get_current_page())
396     {
397     case CITY:
398       set_title(_("City History"));
399       break;
400     case RUIN:
401       set_title(_("Ruin History"));
402       break;
403     case EVENTS: 
404       set_title(_("Event History"));
405       break;
406     case GOLD: 
407       set_title(_("Gold History"));
408       break;
409     case WINNING:
410       set_title(_("Winner History"));
411       break;
412     }
413 }
414
415 void HistoryReportDialog::fill_in_turn_info(guint32 turn)
416 {
417   Glib::ustring s;
418   guint32 count;
419   update_window_title();
420
421   //update the event list
422   //events_list->clear();
423   events_list_box->children().erase(events_list_box->children().begin(),
424                                     events_list_box->children().end());
425   if (turn <= past_eventlists.size() - 1)
426     {
427       std::list<NetworkHistory*> hist = past_eventlists[turn];
428       std::list<NetworkHistory*>::iterator hit = hist.begin();
429       for (; hit != hist.end(); hit++)
430         addHistoryEvent(*hit);
431     }
432
433   //update the gold chart
434   //on turn # you had # gold pieces
435   std::list<guint32> goldlist = *past_goldcounts.begin();
436   std::list<guint32>::iterator it = goldlist.begin();
437   count=1;
438   for (; it != goldlist.end(); it++, count++)
439     {
440       if (count == turn)
441         {
442           count = *it;
443           break;
444         }
445     }
446   turn == past_citylists.size() ?
447     s = String::ucompose(ngettext("On turn %1 you have %2 gold piece!",
448                                   "On turn %1 you have %2 gold pieces!",
449                                   count), turn, count) :
450     s = String::ucompose(ngettext("On turn %1 you had %2 gold piece!",
451                                   "On turn %1 you had %2 gold pieces!",
452                                   count), turn, count);
453   gold_label->set_text(s);
454
455   //update the city chart
456   std::list<guint32> citylist = *past_citycounts.begin();
457   it = citylist.begin();
458   count = 0;
459   for (; it != citylist.end(); it++, count++)
460     {
461       if (count == turn)
462         {
463           count = *it;
464           break;
465         }
466     }
467   turn == past_citylists.size() ?
468     s = String::ucompose(ngettext("On turn %1 you have %2 city!",
469                                   "On turn %1 you have %2 cities!",
470                                   count), turn, count) :
471     s = String::ucompose(ngettext("On turn %1 you had %2 city!",
472                                   "On turn %1 you had %2 cities!",
473                                   count), turn, count);
474   city_label->set_text(s);
475
476   //update the ruin chart
477   std::list<guint32> ruinlist = *past_ruincounts.begin();
478   it = ruinlist.begin();
479   count = 0;
480   for (; it != ruinlist.end(); it++, count++)
481     {
482       if (count == turn)
483         {
484           count = *it;
485           break;
486         }
487     }
488   turn == past_ruinlists.size() ?
489   s = String::ucompose(ngettext("By turn %1 you explored %2 ruin!",
490                                 "By turn %1 you explored %2 ruins!",
491                                 count), turn, count) :
492   s = String::ucompose(ngettext("By turn %1 you explored %2 ruin!",
493                                 "By turn %1 you explored %2 ruins!",
494                                 count), turn, count);
495   ruin_label->set_text(s);
496
497   //on turn # you were coming #
498   std::list<guint32> scores;
499   std::list<std::list<guint32> >::iterator rit = past_rankcounts.begin();
500   for (; rit != past_rankcounts.end(); rit++)
501     {
502       it = (*rit).begin();
503       count=1;
504       for (; it != (*rit).end(); it++, count++)
505         {
506           if (count == turn)
507             {
508               count = *it;
509               scores.push_back(*it);
510               break;
511             }
512         }
513     }
514   turn == past_citylists.size() ?
515     s = String::ucompose(_("On turn %1 you are coming %2!"),
516                          turn, ReportDialog::calculateRank(scores, *scores.begin())):
517     s = String::ucompose(_("On turn %1 you were coming %2!"),
518                          turn, ReportDialog::calculateRank(scores, *scores.begin()));
519   winner_label->set_text(s);
520 }
521
522 void HistoryReportDialog::on_switch_page(GtkNotebookPage *page, guint number)
523 {
524   if (closing)
525     return;
526   update_window_title();
527 }
528
529 void HistoryReportDialog::addHistoryEvent(NetworkHistory *event)
530 {
531   GraphicsCache *gc = GraphicsCache::getInstance();
532   Playerlist *pl = Playerlist::getInstance();
533   Player *p = event->getOwner();
534
535   History *history = event->getHistory();
536
537   Gtk::HBox *box = NULL;
538
539                               
540   Glib::RefPtr<Gdk::Pixbuf> shield = gc->getShieldPic(1, p)->to_pixbuf();
541   switch (history->getType())
542     {
543     case History::FOUND_SAGE: 
544         {
545           History_FoundSage *ev = static_cast<History_FoundSage *>(history);
546           box = Box::ucompose(_("%1 %2 finds a sage!"), shield,
547                               ev->getHeroName());
548           break;
549         }
550     case History::HERO_EMERGES:
551         {
552           History_HeroEmerges *ev;
553           ev = static_cast<History_HeroEmerges *>(history);
554           box = Box::ucompose(_("%1 %2 emerges in %3"), shield,
555                               ev->getHeroName(), ev->getCityName());
556           break;
557         }
558     case History::HERO_QUEST_STARTED:
559         {
560           History_HeroQuestStarted *ev = 
561             static_cast<History_HeroQuestStarted*>(history);
562           box = Box::ucompose(_("%1 %2 begins a quest!"), shield,
563                               ev->getHeroName());
564           break;
565         }
566     case History::HERO_QUEST_COMPLETED:
567         {
568           History_HeroQuestCompleted *ev
569             = static_cast<History_HeroQuestCompleted *>(history);
570           box = Box::ucompose(_("%1 %2 finishes a quest!"), shield,
571                               ev->getHeroName());
572           break;
573         }
574     case History::HERO_KILLED_IN_CITY:
575         {
576           History_HeroKilledInCity *ev = 
577             static_cast<History_HeroKilledInCity *>(history);
578           box = Box::ucompose(_("%1 %2 is killed in %3!"), shield,
579                               ev->getHeroName(), ev->getCityName());
580           break;
581         }
582     case History::HERO_KILLED_IN_BATTLE:
583         {
584           History_HeroKilledInBattle *ev = 
585             static_cast<History_HeroKilledInBattle *>(history);
586           box = Box::ucompose(_("%1 %2 is killed in battle!"), shield,
587                               ev->getHeroName());
588           break;
589         }
590     case History::HERO_KILLED_SEARCHING:
591         {
592           History_HeroKilledSearching *ev = 
593             static_cast<History_HeroKilledSearching *>(history);
594           box = Box::ucompose(_("%1 %2 is killed while searching!"), shield,
595                               ev->getHeroName());
596           break;
597         }
598     case History::HERO_CITY_WON:
599         {
600           History_HeroCityWon *ev = 
601             static_cast<History_HeroCityWon *>(history);
602           box = Box::ucompose(_("%1 %2 conquers %3!"), shield,
603                               ev->getHeroName(), ev->getCityName());
604           break;
605         }
606     case History::PLAYER_VANQUISHED:
607         {
608           box = Box::ucompose(_("%1 %2 utterly vanquished!"), shield,
609                               p->getName());
610           break;
611         }
612     case History::DIPLOMATIC_PEACE:
613         {
614           History_DiplomacyPeace *ev = 
615             static_cast<History_DiplomacyPeace*>(history);
616           Player *opponent = pl->getPlayer(ev->getOpponentId());
617           box = Box::ucompose(_("%1 %2 at peace with %3 %4!"), shield,
618                               p->getName(), 
619                               gc->getShieldPic(1, opponent)->to_pixbuf(), 
620                               opponent->getName());
621           break;
622         }
623     case History::DIPLOMATIC_WAR:
624         {
625           History_DiplomacyWar *ev = 
626             static_cast<History_DiplomacyWar*>(history);
627           Player *opponent = pl->getPlayer(ev->getOpponentId());
628           box = Box::ucompose(_("%1 %2 at war with %3 %4!"), shield,
629                               p->getName(), 
630                               gc->getShieldPic(1, opponent)->to_pixbuf(), 
631                               opponent->getName());
632           break;
633         }
634     case History::DIPLOMATIC_TREACHERY:
635         {
636           History_DiplomacyTreachery *ev = 
637             static_cast<History_DiplomacyTreachery*>(history);
638           Player *opponent = pl->getPlayer(ev->getOpponentId());
639           box = Box::ucompose(_("%1 Treachery on %2 %3!"), shield,
640                               gc->getShieldPic(1, opponent)->to_pixbuf(), 
641                               opponent->getName());
642           break;
643         }
644     case History::HERO_FINDS_ALLIES:
645         {
646           History_HeroFindsAllies *ev = 
647             static_cast<History_HeroFindsAllies*>(history);
648           box = Box::ucompose(_("%1 %2 finds allies!"), shield, 
649                               ev->getHeroName());
650           break;
651         }
652     case History::HERO_RUIN_EXPLORED:
653         {
654           History_HeroRuinExplored *ev = 
655             static_cast<History_HeroRuinExplored *>(history);
656           Ruinlist *rl = Ruinlist::getInstance();
657           box = Box::ucompose(_("%1 %2 explores %3!"), shield, 
658                               ev->getHeroName(),
659                               rl->getById(ev->getRuinId())->getName());
660           break;
661         }
662     default:
663       box = NULL;
664       break;
665     }
666
667   if (box)
668     {
669       events_list_box->pack_start(*manage(box), Gtk::PACK_SHRINK, 0);
670       events_list_box->show_all();
671     }
672 }
673 void HistoryReportDialog::on_close_button()
674 {
675   closing = true;
676   //FIXME: find out why the page_switch events with crap data,
677   //and then remove this function, and the closing variable too.
678 }
679
680 void HistoryReportDialog::generatePastWinningCounts()
681 {
682   //go through the history list looking for score events, per player
683   Playerlist::iterator pit = Playerlist::getInstance()->begin();
684   pit = Playerlist::getInstance()->begin();
685   for (; pit != Playerlist::getInstance()->end(); ++pit)
686     {
687       if (*pit == Playerlist::getInstance()->getNeutral())
688         continue;
689       std::list<History*> *hist = (*pit)->getHistorylist();
690       std::list<History*>::iterator hit = hist->begin();
691       std::list<guint32> line;
692       for (; hit != hist->end(); hit++)
693         {
694           if ((*hit)->getType() == History::SCORE)
695             {
696               History_Score *event = static_cast<History_Score*>(*hit);
697               line.push_back (event->getScore());
698             }
699         }
700       line.push_back ((guint32)(*pit)->getScore());
701       if (*pit == d_player)
702         past_rankcounts.push_front(line);
703       else
704         past_rankcounts.push_back(line);
705     }
706 }
707
708 void HistoryReportDialog::generatePastCityCounts()
709 {
710   // go through the past city list
711   Playerlist::iterator pit = Playerlist::getInstance()->begin();
712   pit = Playerlist::getInstance()->begin();
713   for (; pit != Playerlist::getInstance()->end(); ++pit)
714     {
715       if (*pit == Playerlist::getInstance()->getNeutral())
716         continue;
717       //go through the past city lists, searching for cities owned by this
718       //player
719
720       std::list<guint32> line;
721       for (unsigned int i = 0; i < past_citylists.size(); i++)
722         {
723           guint32 total_cities = 0;
724           LocationList<City*>::iterator it = past_citylists[i]->begin();
725           for (; it != past_citylists[i]->end(); it++)
726             {
727               if ((*it)->getOwner() == *pit)
728                 total_cities++;
729             }
730           line.push_back(total_cities);
731         }
732
733       line.push_back(Citylist::getInstance()->countCities(*pit));
734       if (*pit == d_player)
735         past_citycounts.push_front(line);
736       else
737         past_citycounts.push_back(line);
738
739     }
740 }
741
742 void HistoryReportDialog::generatePastGoldCounts()
743 {
744   //go through the history list looking for gold events, per player
745   Playerlist::iterator pit = Playerlist::getInstance()->begin();
746   pit = Playerlist::getInstance()->begin();
747   for (; pit != Playerlist::getInstance()->end(); ++pit)
748     {
749       if (*pit == Playerlist::getInstance()->getNeutral())
750         continue;
751       std::list<History*> *hist = (*pit)->getHistorylist();
752       std::list<History*>::iterator hit = hist->begin();
753       std::list<guint32> line;
754       for (; hit != hist->end(); hit++)
755         {
756           if ((*hit)->getType() == History::GOLD_TOTAL)
757             {
758               History_GoldTotal *event = static_cast<History_GoldTotal*>(*hit);
759               line.push_back (event->getGold());
760             }
761         }
762       line.push_back ((guint32)(*pit)->getGold());
763       if (*pit == d_player)
764         past_goldcounts.push_front(line);
765       else
766         past_goldcounts.push_back(line);
767     }
768 }
769
770 void HistoryReportDialog::generatePastRuinCounts()
771 {
772   //how many ruins did the players search at each turn?
773
774   Playerlist::iterator pit = Playerlist::getInstance()->begin();
775   pit = Playerlist::getInstance()->begin();
776   for (; pit != Playerlist::getInstance()->end(); ++pit)
777     {
778       if (*pit == Playerlist::getInstance()->getNeutral())
779         continue;
780       std::list<guint32> line;
781       for (unsigned int i = 0; i < past_citylists.size(); i++)
782         {
783           guint32 total_ruins = 0;
784           LocationList<Ruin*>::iterator it = past_ruinlists[i]->begin();
785           for (; it != past_ruinlists[i]->end(); it++)
786             {
787               Ruin *ruin = *it;
788               if (ruin->isHidden() == true && ruin->getOwner() != *pit)
789                 continue;
790               if (ruin->isSearched() == true && 
791                   (*pit)->searchedRuin(ruin) == true)
792                 {
793                   ruin->setOwner(*pit);
794                   total_ruins++;
795                 }
796             }
797           line.push_back(total_ruins);
798         }
799       line.push_back(Ruinlist::getInstance()->countExploredRuins(*pit));
800       if (*pit == d_player)
801         past_ruincounts.push_front(line);
802       else
803         past_ruincounts.push_back(line);
804     }
805 }
806
807 void HistoryReportDialog::generatePastRuinlists()
808 {
809   //we don't do this per player
810   //we just count how many ruins are unexplored at every turn.
811   //how do we deal with hidden ruins?
812   //they should pop up when found.
813   bool last_turn = false;
814
815   //keep a set of pointers to remember how far we are into each player's history
816   std::list<History*> *hist[MAX_PLAYERS];
817   Playerlist::iterator pit = Playerlist::getInstance()->begin();
818   for (; pit != Playerlist::getInstance()->end(); ++pit)
819     {
820       if (*pit == Playerlist::getInstance()->getNeutral())
821         continue;
822       hist[(*pit)->getId()] = (*pit)->getHistorylist();
823     }
824   std::list<History*>::iterator hit[MAX_PLAYERS];
825   pit = Playerlist::getInstance()->begin();
826   for (; pit != Playerlist::getInstance()->end(); ++pit)
827     {
828       if (*pit == Playerlist::getInstance()->getNeutral())
829         continue;
830       hit[(*pit)->getId()] = hist[(*pit)->getId()]->begin();
831     }
832
833   //start off with an initial ruin list where all ruins are unexplored and hidden.
834   //all hidden ruins haven't been found yet, unless they started off that way.
835   LocationList<Ruin*> *rlist = new LocationList<Ruin*>();
836   Ruinlist *rl = Ruinlist::getInstance();
837   for (Ruinlist::iterator it = rl->begin(); it != rl->end(); ++it)
838     rlist->push_back(new Ruin(**it));
839   for (LocationList<Ruin*>::iterator it = rlist->begin(); it != rlist->end(); ++it)
840     {
841       //is the ruin searched to begin with?
842       bool no_ruin_history = true;
843       pit = Playerlist::getInstance()->begin();
844       for (; pit != Playerlist::getInstance()->end(); ++pit)
845         if ((*pit)->searchedRuin(*it) == true)
846           no_ruin_history = false;
847       if ((*it)->isSearched() == true && no_ruin_history)
848         (*it)->setSearched(true);
849       else
850         {
851           (*it)->setSearched(false);
852           if ((*it)->isHidden())
853             (*it)->setOwner(NULL);
854         }
855     }
856
857   unsigned int count = 0;
858   while (1)
859     {
860       //now we see what ruins we took this turn
861       pit = Playerlist::getInstance()->begin();
862       for (; pit != Playerlist::getInstance()->end(); ++pit)
863         {
864           if (*pit == Playerlist::getInstance()->getNeutral())
865             continue;
866           //dump everything up to the next turn
867           guint32 id = (*pit)->getId();
868           if (hit[id] == hist[id]->end())
869             continue;
870           for (; hit[id] != hist[id]->end(); hit[id]++)
871             {
872               if ((*hit[id])->getType() == History::START_TURN)
873                 {
874                   hit[id]++;
875                   break;
876                 }
877               //when a ruin becomes visible all of a sudden, we mark it as visible
878               else if ((*hit[id])->getType() == History::HERO_REWARD_RUIN)
879                 {
880                   guint32 ruin_id;
881                   ruin_id = 
882                     dynamic_cast<History_HeroRewardRuin*>(*hit[id])->getRuinId();
883                   //find ruin with this ruin id in rlist
884                   LocationList<Ruin*>::iterator rit = rlist->begin();
885                   for (; rit != rlist->end(); ++rit)
886                     if ((*rit)->getId() == ruin_id)
887                       {
888                         (*rit)->setOwner(*pit);
889                         break;
890                       }
891                 }
892               else if ((*hit[id])->getType() == History::HERO_RUIN_EXPLORED)
893                 {
894                   guint32 ruin_id;
895                   ruin_id = 
896                     dynamic_cast<History_HeroRuinExplored*>(*hit[id])->getRuinId();
897                   //find ruin with this ruin id in rlist
898                   LocationList<Ruin*>::iterator rit = rlist->begin();
899                   for (; rit != rlist->end(); ++rit)
900                     if ((*rit)->getId() == ruin_id)
901                       {
902                         (*rit)->setSearched(true);
903                         break;
904                       }
905                 }
906             }
907           if (hit[id] == hist[id]->end())
908             {
909               count++;
910               if (count == Playerlist::getInstance()->size() - 2)
911                 last_turn = true;
912             }
913         }
914       //and add it to the list
915       past_ruinlists.push_back(rlist);
916       LocationList<Ruin*> *new_rlist = new LocationList<Ruin*>();
917       for (LocationList<Ruin*>::iterator it = rlist->begin(); 
918            it != rlist->end(); ++it)
919         new_rlist->push_back(new Ruin(**it));
920       rlist = new_rlist;
921       if (last_turn == true)
922         break;
923
924     }
925   past_ruinlists.erase(--past_ruinlists.end());
926 }