1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004 John Farrell
4 // Copyright (C) 2005 Andrea Paternesi
5 // Copyright (C) 2007, 2008, 2009, 2010, 2014, 2015, 2017, 2020 Ben Asselstine
6 // Copyright (C) 2007 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 <sstream>
25 #include <sigc++/functors/mem_fun.h>
26
27 #include "playerlist.h"
28 #include "armysetlist.h"
29 #include "citylist.h"
30 #include "ruinlist.h"
31 #include "vectoredunitlist.h"
32 #include "xmlhelper.h"
33 #include "history.h"
34 #include "stacklist.h"
35 #include "FogMap.h"
36 #include "real_player.h"
37 #include "ai_smart.h"
38 #include "ai_fast.h"
39 #include "ai_dummy.h"
40 #include "network_player.h"
41 #include "GameMap.h"
42 #include "shieldset.h"
43 #include "shieldsetlist.h"
44 #include "ucompose.hpp"
45 #include "stack.h"
46 #include "rnd.h"
47
48 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
49 #define debug(x)
50
51 Glib::ustring Playerlist::d_tag = "playerlist";
52 Playerlist* Playerlist::s_instance = 0;
53 Player* Playerlist::d_activeplayer = 0;
54 Player* Playerlist::viewingplayer = 0;
55
getInstance()56 Playerlist* Playerlist::getInstance()
57 {
58 if (s_instance == 0)
59 s_instance = new Playerlist();
60
61 return s_instance;
62 }
63
getInstance(XML_Helper * helper)64 Playerlist* Playerlist::getInstance(XML_Helper* helper)
65 {
66 if (s_instance)
67 deleteInstance();
68
69 s_instance = new Playerlist(helper);
70
71 return s_instance;
72 }
73
deleteInstance()74 void Playerlist::deleteInstance()
75 {
76 if (s_instance)
77 {
78 delete s_instance;
79 s_instance = 0;
80 }
81 }
82
Playerlist()83 Playerlist::Playerlist()
84 :d_neutral(0)
85 {
86 d_activeplayer = 0;
87 viewingplayer = 0;
88 }
89
Playerlist(XML_Helper * helper)90 Playerlist::Playerlist(XML_Helper* helper)
91 :d_neutral(0)
92 {
93 d_activeplayer=0;
94 viewingplayer=0;
95 //load data. This consists currently of two values: size (for checking
96 //the size; we don't use it yet) and active(which player is active)
97 //we do it by calling load with playerlist as string
98 load(Playerlist::d_tag, helper);
99
100 helper->registerTag(Player::d_tag, sigc::mem_fun(this, &Playerlist::load));
101 }
102
~Playerlist()103 Playerlist::~Playerlist()
104 {
105 iterator it = begin();
106 while (!empty())
107 it = flErase(it);
108 }
109
checkPlayers()110 bool Playerlist::checkPlayers()
111 {
112 bool last = false;
113 bool dead = false;
114 debug("checkPlayers()");
115 iterator it = begin ();
116
117 while (it != end ())
118 {
119 debug("checkPlayers() iter");
120 //ignore the neutral player as well as dead and immortal ones
121 if ((*it) == d_neutral || (*it)->isDead() || (*it)->isImmortal())
122 {
123 debug("checkPlayers() dead?");
124 it++;
125 continue;
126 }
127
128 if (!Citylist::getInstance()->countCities((*it)))
129 {
130 debug("checkPlayers() city?");
131 iterator nextit = it;
132 nextit++;
133
134 (*it)->kill();
135 if (getNoOfPlayers() == 1)
136 last = true;
137 splayerDead.emit(*it);
138 dead = true;
139 if (last)
140 break;
141
142 it = nextit; // do this at the end to catch abuse of invalid it
143 } else {
144 debug("checkPlayers() inc");
145 ++it;
146 }
147 }
148 return dead;
149 }
150
nextPlayer()151 void Playerlist::nextPlayer()
152 {
153 debug("nextPlayer()");
154
155 iterator it;
156
157 if (!d_activeplayer)
158 it = begin();
159 else
160 {
161 for (it = begin(); it != end(); ++it)
162 {
163 if ((*it) == d_activeplayer)
164 {
165 it++;
166 break;
167 }
168 }
169 }
170
171 // in case we have got a dead player, continue iterating. This breaks
172 // if we have ONLY dead players which we assume never happens.
173 while ((it == end()) || ((*it)->isDead()))
174 {
175 if (it == end())
176 {
177 it = begin();
178 continue;
179 }
180 it++;
181 }
182
183 d_activeplayer = (*it);
184 updateViewingPlayer();
185 debug("got player: " <<d_activeplayer->getName())
186 }
187
getPlayer(Glib::ustring name) const188 Player* Playerlist::getPlayer(Glib::ustring name) const
189 {
190 debug("getPlayer()");
191 for (const_iterator it = begin(); it != end(); ++it)
192 if ((*it)->getName() == name) return (*it);
193 return 0;
194 }
195
getPlayer(guint32 id) const196 Player* Playerlist::getPlayer(guint32 id) const
197 {
198 IdMap::const_iterator it = d_id.find(id);
199 if (it == d_id.end())
200 return NULL;
201 return (*it).second;
202 }
203
getNoOfPlayers() const204 guint32 Playerlist::getNoOfPlayers() const
205 {
206 unsigned int number = 0;
207
208 for (const_iterator it = begin(); it != end(); it++)
209 {
210 if (((*it) != d_neutral) && !(*it)->isDead())
211 number++;
212 }
213
214 return number;
215 }
216
getFirstLiving() const217 Player* Playerlist::getFirstLiving() const
218 {
219 for (const_iterator it = begin(); ; it++)
220 if (!(*it)->isDead() && *it != d_neutral)
221 return (*it);
222 }
223
save(XML_Helper * helper) const224 bool Playerlist::save(XML_Helper* helper) const
225 {
226 //to prevent segfaults
227 if (!d_activeplayer)
228 d_activeplayer = (*begin());
229
230 bool retval = true;
231
232 retval &= helper->openTag(Playerlist::d_tag);
233 retval &= helper->saveData("active", d_activeplayer->getId());
234 retval &= helper->saveData("neutral", d_neutral->getId());
235
236 for (const_iterator it = begin(); it != end(); it++)
237 retval &= (*it)->save(helper);
238
239 retval &= helper->closeTag();
240
241 return retval;
242 }
243
add(Player * player)244 void Playerlist::add(Player *player)
245 {
246 push_back(player);
247 d_id[player->getId()] = player;
248 }
249
load(Glib::ustring tag,XML_Helper * helper)250 bool Playerlist::load(Glib::ustring tag, XML_Helper* helper)
251 {
252 static guint32 active = 0;
253 static guint32 neutral = 0;
254
255 if (tag == Playerlist::d_tag) //only called in the constructor
256 {
257 helper->getData(active, "active");
258 helper->getData(neutral, "neutral");
259 return true;
260 }
261
262 if (tag != Player::d_tag)
263 return false;
264
265 Player* p = Player::loadPlayer(helper);
266 if(p == 0)
267 return false;
268
269 //insert player...
270 add(p);
271
272 //set neutral and active
273 if (p->getId() == neutral)
274 d_neutral = p;
275 if (p->getId() == active)
276 d_activeplayer = p;
277
278 updateViewingPlayer();
279
280 return true;
281 }
282
flErase(Playerlist::iterator it)283 Playerlist::iterator Playerlist::flErase(Playerlist::iterator it)
284 {
285 if ((*it) == d_neutral)
286 d_neutral = 0;
287
288 delete (*it);
289 return erase (it);
290 }
291
compareDiplomaticScores(const struct rankable_t lhs,const struct rankable_t rhs)292 bool compareDiplomaticScores (const struct rankable_t lhs,
293 const struct rankable_t rhs)
294 {
295 /* make ties prefer normal player order */
296 if (lhs.score == rhs.score)
297 return lhs.player->getId() > rhs.player->getId();
298 else
299 return lhs.score < rhs.score;
300 }
301
get_title(int rank)302 Glib::ustring Playerlist::get_title(int rank)
303 {
304 if (rank == 0)
305 return _("Statesman");
306 else if (rank == 1)
307 return _("Diplomat");
308 else if (rank == 2)
309 return _("Pragmatist");
310 else if (rank == 3)
311 return _("Politician");
312 else if (rank == 4)
313 return _("Deceiver");
314 else if (rank == 5)
315 return _("Scoundrel");
316 else if (rank == 6)
317 return _("Turncoat");
318 else if (rank == 7)
319 return _("Running Dog");
320 return _("unknown");
321 }
322
calculateDiplomaticRankings()323 void Playerlist::calculateDiplomaticRankings()
324 {
325 unsigned int i = 0;
326 int used_titles[MAX_PLAYERS];
327 memset (used_titles, 0, sizeof (used_titles));
328
329 //determine the rank for each player
330 //add up the scores for all living players, and sort
331 std::list<struct rankable_t> rankables;
332 for (iterator pit = begin (); pit != end (); pit++)
333 {
334 if ((*pit) == d_neutral)
335 continue;
336 if ((*pit)->isDead () == true)
337 continue;
338 struct rankable_t rankable;
339 rankable.score = 0;
340 for (iterator it = begin (); it != end (); it++)
341 {
342 if ((*it) == d_neutral)
343 continue;
344 if ((*it)->isDead () == true)
345 continue;
346 if (*pit == *it)
347 continue;
348 rankable.score += (*it)->getDiplomaticScore(*pit);
349 }
350 rankable.player = *pit;
351 rankables.push_back(rankable);
352 }
353 rankables.sort (compareDiplomaticScores);
354 std::reverse (rankables.begin (), rankables.end ());
355
356 i = 1;
357 for (std::list<struct rankable_t>::iterator rit = rankables.begin ();
358 rit != rankables.end (); rit++)
359 {
360 (*rit).player->setDiplomaticRank(i);
361 i++;
362 }
363
364 // given the rankings, what are the titles?
365 // the titles are depleted from the middle as players die.
366 // 7 means deplete first, 0 means deplete last.
367 unsigned int deplete[MAX_PLAYERS] = { 0, 2, 4, 6, 7, 5, 3, 1 };
368
369 unsigned int numAlive = countPlayersAlive ();
370 // okay, we take the first numAlive titles
371
372 std::vector<Glib::ustring> available_titles;
373 for (i = numAlive; i < MAX_PLAYERS ; i++)
374 {
375 for (unsigned int j = 0; j < MAX_PLAYERS; j++)
376 {
377 if (deplete[j] == i)
378 used_titles[j] = 1;
379 }
380 }
381 for (unsigned int j = 0; j < MAX_PLAYERS; j++)
382 {
383 if (used_titles[j] != 1)
384 available_titles.push_back (get_title(j));
385 }
386
387 for (const_iterator it = begin (); it != end (); it++)
388 {
389 if ((*it) == d_neutral)
390 continue;
391 if ((*it)->isDead () == true)
392 continue;
393 guint32 rank = (*it)->getDiplomaticRank();
394 // recall that the first rank is 1, and not 0.
395 (*it)->setDiplomaticTitle (available_titles[rank - 1]);
396 }
397
398 return;
399 }
400
calculateWinners()401 void Playerlist::calculateWinners()
402 {
403 guint32 score;
404 guint32 total_gold = 0;
405 guint32 total_armies = 0;
406 guint32 total_cities = 0;
407 for (const_iterator it = begin(); it != end(); it++)
408 {
409 if ((*it) == d_neutral)
410 continue;
411 if ((*it)->isDead() == true)
412 continue;
413 total_gold += (*it)->getGold();
414 total_armies += (*it)->getStacklist()->countArmies();
415 }
416 total_cities = Citylist::getInstance()->size();
417
418 for (const_iterator it = begin(); it != end(); it++)
419 {
420 if ((*it) == d_neutral)
421 continue;
422 if ((*it)->isDead() == true)
423 continue;
424
425 float city_component = (float)
426 ((float) Citylist::getInstance()->countCities(*it)/ (float)total_cities) * 70.0;
427 float gold_component = (float)
428 ((float) (*it)->getGold() / (float)total_gold) * 10.0;
429 float army_component = (float)
430 ((float) (*it)->getStacklist()->countArmies() /
431 (float)total_armies) * 20.0;
432 score = (guint32) (city_component + gold_component + army_component);
433 (*it)->reportEndOfRound(score);
434 }
435
436 return;
437 }
438
countHumanPlayersAlive() const439 guint32 Playerlist::countHumanPlayersAlive() const
440 {
441 guint32 retval = 0;
442 for (const_iterator it = begin(); it != end(); it++)
443 if ((*it)->isDead() == false && (*it)->getType() == Player::HUMAN)
444 retval++;
445 return retval;
446 }
447
countPlayersAlive() const448 guint32 Playerlist::countPlayersAlive () const
449 {
450 guint32 numAlive = 0;
451
452 for (const_iterator it = begin (); it != end (); it++)
453 {
454 if ((*it) == d_neutral)
455 continue;
456 if ((*it)->isDead () == true)
457 continue;
458 numAlive++;
459 }
460 return numAlive;
461 }
462
negotiateDiplomacy()463 void Playerlist::negotiateDiplomacy()
464 {
465 // hold diplomatic talks, and determine diplomatic outcomes
466 for (iterator pit = begin(); pit != end(); pit++)
467 {
468 if ((*pit)->isDead())
469 continue;
470
471 if ((*pit) == getNeutral())
472 continue;
473
474 for (iterator it = begin(); it != end(); it++)
475 {
476
477 if ((*it)->isDead())
478 continue;
479
480 if ((*it) == getNeutral())
481 continue;
482
483 if ((*it) == (*pit))
484 break;
485
486 Player::DiplomaticState old_state = (*pit)->getDiplomaticState(*it);
487 Player::DiplomaticState new_state = (*pit)->negotiateDiplomacy(*it);
488 (*pit)->declareDiplomacy (new_state, (*it), false);
489 (*pit)->proposeDiplomacy (Player::NO_PROPOSAL, (*it));
490 (*it)->declareDiplomacy (new_state, (*pit), false);
491 (*it)->proposeDiplomacy (Player::NO_PROPOSAL, (*pit));
492 if (old_state != new_state)
493 {
494 Player *me = *pit;
495 Player *them = *it;
496 if (new_state == Player::AT_PEACE)
497 {
498 //their view of me goes up
499 them->improveDiplomaticRelationship(me, 1);
500 //their allies think better of me
501 me->improveAlliesRelationship (them, 1, Player::AT_PEACE);
502 //their enemies think less of me
503 them->deteriorateAlliesRelationship (me, 1, Player::AT_WAR);
504 }
505 else if (new_state == Player::AT_WAR)
506 {
507 //their view of me goes down
508 them->deteriorateDiplomaticRelationship(me, 1);
509 //their allies view of me goes down
510 them->deteriorateAlliesRelationship(me, 1, Player::AT_PEACE);
511 //their enemies view of me goes up
512 me->improveAlliesRelationship(them, 1, Player::AT_WAR);
513 }
514 }
515 }
516 }
517 }
518
swap(Player * old_player,Player * new_player)519 void Playerlist::swap(Player *old_player, Player *new_player)
520 {
521 std::replace(begin(), end(), old_player, new_player);
522 //point cities to the new owner
523 Citylist::getInstance()->changeOwnership (old_player, new_player);
524 Ruinlist::getInstance()->changeOwnership (old_player, new_player);
525 VectoredUnitlist::getInstance()->changeOwnership (old_player, new_player);
526 AI_Analysis::changeOwnership(old_player, new_player);
527 if (old_player == d_activeplayer)
528 {
529 d_activeplayer = new_player;
530 d_activeplayer->setActivestack(0);
531 }
532 if (old_player == viewingplayer)
533 viewingplayer = new_player;
534 d_id[new_player->getId()] = new_player;
535 GameMap::getInstance()->clearStackPositions();
536 GameMap::getInstance()->updateStackPositions();
537 /* note, we don't have to change the player associated with flag graphics
538 because it's stored as an id. */
539 }
540
randomly(const Player * lhs,const Player * rhs)541 bool Playerlist::randomly(const Player *lhs, const Player *rhs)
542 {
543 (void) rhs;
544 if (lhs == Playerlist::getInstance()->getNeutral())
545 return false;
546 if (Rnd::rand() % 2 == 0)
547 return true;
548 else
549 return false;
550 }
551
inOrderOfId(const Player * lhs,const Player * rhs)552 bool Playerlist::inOrderOfId(const Player *lhs, const Player *rhs)
553 {
554 if (lhs->getId() > rhs->getId())
555 return false;
556 else
557 return true;
558 }
559
560 //randomly reorder the player list, but keeping neutral last.
randomizeOrder()561 void Playerlist::randomizeOrder()
562 {
563 sort(randomly);
564 d_activeplayer = NULL;
565 viewingplayer = NULL;
566 }
567
nextRound(bool diplomacy,bool * surrender_already_offered)568 void Playerlist::nextRound(bool diplomacy, bool *surrender_already_offered)
569 {
570 // update diplomacy
571 if (diplomacy)
572 {
573 negotiateDiplomacy();
574 calculateDiplomaticRankings();
575 }
576
577 // update winners
578 calculateWinners();
579
580 // offer surrender
581 if (countHumanPlayersAlive() == 1 &&
582 *surrender_already_offered == 0)
583 {
584 for (iterator it = begin(); it != end(); it++)
585 {
586 if ((*it)->getType() == Player::HUMAN)
587 {
588 int target_level = Citylist::getInstance()->size() / 2;
589 if (Citylist::getInstance()->countCities(*it) > target_level)
590 {
591 *surrender_already_offered = 1;
592 ssurrender.emit(*it);
593 break;
594 }
595 }
596 }
597 }
598 }
599
syncPlayer(GameParameters::Player player)600 void Playerlist::syncPlayer(GameParameters::Player player)
601 {
602 Player *p = getPlayer((guint32)player.id);
603 if (!p)
604 {
605 //player was off originally, but now it's on
606 guint32 armyset = d_neutral->getArmyset();
607 int width = d_neutral->getFogMap()->getWidth();
608 int height = d_neutral->getFogMap()->getHeight();
609 int gold = d_neutral->getGold();
610 Shieldset *shieldset = GameMap::getShieldset();
611 switch (player.type)
612 {
613 case GameParameters::Player::HUMAN:
614 p = new RealPlayer(player.name, armyset,
615 shieldset->getColor(player.id),
616 width, height, Player::HUMAN, player.id);
617 break;
618 case GameParameters::Player::EASY:
619 p = new AI_Fast(player.name, armyset,
620 shieldset->getColor(player.id),
621 width, height, player.id);
622 break;
623 case GameParameters::Player::HARD:
624 p = new AI_Smart(player.name, armyset,
625 shieldset->getColor(player.id),
626 width, height, player.id);
627 break;
628 case GameParameters::Player::OFF:
629 //was off, now it's still off.
630 break;
631 default:
632 std::cerr << String::ucompose("could not make player with type %1", player.type) << std::endl;
633 exit (1);
634 break;
635 }
636 if (p)
637 {
638 p->setGold(gold);
639 add(p);
640
641 sort(inOrderOfId);
642 d_activeplayer = getFirstLiving();
643 updateViewingPlayer();
644 }
645 return;
646 }
647 else
648 p->setName(player.name);
649
650
651 switch (player.type)
652 {
653 case GameParameters::Player::HUMAN:
654 if (p->getType() != Player::HUMAN)
655 {
656 RealPlayer *new_p = new RealPlayer(*p);
657 swap(p, new_p);
658 }
659 break;
660 case GameParameters::Player::EASY:
661 if (p->getType() != Player::AI_FAST)
662 {
663 AI_Fast *new_p = new AI_Fast(*p);
664 swap(p, new_p);
665 }
666 break;
667 case GameParameters::Player::HARD:
668 if (p->getType() != Player::AI_SMART)
669 {
670 AI_Smart *new_p = new AI_Smart(*p);
671 swap(p, new_p);
672 }
673 break;
674 case GameParameters::Player::OFF:
675 {
676 //point owned cities to neutral
677 Citylist::getInstance()->changeOwnership (p, d_neutral);
678 //point owned ruins to neutral
679 Ruinlist::getInstance()->changeOwnership (p, d_neutral);
680 //also copy over the stacks to neutral
681 p->getStacklist()->changeOwnership(p, d_neutral);
682 //now get rid of the player entirely
683 GameMap::getInstance()->clearStackPositions();
684 if (d_id.find(p->getId()) != d_id.end())
685 d_id.erase(d_id.find(p->getId()));
686 flErase(find(begin(), end(), p));
687 GameMap::getInstance()->updateStackPositions();
688 }
689 break;
690 default:
691 std::cerr << String::ucompose("could not sync player with type %1", player.type) << std::endl;
692 exit (1);
693 break;
694 }
695
696 sort(inOrderOfId);
697 d_activeplayer = getFirstLiving();
698 updateViewingPlayer();
699 return;
700 }
701
syncPlayers(std::vector<GameParameters::Player> players)702 void Playerlist::syncPlayers(std::vector<GameParameters::Player> players)
703 {
704 std::vector<GameParameters::Player>::const_iterator i = players.begin();
705 for (; i != players.end(); i++)
706 syncPlayer(*i);
707 }
708
turnHumansIntoNetworkPlayers()709 guint32 Playerlist::turnHumansIntoNetworkPlayers()
710 {
711 guint32 count = 0;
712 std::list<Player*> p;
713 for (iterator i = begin(); i != end(); i++)
714 {
715 if ((*i)->getType() == Player::HUMAN)
716 {
717 count++;
718 NetworkPlayer *new_p = new NetworkPlayer(**i);
719 p.push_back(*i);
720 swap((*i), new_p);
721 i = begin();
722 continue;
723 }
724 }
725 for (std::list<Player*>::iterator j = p.begin(); j != p.end(); j++)
726 delete *j;
727 return count;
728 }
729
turnHumansInto(Player::Type type,int number_of_players)730 guint32 Playerlist::turnHumansInto(Player::Type type, int number_of_players)
731 {
732 int count = 0;
733 for (iterator i = begin(); i != end(); i++)
734 {
735 if (count >= number_of_players && number_of_players > 0)
736 break;
737 if ((*i)->getType() == Player::HUMAN)
738 {
739 switch (type)
740 {
741 case Player::AI_DUMMY:
742 {
743 AI_Dummy *new_p = new AI_Dummy(**i);
744 swap((*i), new_p);
745 //delete *i; fixme
746 i = begin();
747 count++;
748 continue;
749 }
750 break;
751 case Player::AI_FAST:
752 {
753 AI_Fast *new_p = new AI_Fast(**i);
754 swap((*i), new_p);
755 //delete *i; fixme
756 i = begin();
757 count++;
758 continue;
759 }
760 break;
761 case Player::AI_SMART:
762 {
763 AI_Smart *new_p = new AI_Smart(**i);
764 swap((*i), new_p);
765 //delete *i; fixme
766 i = begin();
767 count++;
768 continue;
769 }
770 break;
771 case Player::NETWORKED:
772 {
773 NetworkPlayer *new_p = new NetworkPlayer(**i);
774 swap((*i), new_p);
775 //delete *i; fixme
776 i = begin();
777 count++;
778 continue;
779 }
780 break;
781 case Player::HUMAN:
782 break;
783 }
784 }
785 }
786 return count;
787 }
788
789 std::list<guint32> given_turn_order;
inGivenOrder(const Player * lhs,const Player * rhs)790 bool Playerlist::inGivenOrder(const Player *lhs, const Player *rhs)
791 {
792 if (given_turn_order.size() == 0)
793 return true;
794
795 int count = 0;
796 for(std::list<guint32>::iterator it = given_turn_order.begin();
797 it != given_turn_order.end(); it++)
798 {
799 count++;
800 if (lhs->getId() == (*it))
801 break;
802 }
803 int lhs_rank = count;
804 count = 0;
805 for(std::list<guint32>::iterator it = given_turn_order.begin();
806 it != given_turn_order.end(); it++)
807 {
808 count++;
809 if (rhs->getId() == (*it))
810 break;
811 }
812 int rhs_rank = count;
813 return lhs_rank < rhs_rank;
814 }
815
reorder(std::list<guint32> order)816 void Playerlist::reorder(std::list<guint32> order)
817 {
818 given_turn_order = order;
819 sort(inGivenOrder);
820 given_turn_order.clear();
821 d_activeplayer = getFirstLiving();
822 updateViewingPlayer();
823 }
824
getHistoryForHeroId(guint32 id) const825 std::list<History *>Playerlist::getHistoryForHeroId(guint32 id) const
826 {
827 std::list<History*> no_events;
828 for (const_iterator it = begin(); it != end(); ++it)
829 {
830 std::list<History *>events = (*it)->getHistoryForHeroId(id);
831 if (events.size() > 0)
832 return events;
833 }
834 return no_events;
835 }
836
surrender()837 void Playerlist::surrender()
838 {
839 //the last human player has accepted surrender
840 for (iterator it = begin(); it != end(); it++)
841 {
842 if ((*it)->getType() != Player::HUMAN)
843 (*it)->setSurrendered(true);
844 }
845 }
846
isEndOfRound() const847 bool Playerlist::isEndOfRound() const
848 {
849 //check to see if all players have moved this round.
850 //do all players have the same number of history:end_turn events?
851 if (d_activeplayer == NULL)
852 return false;
853 guint32 count = d_activeplayer->countEndTurnHistoryEntries();
854 for (const_iterator it = begin(); it != end(); it++)
855 {
856 if (*it == d_activeplayer)
857 continue;
858 if (count != (*it)->countEndTurnHistoryEntries())
859 return false;
860 }
861 return true;
862 }
863
setWinningPlayer(Player * winner)864 void Playerlist::setWinningPlayer(Player *winner)
865 {
866 //only for humans
867 d_activeplayer = winner;
868 }
869
getWinningPlayer() const870 Player *Playerlist::getWinningPlayer() const
871 {
872 guint32 best_score = 0;
873 Player *winning_player = NULL;
874 for (const_iterator it = begin(); it != end(); it++)
875 {
876 Player *p = (*it);
877 if (p->isDead() == false)
878 continue;
879 if (p == getNeutral())
880 continue;
881 if (p->getScore() >= best_score)
882 {
883 best_score = p->getScore();
884 winning_player = p;
885 }
886 }
887 return winning_player;
888 }
889
hasArmyset(guint32 id) const890 bool Playerlist::hasArmyset(guint32 id) const
891 {
892 for (const_iterator it = begin(); it != end(); it++)
893 {
894 if ((*it)->getArmyset() == id)
895 return true;
896 }
897 return false;
898 }
899
setNewColours(Shieldset * shieldset)900 void Playerlist::setNewColours(Shieldset *shieldset)
901 {
902 for (iterator it = begin(); it != end(); it++)
903 (*it)->setColor(shieldset->getColor((*it)->getId()));
904 }
905
clearAllActions()906 void Playerlist::clearAllActions()
907 {
908 for (iterator it = begin(); it != end(); it++)
909 (*it)->clearActionlist();
910 }
911
syncNeutral()912 void Playerlist::syncNeutral()
913 {
914 if (d_neutral == NULL)
915 return;
916 if (d_neutral->getType() == Player::AI_DUMMY)
917 return;
918 //okay, let's sync it.
919 Player *p = new AI_Dummy(*d_neutral);
920 swap(d_neutral, p);
921 d_neutral = p;
922 }
923
getStackById(guint32 id) const924 Stack *Playerlist::getStackById(guint32 id) const
925 {
926 //this method checks each stacklist for the given stack id.
927 //the stack ids in each stacklist are in a std::map, so that's how the
928 //stack pointers are gotten.
929 for (const_iterator j = begin(), jend = end(); j != jend; ++j)
930 {
931 Stack *s = (*j)->getStacklist()->getStackById(id);
932 if (s)
933 return s;
934 }
935 return NULL;
936 }
937
updateViewingPlayer()938 void Playerlist::updateViewingPlayer ()
939 {
940 /*
941 * the idea here is that the viewing player is related to the
942 * hidden map.
943 *
944 * imagine a computer player moving and then it walks into the area of
945 * your map that you have uncovered.
946 *
947 * i think the smallmap happens to be getting blanked right now,
948 * but this funciton is about retaining the last human player as the
949 * player who can see movements through his or her territory.
950 *
951 * the blanking of the smallmap/bigmap is because:
952 * it's not really fair to show one player some enemy units going through
953 * his or her territory, and not all players. why should one player be
954 * rewarded in this way just by fluke?
955 *
956 * this is the story for hotseat anyway. i'm not sure how it relates to
957 * network play.
958 */
959 if (d_activeplayer && d_activeplayer->getType() == Player::HUMAN)
960 viewingplayer = d_activeplayer;
961 else
962 viewingplayer = getNeutral();
963 }
964
getTurnOrderNumber(const Player * p)965 guint32 Playerlist::getTurnOrderNumber(const Player *p)
966 {
967 guint32 count = 1;
968 for (const_iterator i = begin(); i != end(); i++)
969 {
970 if ((*i) == p)
971 break;
972 count++;
973 }
974 return count;
975 }
976
countAllStacks() const977 guint32 Playerlist::countAllStacks () const
978 {
979 guint32 count = 0;
980 for (const_iterator i = begin(); i != end(); i++)
981 count += (*i)->getStacklist ()->size ();
982 return count;
983 }
984
playerHasNoCapitalCity() const985 bool Playerlist::playerHasNoCapitalCity () const
986 {
987 for (const_iterator i = begin (); i != end (); i++)
988 if (*i != d_neutral &&
989 Citylist::getInstance ()->getCapitalCity (*i) == NULL)
990 return true;
991 return false;
992 }
993