1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005 Andrea Paternesi
4 // Copyright (C) 2004 John Farrell
5 // Copyright (C) 2005 Bryan Duff
6 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2014, 2015, 2017,
7 // 2020 Ben Asselstine
8 // Copyright (C) 2007, 2008 Ole Laursen
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 // 02110-1301, USA.
24
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <fstream>
28 #include <sstream>
29 #include <sigc++/functors/mem_fun.h>
30
31 #include "MoveResult.h"
32 #include "player.h"
33 #include "playerlist.h"
34 #include "stacklist.h"
35 #include "citylist.h"
36 #include "templelist.h"
37 #include "city.h"
38 #include "path.h"
39 #include "armysetlist.h"
40 #include "real_player.h"
41 #include "ai_dummy.h"
42 #include "ai_fast.h"
43 #include "ai_smart.h"
44 #include "network_player.h"
45 #include "GameMap.h"
46 #include "counter.h"
47 #include "army.h"
48 #include "hero.h"
49 #include "heroproto.h"
50 #include "herotemplates.h"
51 #include "Configuration.h"
52 #include "GameScenarioOptions.h"
53 #include "action.h"
54 #include "network-action.h"
55 #include "history.h"
56 #include "network-history.h"
57 #include "AI_Analysis.h"
58 #include "AI_Allocation.h"
59 #include "FogMap.h"
60 #include "QuestsManager.h"
61 #include "signpost.h"
62 #include "vectoredunit.h"
63 #include "ucompose.hpp"
64 #include "armyprodbase.h"
65 #include "Triumphs.h"
66 #include "Backpack.h"
67 #include "MapBackpack.h"
68 #include "PathCalculator.h"
69 #include "stacktile.h"
70 #include "temple.h"
71 #include "QCityOccupy.h"
72 #include "QCitySack.h"
73 #include "QCityRaze.h"
74 #include "QPillageGold.h"
75 #include "Quest.h"
76 #include "QKillHero.h"
77 #include "QEnemyArmies.h"
78 #include "QEnemyArmytype.h"
79 #include "callback-enums.h"
80 #include "stackreflist.h"
81 #include "SightMap.h"
82 #include "rewardlist.h"
83 #include "Item.h"
84 #include "ItemProto.h"
85 #include "xmlhelper.h"
86 #include "rnd.h"
87 #include "game-actionlist.h"
88 #include "turn-actionlist.h"
89 #include "keeper.h"
90
91 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::flush<<std::endl;}
92 #define debug(x)
93
94 Glib::ustring Player::d_tag = "player";
95
Player(Glib::ustring name,guint32 armyset,Gdk::RGBA color,int width,int height,Type type,int player_no)96 Player::Player(Glib::ustring name, guint32 armyset, Gdk::RGBA color, int width,
97 int height, Type type, int player_no)
98 :d_color(color), d_name(name), d_armyset(armyset), d_gold(1000),
99 d_dead(false), d_immortal(false), d_type(type), d_upkeep(0), d_income(0),
100 d_observable(true), surrendered(false), abort_requested(false)
101 {
102 if (player_no != -1)
103 d_id = player_no;
104 else
105 d_id = fl_counter->getNextId();
106 d_stacklist = new Stacklist();
107 debug("type of " << d_name << " is " << type)
108
109 d_fogmap = new FogMap(width, height);
110
111 //initial fight order is the order in which the armies appear
112 //in the default.xml file.
113 for (auto i: *Armysetlist::getInstance()->get(d_armyset))
114 d_fight_order.push_back(i->getId());
115
116 for (unsigned int i = 0 ; i < MAX_PLAYERS; i++)
117 {
118 d_diplomatic_state[i] = AT_PEACE;
119 d_diplomatic_proposal[i] = NO_PROPOSAL;
120 d_diplomatic_score[i] = DIPLOMACY_STARTING_SCORE;
121 }
122 d_diplomatic_rank = 0;
123 d_diplomatic_title = Glib::ustring("");
124
125 d_triumphs = new Triumphs();
126 }
127
Player(const Player & player)128 Player::Player(const Player& player)
129 :sigc::trackable(player), d_color(player.d_color), d_name(player.d_name),
130 d_armyset(player.d_armyset), d_gold(player.d_gold), d_dead(player.d_dead),
131 d_immortal(player.d_immortal), d_type(player.d_type), d_id(player.d_id),
132 d_fight_order(player.d_fight_order), d_upkeep(player.d_upkeep),
133 d_income(player.d_income), d_observable(player.d_observable),
134 surrendered(player.surrendered),abort_requested(player.abort_requested)
135 {
136 // as the other player is propably dumped somehow, we need to deep copy
137 // everything.
138 d_stacklist = new Stacklist();
139 for (Stacklist::iterator it = player.d_stacklist->begin();
140 it != player.d_stacklist->end(); it++)
141 {
142 Stack* mine = new Stack(**it, true);
143 // change the stack's loyalty
144 mine->setPlayer(this);
145 d_stacklist->add(mine);
146 }
147
148 // copy actions
149 for (auto ait: player.d_actions)
150 d_actions.push_back(Action::copy(ait));
151
152 // copy events
153 for (auto pit: player.d_history)
154 d_history.push_back(History::copy(pit));
155
156 // copy fogmap
157 d_fogmap = new FogMap(*player.getFogMap());
158
159 // copy diplomatic states
160 for (unsigned int i = 0 ; i < MAX_PLAYERS; i++)
161 {
162 d_diplomatic_state[i] = player.d_diplomatic_state[i];
163 d_diplomatic_proposal[i] = player.d_diplomatic_proposal[i];
164 d_diplomatic_score[i] = player.d_diplomatic_score[i];
165 }
166 d_diplomatic_rank = player.d_diplomatic_rank;
167 d_diplomatic_title = player.d_diplomatic_title;
168
169 d_triumphs = new Triumphs(*player.getTriumphs());
170 }
171
Player(XML_Helper * helper)172 Player::Player(XML_Helper* helper)
173 :d_stacklist(0), d_fogmap(0), surrendered(false), abort_requested(false)
174 {
175 helper->getData(d_id, "id");
176 helper->getData(d_name, "name");
177 helper->getData(d_gold, "gold");
178 helper->getData(d_dead, "dead");
179 helper->getData(d_immortal, "immortal");
180 Glib::ustring type_str;
181 helper->getData(type_str, "type");
182 d_type = playerTypeFromString(type_str);
183 helper->getData(d_upkeep, "upkeep");
184 helper->getData(d_income, "income");
185 helper->getData(d_color, "color");
186 helper->getData(d_armyset, "armyset");
187
188 // Read in Fight Order. One ranking per army type.
189 Glib::ustring fight_order;
190 std::stringstream sfight_order;
191 guint32 val;
192 helper->getData(fight_order, "fight_order");
193 sfight_order.str(fight_order);
194 for (auto i: *Armysetlist::getInstance()->get (d_armyset))
195 {
196 (void)i;
197 sfight_order >> val;
198 d_fight_order.push_back(val);
199 }
200
201 // Read in Diplomatic States. One state per player.
202 Glib::ustring diplomatic_states;
203 std::stringstream sdiplomatic_states;
204 helper->getData(diplomatic_states, "diplomatic_states");
205 sdiplomatic_states.str(diplomatic_states);
206 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
207 {
208 sdiplomatic_states >> val;
209 d_diplomatic_state[i] = DiplomaticState(val);
210 }
211
212 helper->getData(d_diplomatic_rank, "diplomatic_rank");
213 helper->getData(d_diplomatic_title, "diplomatic_title");
214
215 // Read in Diplomatic Proposals. One proposal per player.
216 Glib::ustring diplomatic_proposals;
217 std::stringstream sdiplomatic_proposals;
218 helper->getData(diplomatic_proposals, "diplomatic_proposals");
219 sdiplomatic_proposals.str(diplomatic_proposals);
220 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
221 {
222 sdiplomatic_proposals>> val;
223 d_diplomatic_proposal[i] = DiplomaticProposal(val);
224 }
225
226 // Read in Diplomatic Scores. One score per player.
227 Glib::ustring diplomatic_scores;
228 std::stringstream sdiplomatic_scores;
229 helper->getData(diplomatic_scores, "diplomatic_scores");
230 sdiplomatic_scores.str(diplomatic_scores);
231 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
232 {
233 sdiplomatic_scores >> val;
234 d_diplomatic_score[i] = val;
235 }
236 helper->getData(d_observable, "observable");
237
238 helper->registerTag(Action::d_tag, sigc::mem_fun(this, &Player::load));
239 helper->registerTag(History::d_tag, sigc::mem_fun(this, &Player::load));
240 helper->registerTag(Stacklist::d_tag, sigc::mem_fun(this, &Player::load));
241 helper->registerTag(FogMap::d_tag, sigc::mem_fun(this, &Player::load));
242 helper->registerTag(Triumphs::d_tag, sigc::mem_fun(this, &Player::load));
243
244 }
245
~Player()246 Player::~Player()
247 {
248 if (d_stacklist)
249 {
250 delete d_stacklist;
251 d_stacklist = NULL;
252 }
253 if (d_fogmap)
254 {
255 delete d_fogmap;
256 d_fogmap = NULL;
257 }
258
259 delete d_triumphs;
260 d_triumphs = NULL;
261 clearActionlist();
262 clearHistorylist();
263 }
264
create(Glib::ustring name,guint32 armyset,Gdk::RGBA color,int width,int height,Type type)265 Player* Player::create(Glib::ustring name, guint32 armyset, Gdk::RGBA color, int width, int height, Type type)
266 {
267 switch(type)
268 {
269 case HUMAN:
270 return (new RealPlayer(name, armyset, color, width, height));
271 case AI_FAST:
272 return (new AI_Fast(name, armyset, color, width, height));
273 case AI_DUMMY:
274 return (new AI_Dummy(name, armyset, color, width, height));
275 case AI_SMART:
276 return (new AI_Smart(name, armyset, color, width, height));
277 case NETWORKED:
278 return (new NetworkPlayer(name, armyset, color, width, height));
279 }
280
281 return 0;
282 }
283
create(Player * orig,Type type)284 Player* Player::create(Player* orig, Type type)
285 {
286 switch(type)
287 {
288 case HUMAN:
289 return new RealPlayer(*orig);
290 case AI_FAST:
291 return new AI_Fast(*orig);
292 case AI_DUMMY:
293 return new AI_Dummy(*orig);
294 case AI_SMART:
295 return new AI_Smart(*orig);
296 case NETWORKED:
297 return new NetworkPlayer(*orig);
298 }
299
300 return 0;
301 }
302
303
initTurn()304 void Player::initTurn()
305 {
306 //printf("local: dumping %lu actions\n", d_actions.size());
307 //for (auto i: d_actions)
308 //{
309 //printf("\t%s %s\n", Action::actionTypeToString(i->getType()).c_str(), i->dump().c_str());
310 //}
311
312 GameActionlist::getInstance()->add(new TurnActionlist (this, d_actions));
313 clearActionlist();
314 History_StartTurn* item = new History_StartTurn();
315 addHistory(item);
316 guint32 order = Playerlist::getInstance()->getTurnOrderNumber(this);
317 Action_InitTurn* action = new Action_InitTurn(order);
318 addAction(action);
319 }
320
setColor(Gdk::RGBA c)321 void Player::setColor(Gdk::RGBA c)
322 {
323 d_color = c;
324 }
325
addGold(int gold)326 void Player::addGold(int gold)
327 {
328 d_gold += gold;
329 schangingStats.emit();
330 }
331
withdrawGold(int gold)332 void Player::withdrawGold(int gold)
333 {
334 d_gold -= gold;
335 if (d_gold < 0)
336 d_gold = 0; /* bankrupt. should we start turning off city production? */
337 schangingStats.emit();
338 }
339
getName() const340 Glib::ustring Player::getName() const
341 {
342 return d_name;
343 }
344
dumpActionlist() const345 void Player::dumpActionlist() const
346 {
347 for (auto it: d_actions)
348 std::cerr << it->dump() << std::endl;
349 }
350
dumpHistorylist() const351 void Player::dumpHistorylist() const
352 {
353 for (auto it: d_history)
354 std::cerr << it->dump() << std::endl;
355 }
356
clearActionlist()357 void Player::clearActionlist()
358 {
359 for (auto it: d_actions)
360 delete (it);
361 d_actions.clear();
362 }
363
clearHistorylist(std::list<History * > & history)364 void Player::clearHistorylist(std::list<History*> &history)
365 {
366 for (auto it: history)
367 delete (it);
368 history.clear();
369 }
370
clearHistorylist()371 void Player::clearHistorylist()
372 {
373 clearHistorylist(d_history);
374 }
375
addStack(Stack * stack)376 void Player::addStack(Stack* stack)
377 {
378 debug("Player " << getName() << ": Stack Id: " << stack->getId() << " added to stacklist");
379 stack->setPlayer(this);
380 d_stacklist->add(stack);
381 }
382
deleteStack(Stack * stack)383 bool Player::deleteStack(Stack* stack)
384 {
385 if (isComputer() == true)
386 {
387 AI_Analysis::deleteStack(stack->getId());
388 AI_Allocation::deleteStack(stack);
389 }
390 return d_stacklist->flRemove(stack);
391 }
392
kill(bool record_action)393 void Player::kill(bool record_action)
394 {
395 doKill();
396 if (record_action)
397 {
398 addAction(new Action_Kill());
399 if (d_immortal == false)
400 addHistory(new History_PlayerVanquished());
401 }
402 schangingStats.emit();
403 }
404
doKill()405 void Player::doKill()
406 {
407 if (d_immortal)
408 // ignore it
409 return;
410
411 d_observable = false;
412
413 d_dead = true;
414 //drop the bags of stuff that the heroes might be carrying
415 std::list<Hero*> h = getHeroes();
416 for (std::list<Hero*>::iterator it = h.begin(); it != h.end(); it++)
417 {
418 Stack *s = d_stacklist->getArmyStackById((*it)->getId());
419 if (s)
420 doStackDisband(s);
421 }
422 //get rid of all of the other stacks.
423 d_stacklist->flClear();
424
425 // Since in some cases the player can be killed rather innocently
426 // (using reactions), we also need to clear the player's traces in the
427 // single cities
428 for (auto city: *Citylist::getInstance())
429 if (city->getOwner() == this && city->isBurnt() == false)
430 Playerlist::getInstance()->getNeutral()->takeCityInPossession(city);
431
432 d_diplomatic_rank = 0;
433 d_diplomatic_title = Glib::ustring("");
434 }
435
save(XML_Helper * helper) const436 bool Player::save(XML_Helper* helper) const
437 {
438 bool retval = true;
439
440 retval &= helper->saveData("id", d_id);
441 retval &= helper->saveData("name", d_name);
442 retval &= helper->saveData("color", d_color);
443 retval &= helper->saveData("armyset", d_armyset);
444 retval &= helper->saveData("gold", d_gold);
445 retval &= helper->saveData("dead", d_dead);
446 retval &= helper->saveData("immortal", d_immortal);
447 Glib::ustring type_str = playerTypeToString(Player::Type(d_type));
448 retval &= helper->saveData("type", type_str);
449 debug("type of " << d_name << " is " << d_type)
450 retval &= helper->saveData("upkeep", d_upkeep);
451 retval &= helper->saveData("income", d_income);
452
453 // save the fight order, one ranking per army type
454 std::stringstream fight_order;
455 for (std::list<guint32>::const_iterator it = d_fight_order.begin();
456 it != d_fight_order.end(); it++)
457 {
458 fight_order << (*it) << " ";
459 }
460 retval &= helper->saveData("fight_order", fight_order.str());
461
462 // save the diplomatic states, one state per player
463 std::stringstream diplomatic_states;
464 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
465 {
466 diplomatic_states << d_diplomatic_state[i] << " ";
467 }
468 retval &= helper->saveData("diplomatic_states", diplomatic_states.str());
469
470 retval &= helper->saveData("diplomatic_rank", d_diplomatic_rank);
471 retval &= helper->saveData("diplomatic_title", d_diplomatic_title);
472
473 // save the diplomatic proposals, one proposal per player
474 std::stringstream diplomatic_proposals;
475 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
476 {
477 diplomatic_proposals << d_diplomatic_proposal[i] << " ";
478 }
479 retval &= helper->saveData("diplomatic_proposals",
480 diplomatic_proposals.str());
481
482 // save the diplomatic scores, one score per player
483 std::stringstream diplomatic_scores;
484 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
485 {
486 diplomatic_scores << d_diplomatic_score[i] << " ";
487 }
488 retval &= helper->saveData("diplomatic_scores", diplomatic_scores.str());
489
490 retval &= helper->saveData("observable", d_observable);
491
492 //save the actionlist
493 for (auto it: d_actions)
494 retval &= it->save(helper);
495
496 //save the pasteventlist
497 for (auto it: d_history)
498 retval &= it->save(helper);
499
500 retval &= d_stacklist->save(helper);
501 retval &= d_fogmap->save(helper);
502 retval &= d_triumphs->save(helper);
503
504 return retval;
505 }
506
loadPlayer(XML_Helper * helper)507 Player* Player::loadPlayer(XML_Helper* helper)
508 {
509 Type type;
510 Glib::ustring type_str;
511 helper->getData(type_str, "type");
512 type = playerTypeFromString(type_str);
513
514 switch (type)
515 {
516 case HUMAN:
517 return new RealPlayer(helper);
518 case AI_FAST:
519 return new AI_Fast(helper);
520 case AI_SMART:
521 return new AI_Smart(helper);
522 case AI_DUMMY:
523 return new AI_Dummy(helper);
524 case NETWORKED:
525 return new NetworkPlayer(helper);
526 }
527
528 return 0;
529 }
530
load(Glib::ustring tag,XML_Helper * helper)531 bool Player::load(Glib::ustring tag, XML_Helper* helper)
532 {
533 if (tag == Action::d_tag)
534 {
535 Action* action;
536 action = Action::handle_load(helper);
537 d_actions.push_back(action);
538 }
539 if (tag == History::d_tag)
540 {
541 History* history;
542 history = History::handle_load(helper);
543 d_history.push_back(history);
544 }
545
546 if (tag == Stacklist::d_tag)
547 d_stacklist = new Stacklist(helper);
548
549 if (tag == FogMap::d_tag)
550 d_fogmap = new FogMap(helper);
551
552 if (tag == Triumphs::d_tag)
553 d_triumphs = new Triumphs(helper);
554
555 return true;
556 }
557
addAction(Action * action)558 void Player::addAction(Action *action)
559 {
560 d_actions.push_back(action);
561 acting.emit (action, getId());
562 }
563
addHistory(History * history)564 void Player::addHistory(History *history)
565 {
566 d_history.push_back(history);
567 history_written.emit(history, getId());
568 }
569
getScore() const570 guint32 Player::getScore() const
571 {
572 //go get our last published score in the history
573 guint32 score = 0;
574 std::list<History*>::const_reverse_iterator it = d_history.rbegin();
575 for (; it != d_history.rend(); it++)
576 {
577 if ((*it)->getType() == History::SCORE)
578 {
579 score = static_cast<History_Score*>(*it)->getScore();
580 break;
581 }
582 }
583 return score;
584 }
585
calculateUpkeep()586 void Player::calculateUpkeep()
587 {
588 d_upkeep = 0;
589 Stacklist *sl = getStacklist();
590 for (Stacklist::iterator i = sl->begin(), iend = sl->end(); i != iend; ++i)
591 d_upkeep += (*i)->getUpkeep();
592 }
593
calculateIncome()594 void Player::calculateIncome()
595 {
596 d_income = 0;
597 for (auto city: *Citylist::getInstance())
598 if (city->getOwner() == this)
599 d_income += city->getGold();
600 }
601
doSetFightOrder(std::list<guint32> order)602 void Player::doSetFightOrder(std::list<guint32> order)
603 {
604 d_fight_order = order;
605 }
606
setFightOrder(std::list<guint32> order)607 void Player::setFightOrder(std::list<guint32> order)
608 {
609 doSetFightOrder(order);
610
611 addAction(new Action_FightOrder(order));
612 }
613
doStackSplitArmy(Stack * s,Army * a,Stack * & new_stack)614 bool Player::doStackSplitArmy(Stack *s, Army *a, Stack *& new_stack)
615 {
616 new_stack = s->splitArmy(a);
617 if (new_stack != NULL)
618 {
619 debug("1. split stack " << new_stack->getId() << " from stack " << s->getId());
620 addStack(new_stack);
621 supdatingStack.emit(0);
622 return true;
623 }
624 return false;
625 }
626
627
doStackSplitArmies(Stack * stack,std::list<guint32> armies,Stack * & new_stack)628 bool Player::doStackSplitArmies(Stack *stack, std::list<guint32> armies,
629 Stack *& new_stack)
630 {
631 new_stack = stack->splitArmies(armies);
632 if (new_stack != NULL)
633 {
634 addStack(new_stack);
635 return true;
636 }
637 return false;
638 }
639
stackSplitArmies(Stack * stack,std::list<guint32> armies)640 Stack *Player::stackSplitArmies(Stack *stack, std::list<guint32> armies)
641 {
642 Stack *new_stack = NULL;
643 bool retval = doStackSplitArmies(stack, armies, new_stack);
644 if (retval == true)
645 {
646 addAction(new Action_Split(stack, new_stack));
647 addAction(new Action_ReorderArmies(stack));
648 addAction(new Action_ReorderArmies(new_stack));
649 }
650 return new_stack;
651 }
652
stackSplitArmy(Stack * stack,Army * a)653 Stack *Player::stackSplitArmy(Stack *stack, Army *a)
654 {
655 Stack *new_stack = NULL;
656 bool retval = doStackSplitArmy(stack, a, new_stack);
657 if (retval == true)
658 {
659 addAction(new Action_Split(stack, new_stack));
660 addAction(new Action_ReorderArmies(stack));
661 }
662 return new_stack;
663 }
664
doStackJoin(Stack * receiver,Stack * joining)665 void Player::doStackJoin(Stack* receiver, Stack* joining)
666 {
667 receiver->join(joining);
668 deleteStack(joining);
669 //d_stacklist->flRemove(joining);
670
671 d_stacklist->setActivestack(receiver);
672 }
673
stackJoin(Stack * receiver,Stack * joining)674 bool Player::stackJoin(Stack* receiver, Stack* joining)
675 {
676
677 if ((receiver == 0) || (joining == 0))
678 return false;
679 debug("Player::stackJoin("<<receiver->getId()<<","<<joining->getId()<<")");
680
681 assert (receiver->getPos() == joining->getPos());
682 if (GameMap::canJoin(joining, receiver) == false)
683 return false;
684
685 Action_Join *action = new Action_Join (receiver, joining);
686
687 doStackJoin(receiver, joining);
688 addAction(action);
689
690 addAction(new Action_ReorderArmies(receiver));
691
692 supdatingStack.emit(0);
693 return true;
694 }
695
stackSplitAndMove(Stack * s,Stack * & new_stack)696 bool Player::stackSplitAndMove(Stack* s, Stack *& new_stack)
697 {
698 if (s->hasPath() == false)
699 return false;
700 Vector<int> pos = s->getLastReachablePointInPath();
701 if (pos == Vector<int>(-1,-1))
702 return false;
703 Stack *join = GameMap::getFriendlyStack(pos);
704 if (join)
705 return stackSplitAndMoveToJoin(s, join, new_stack);
706 else
707 return stackSplitAndMoveToAttack(s, new_stack);
708 }
709
stackSplitAndMoveToJoin(Stack * s,Stack * join,Stack * & new_stack)710 bool Player::stackSplitAndMoveToJoin(Stack* s, Stack *join, Stack *& new_stack)
711 {
712 //the stack can't get there, but maybe part of the stack can.
713 if (s->hasPath() == false)
714 return false;
715
716 std::list<guint32> ids;
717 ids = s->determineReachableArmies(s->getLastPointInPath());
718 if (ids.size() == 0)
719 return false;
720 //if they're all reachable and we can join, just move them
721 if (ids.size() == s->size() && GameMap::canJoin(s, join) == true)
722 return stackMove(s);
723
724 //let's take who we can fit.
725 if (ids.size() > join->getMaxArmiesToJoin())
726 {
727 int diff = ids.size() - join->getMaxArmiesToJoin();
728 for (int i = 0; i < diff; i++)
729 ids.pop_front();
730 }
731
732 if (ids.size() == 0)
733 return false;
734 if (s->fliesWithItemAndNonFlyersOverWaterOrMountains())
735 return false;
736 //okay, ids.size armies can make the move. but can that tile accept it?
737 new_stack = stackSplitArmies(s, ids);
738 if (new_stack)
739 {
740 setActivestack(new_stack);
741 return stackMove(new_stack);
742 }
743 return false;
744 }
745
stackSplitAndMoveToAttack(Stack * s,Stack * & new_stack)746 bool Player::stackSplitAndMoveToAttack(Stack* s, Stack *& new_stack)
747 {
748 //the stack can't get there, but maybe part of the stack can.
749 if (s->getPath()->empty())
750 return false;
751
752 std::list<guint32> ids;
753 ids = s->determineReachableArmies(s->getLastPointInPath());
754 if (ids.size() == 0)
755 return false;
756 if (ids.size() == s->size())
757 return stackMove(s);
758 if (s->fliesWithItemAndNonFlyersOverWaterOrMountains())
759 return false;
760
761 new_stack = stackSplitArmies(s, ids);
762 if (new_stack)
763 {
764 setActivestack(new_stack);
765 return stackMove(new_stack);
766 }
767 return false;
768 }
769
stackMove(Stack * s)770 bool Player::stackMove(Stack* s)
771 {
772 debug("Player::stackMove(Stack*)")
773
774 if (s->getPath()->empty())
775 {
776 return false;
777 }
778
779 MoveResult *result = stackMove(s, s->getLastPointInPath(), true);
780 bool ret = result->didSomething();//result->moveSucceeded();
781 delete result;
782 result = 0;
783 return ret;
784 }
785
nextStepOnEnemyStackOrCity(Stack * s) const786 bool Player::nextStepOnEnemyStackOrCity(Stack *s) const
787 {
788 Vector<int> dest = s->getFirstPointInPath();
789 if (dest != Vector<int>(-1,-1))
790 {
791 if (GameMap::getEnemyStack(dest))
792 return true;
793 City *enemy = GameMap::getEnemyCity(dest);
794 if (enemy && enemy->isBurnt() == false)
795 return true;
796 }
797 return false;
798 }
799
stackMove(Stack * s,Vector<int> dest)800 MoveResult *Player::stackMove(Stack* s, Vector<int> dest)
801 {
802 if (dest == Vector<int>(-1,-1))
803 return stackMove(s, dest, true);
804 else
805 return stackMove(s, dest, false);
806 }
807
stackMove(Stack * s,Vector<int> dest,bool follow)808 MoveResult *Player::stackMove(Stack* s, Vector<int> dest, bool follow)
809 {
810 bool searched_temple = false;
811 bool searched_ruin = false;
812 bool got_quest = false;
813 bool picked_up = false;
814 debug("Player::stack_move()");
815 //if follow is set to true, follow an already calculated way, else
816 //calculate it here
817
818 smovingStack.emit(s);
819 if (!follow)
820 {
821 s->getPath()->calculate(s, dest);
822 }
823
824 if (s->getPath()->empty())
825 {
826 MoveResult *result = new MoveResult;
827 result->setReachedEndOfPath(true);
828 sstoppingStack.emit();
829 return result;
830 }
831
832 int stepCount = 0;
833 int moves_left = s->getPath()->getMovesExhaustedAtPoint();
834 while (1)
835 {
836 if (abortRequested())
837 {
838 MoveResult *result = new MoveResult;
839 result->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
840 result->setMoveAborted(true);
841 return result;
842 }
843 if (s->getPath()->size() <= 1)
844 break;
845 if (nextStepOnEnemyStackOrCity(s) == true)
846 break;
847
848 bool step = false;
849 step = stackMoveOneStep(s);
850 if (!step)
851 step = stackMoveOneStepOverTooLargeFriendlyStacks(s);
852 if (step)
853 {
854 stepCount++;
855 supdatingStack.emit(0);
856 if (isComputer())
857 {
858 MoveResult *result = new MoveResult;
859 result->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
860 bool stack_died = computerSearch(s, result);
861 searched_temple = result->getComputerSearchedTemple();
862 searched_ruin = result->getComputerSearchedRuin();
863 got_quest = result->getComputerGotQuest();
864 picked_up = result->getComputerPickedUpBag();
865 if (stack_died)
866 return result;
867 else
868 delete result;
869 }
870 moves_left--;
871 if (moves_left == 1)
872 break;
873 }
874 else
875 break;
876 }
877
878 //the idea here is that we're one move away from our destination.
879 //but in some cases we've already reached the end of the path
880 //because a fight has to happen.
881
882 //did we jump over a too large friendly stack to an enemy stack or city?
883
884 //alright, we've walked up to the last place in the path.
885 if (s->getPath()->size() >= 1 && s->enoughMoves())
886 //now look for fight targets, joins etc.
887 {
888
889 Vector<int> pos = s->getFirstPointInPath();
890 City* city = GameMap::getCity(pos);
891 Stack* target = GameMap::getStack(pos);
892
893
894 //first fight_city to avoid ambiguity with fight_army
895 if (city && (city->getOwner() != this) && (!city->isBurnt()))
896 {
897 bool treachery = false;
898 if (this->getDiplomaticState (city->getOwner()) != AT_WAR)
899 {
900 if (streacheryStack.emit (s, city->getOwner(),
901 city->getPos()) == false)
902 {
903 //we decided not to be treacherous
904 s->getPath()->clear();
905 MoveResult *moveResult = new MoveResult;
906 moveResult->setConsideredTreachery(true);
907 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
908 if (isComputer())
909 computerSearch(s, moveResult);
910 sstoppingStack.emit();
911 return moveResult;
912 }
913 else
914 treachery = true;
915 }
916 MoveResult *moveResult = new MoveResult;
917 moveResult->setTreachery(treachery);
918 moveResult->setConsideredTreachery(treachery);
919 if (stackMoveOneStep(s))
920 {
921 stepCount++;
922 }
923 else
924 {
925 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
926 shaltedStack.emit(s);
927 return moveResult;
928 }
929
930 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
931 if (isComputer())
932 computerSearch(s, moveResult);
933
934 Fight::Result result;
935 std::vector<Stack*> def_in_city = city->getDefenders();
936 if (!def_in_city.empty())
937 {
938 // This is a hack to circumvent the limitations of stackFight.
939 if (!target)
940 target = def_in_city[0];
941
942 Fight *fight = stackFight(&s, &target);
943 result = fight->getResult();
944 finishStackFight (fight, &s, &target);
945 delete fight;
946 }
947 else
948 result = Fight::ATTACKER_WON;
949
950 moveResult->setFightResult(result);
951
952 // We may only take the city if we have defeated all defenders
953 if (result == Fight::ATTACKER_WON)
954 {
955 adjustDiplomacyFromConqueringCity(city);
956 conquerCity(city, s);
957 invadeCity(city); //let AIs determine what to do with city
958 shaltedStack.emit(s);
959 }
960 else
961 sstoppingStack.emit();
962
963 cityfight_finished(city, result);
964 supdatingStack.emit(0);
965
966 return moveResult;
967 }
968
969 //another friendly stack => share the tile if we're human
970 else if (target && target->getOwner() == this /*&&
971 getType() == Player::HUMAN*/)
972 {
973 MoveResult *moveResult = new MoveResult;
974 if (stackMoveOneStep(s))
975 stepCount++;
976 else
977 moveResult->setTooLargeStackInTheWay(true);
978
979 supdatingStack.emit(0);
980 shaltedStack.emit(d_stacklist->getActivestack());
981 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
982 if (isComputer())
983 computerSearch(s, moveResult);
984
985 return moveResult;
986 }
987
988 //enemy stack => fight
989 else if (target)
990 {
991 bool treachery = false;
992 if (this->getDiplomaticState (target->getOwner()) == AT_PEACE)
993 {
994 if (streacheryStack.emit (s, target->getOwner(),
995 target->getPos()) == false)
996 {
997 s->getPath()->clear();
998 MoveResult *moveResult = new MoveResult;
999 moveResult->setConsideredTreachery(true);
1000 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
1001 if (isComputer())
1002 computerSearch(s, moveResult);
1003 sstoppingStack.emit();
1004 return moveResult;
1005 }
1006 else
1007 treachery = true;
1008 }
1009 MoveResult *moveResult = new MoveResult;
1010 moveResult->setTreachery(treachery);
1011 moveResult->setConsideredTreachery(treachery);
1012
1013 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
1014 Fight *fight = stackFight(&s, &target);
1015 Fight::Result result = fight->getResult();
1016 moveResult->setFightResult(result);
1017 finishStackFight(fight, &s, &target);
1018 delete fight;
1019 if (result == Fight::ATTACKER_WON)
1020 {
1021 if (stackMoveOneStep(s))
1022 stepCount++;
1023 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
1024 if (isComputer())
1025 computerSearch(s, moveResult);
1026 }
1027
1028 supdatingStack.emit(0);
1029 if (result == Fight::ATTACKER_WON)
1030 shaltedStack.emit(s);
1031 else
1032 sstoppingStack.emit();
1033 return moveResult;
1034 }
1035
1036 //else
1037 if (stackMoveOneStep(s))
1038 {
1039 supdatingStack.emit(0);
1040 stepCount++;
1041 }
1042
1043 shaltedStack.emit(s);
1044
1045 MoveResult *moveResult = new MoveResult;
1046 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
1047 if (isComputer())
1048 computerSearch(s, moveResult);
1049 return moveResult;
1050 }
1051 else if (s->getPath()->size() >= 1 && s->enoughMoves() == false)
1052 {
1053
1054 MoveResult *moveResult = new MoveResult;
1055 moveResult->fillData(s, stepCount, searched_temple, searched_ruin, got_quest, picked_up);
1056 /* if we can't attack a city, don't remember it in the stack's path. */
1057 Vector<int> pos = s->getFirstPointInPath();
1058 City* city = GameMap::getCity(pos);
1059 if (city && city->getOwner() != this && city->isBurnt() == false)
1060 s->clearPath();
1061
1062 if (isComputer())
1063 computerSearch(s, moveResult);
1064 sstoppingStack.emit();
1065 return moveResult;
1066 }
1067
1068 MoveResult *moveResult = new MoveResult;
1069 moveResult->setStepCount(stepCount);
1070 sstoppingStack.emit();
1071 return moveResult;
1072 }
1073
1074
stackMoveOneStepOverTooLargeFriendlyStacks(Stack * s)1075 bool Player::stackMoveOneStepOverTooLargeFriendlyStacks(Stack *s)
1076 {
1077 if (!s)
1078 return false;
1079
1080 if (!s->enoughMoves())
1081 return false;
1082
1083 if (s->getPath()->size() <= 1)
1084 return false;
1085
1086 Vector<int> dest = s->getFirstPointInPath();
1087 Stack *another_stack = GameMap::getStack(dest);
1088 if (!another_stack)
1089 return false;
1090
1091 if (another_stack->getOwner() != s->getOwner())
1092 return false;
1093
1094 if (d_stacklist->canJumpOverTooLargeStack(s) == false)
1095 return false;
1096
1097 Action_Move *a = new Action_Move(s, dest);
1098 s->moveOneStep(true);
1099 a->setMovesLeft(s->getMoves());
1100 a->setHasShip(s->hasShip());
1101 addAction(a);
1102 return true;
1103 }
1104
computerSearch(Stack * s,MoveResult * r)1105 bool Player::computerSearch(Stack *s, MoveResult *r)
1106 {
1107 bool stack_died = false;
1108
1109 Maptile *tile = GameMap::getInstance()->getTile(s->getPos());
1110
1111 if (tile->getBackpack()->size() > 0)
1112 {
1113 if (computerChoosePickupBag(s, s->getPos(), 0, 0) == true)
1114 {
1115 r->setComputerPickedUpBag(true);
1116 Hero *hero = static_cast<Hero*>(s->getFirstHero());
1117 if (hero)
1118 heroPickupAllItems(hero, s->getPos());
1119 }
1120 }
1121
1122 //are we at a computer and happen to be a temple, or ruin?
1123 if (GameMap::can_search(s) == false)
1124 return false;
1125
1126 if (tile->getBuilding() == Maptile::TEMPLE)
1127 {
1128 if (s->hasHero())
1129 {
1130 if (computerChooseVisitTempleForQuest(s, s->getPos(), 0, 0) == true)
1131 {
1132 r->setComputerSearchedTemple(true);
1133 svisitingTemple.emit(GameMap::getTemple(s->getPos()), s);
1134 }
1135 }
1136 else
1137 {
1138 if (computerChooseVisitTempleForBlessing(s, s->getPos(), 0, 0) == true)
1139 {
1140 r->setComputerSearchedTemple(true);
1141 bool got_quest =
1142 svisitingTemple.emit(GameMap::getTemple(s->getPos()), s);
1143 r->setComputerGotQuest(got_quest);
1144 }
1145 }
1146 }
1147 else if (tile->getBuilding() == Maptile::RUIN)
1148 {
1149 if (s->hasHero() == true)
1150 {
1151 if (computerChooseVisitRuin(s, s->getPos(), 0, 0) == true)
1152 {
1153 r->setComputerSearchedRuin(true);
1154 guint32 oldsize = s->size();
1155 stack_died =
1156 ssearchingRuin.emit(GameMap::getRuin(s->getPos()), s);
1157 if (stack_died)
1158 r->setRuinFightResult(Fight::DEFENDER_WON);
1159 else
1160 {
1161 if (oldsize >= s->size())
1162 r->setRuinFightResult(Fight::ATTACKER_WON);
1163 else
1164 r->setRuinFightResult(Fight::DEFENDER_WON);
1165 }
1166 }
1167 }
1168 }
1169 return stack_died;
1170 }
1171
stackMoveOneStep(Stack * s)1172 bool Player::stackMoveOneStep(Stack* s)
1173 {
1174 if (!s)
1175 return false;
1176
1177 if (!s->enoughMoves())
1178 return false;
1179
1180 Vector<int> dest = s->getFirstPointInPath();
1181
1182 Stack *another_stack = GameMap::getStack(dest);
1183 if (another_stack)
1184 {
1185 if (another_stack->getOwner() == s->getOwner())
1186 {
1187 if (GameMap::canJoin(s,another_stack) == false)
1188 return false;
1189 }
1190 else
1191 {
1192 //if we're attacking, then jump onto the square with the enemy.
1193 if (s->getPath()->size() != 1)
1194 return false;
1195 }
1196
1197 }
1198 Action_Move *a = new Action_Move(s, dest);
1199
1200 s->moveOneStep();
1201 a->setMovesLeft(s->getMoves());
1202 a->setHasShip(s->hasShip());
1203 addAction(a);
1204
1205
1206 return true;
1207 }
1208
cleanupAfterFight(std::list<Stack * > & attackers,std::list<Stack * > & defenders,std::list<History * > & attacker_history,std::list<History * > & defender_history)1209 void Player::cleanupAfterFight(std::list<Stack*> &attackers,
1210 std::list<Stack*> &defenders,
1211 std::list<History*> &attacker_history,
1212 std::list<History*> &defender_history)
1213 {
1214 // get attacker and defender heroes and more...
1215 std::vector<guint32> attackerHeroes, defenderHeroes;
1216
1217 getHeroes(attackers, attackerHeroes);
1218 getHeroes(defenders, defenderHeroes);
1219
1220 // here we calculate also the total XP to add when a player have a battle
1221 // clear dead defenders
1222 //
1223 double defender_xp = countXPFromDeadArmies(defenders);
1224 debug("clean dead defenders");
1225 removeDeadArmies(defenders, attackerHeroes, defender_history);
1226
1227 // and dead attackers
1228 double attacker_xp = countXPFromDeadArmies(attackers);
1229 debug("clean dead attackers");
1230 removeDeadArmies(attackers, defenderHeroes, attacker_history);
1231
1232 debug("after fight: attackers empty? " << attackers.empty()
1233 << "(" << attackers.size() << ")");
1234
1235 if (!attackers.empty() && defender_xp != 0)
1236 updateArmyValues(attackers, defender_xp);
1237
1238 if (!defenders.empty() && attacker_xp != 0)
1239 updateArmyValues(defenders, attacker_xp);
1240
1241 supdatingStack.emit(0);
1242 }
1243
stackFight(Stack ** attacker,Stack ** defender)1244 Fight* Player::stackFight(Stack** attacker, Stack** defender)
1245 {
1246 debug("stackFight: player = " << getName()<<" at position "
1247 <<(*defender)->getPos().x<<","<<(*defender)->getPos().y << " with stack " << (*attacker)->getId() << " against " << (*defender)->getId() << " which is player = " <<(*defender)->getOwner()->getName());
1248
1249 // I suppose, this should be always true, but one can never be sure
1250 bool attacker_active = *attacker == d_stacklist->getActivestack();
1251 if (attacker_active == false && (*attacker)->getOwner()->isComputer() == true)
1252 {
1253 assert(0);
1254 }
1255
1256 Fight *fight = new Fight(*attacker, *defender);
1257 fight->battle(GameScenarioOptions::s_intense_combat);
1258 // add a fight item about the combat
1259 addAction(new Action_Fight(fight));
1260
1261 fight_started.emit(*fight);
1262 return fight;
1263 }
1264
finishStackFight(Fight * fight,Stack ** attacker,Stack ** defender)1265 void Player::finishStackFight (Fight *fight, Stack **attacker, Stack **defender)
1266 {
1267 std::list<Stack *> attackers = fight->getAttackers(),
1268 defenders = fight->getDefenders();
1269
1270 Player* pd = (*defender)->getOwner();
1271 bool attacker_active = *attacker == d_stacklist->getActivestack();
1272 std::list<History*> attacker_history;
1273 std::list<History*> defender_history;
1274 cleanupAfterFight(attackers, defenders, attacker_history, defender_history);
1275
1276 for (std::list<History*>::iterator i = attacker_history.begin();
1277 i != attacker_history.end(); i++)
1278 addHistory(*i);
1279 for (std::list<History*>::iterator i = defender_history.begin();
1280 i != defender_history.end(); i++)
1281 addHistory(*i);
1282
1283 for (std::list<Stack*>::iterator i = attackers.begin();
1284 i != attackers.end(); i++)
1285 addAction(new Action_ReorderArmies(*i));
1286
1287 for (std::list<Stack*>::iterator i = defenders.begin();
1288 i != defenders.end(); i++)
1289 addAction(new Action_ReorderArmies(*i));
1290
1291 // Set the attacker and defender stack to 0 if neccessary. This is a great
1292 // help for the functions calling stackFight (e.g. if a stack attacks
1293 // another stack and destroys it without winning the battle, it may take the
1294 // position of this stack)
1295
1296 // First, the attacker...
1297 bool exists =
1298 std::find(d_stacklist->begin(), d_stacklist->end(), *attacker)
1299 != d_stacklist->end();
1300
1301 if (!exists)
1302 {
1303 (*attacker) = 0;
1304 if (attacker_active)
1305 d_stacklist->setActivestack(0);
1306 }
1307
1308 // ...then the defender.
1309 exists = false;
1310 if (pd)
1311 exists =
1312 std::find(pd->getStacklist()->begin(), pd->getStacklist()->end(),
1313 *defender) != pd->getStacklist()->end();
1314 else
1315 exists = true;
1316 if (!exists)
1317 (*defender) = 0;
1318
1319 schangingStats.emit();
1320 return;
1321 }
1322
1323 /*
1324 *
1325 * To help factor in the advantage of hero experience/strength and
1326 * ruin-monster strength as well as the stack strength, I think you'll
1327 * find it'll be easier to calculate in terms of the odds of failure [than
1328 * the odds of success]. A new hero (minimum strength) with nothing in
1329 * the stack to help him might have 10-20% odds of failure at a wimpy ruin.
1330 * The same novice hero facing a dragon in the ruin might have 50% odds of
1331 * failure. So a rule of thumb would be to start with a 25% chance of
1332 * failure. The odds would be doubled by the worst monster and halved by
1333 * the easiest. I agree that a strength-9 hero with 8 in the stack should i
1334 * definitely be at 99%. A reasonable formula might be:
1335 *
1336 * OddsOfFailure = BaseOdds * MonsterFactor * StackFactor * HeroFactor,
1337 *
1338 * with
1339 * BaseOdds = 0.10
1340 * and
1341 * MonsterFactor = 2, 1 or 0.5 depending on hard vs. easy
1342 * and
1343 * StackFactor = (9 - SizeOfStack)/8,
1344 * and
1345 * HeroFactor = (10-StrengthOfHero)/5.
1346 */
ruinfight(Stack ** attacker,Stack ** defender)1347 Fight::Result ruinfight (Stack **attacker, Stack **defender)
1348 {
1349 Stack *loser;
1350 Fight::Result result;
1351 guint32 hero_strength, monster_strength;
1352 hero_strength = (*attacker)->getFirstHero()->getStat(Army::STRENGTH, true);
1353 monster_strength = (*defender)->getStrongestArmy()->getStat(Army::STRENGTH, true);
1354 float base_factor = 0.28;
1355 float stack_factor = ((float)(MAX_STACK_SIZE + 1) - (*attacker)->size()) / (float)MAX_STACK_SIZE;
1356 float hero_factor = (10.0 - hero_strength) / 5.0;
1357 float monster_factor;
1358 if (monster_strength >= 8)
1359 monster_factor = 2.0;
1360 else if (monster_strength >= 6)
1361 monster_factor = 1.0;
1362 else
1363 monster_factor = 0.5;
1364 float fail = base_factor * monster_factor * stack_factor * hero_factor;
1365
1366 if (Rnd::rand() % 100 > fail * 100.0)
1367 {
1368 result = Fight::ATTACKER_WON;
1369 loser = *defender;
1370 for (Stack::iterator sit = loser->begin(); sit != loser->end();)
1371 {
1372 (*sit)->setHP (0);
1373 sit++;
1374 }
1375 }
1376 else
1377 {
1378 result = Fight::DEFENDER_WON;
1379 loser = *attacker;
1380 loser->getFirstHero()->setHP(0); /* only the hero dies */
1381 }
1382
1383 return result;
1384 }
1385
stackRuinFight(Stack ** attacker,Keeper * defender,bool & stackdied,std::list<History * > & attacker_history,std::list<History * > & defender_history)1386 Fight::Result Player::stackRuinFight (Stack **attacker, Keeper *defender,
1387 bool &stackdied,
1388 std::list<History*> &attacker_history,
1389 std::list<History*> &defender_history)
1390 {
1391 Fight::Result result = Fight::DRAW;
1392 if (defender->getStack () == NULL)
1393 return Fight::ATTACKER_WON;
1394 debug("stackRuinFight: player = " << getName()<<" at position "
1395 <<(*defender)->getStack ()->getPos().x<<","<<(*defender)->getStack ()->getPos().y);
1396
1397 ruinfight_started.emit(*attacker, defender);
1398 Stack *defender_stack = defender->getStack ();
1399 result = ruinfight (attacker, &defender_stack);
1400
1401 ruinfight_finished.emit(result);
1402 // cleanup
1403
1404 // get attacker and defender heroes and more...
1405 std::list<Stack*> attackers;
1406 attackers.push_back(*attacker);
1407 std::list<Stack*> defenders;
1408 defenders.push_back(defender_stack);
1409
1410 cleanupAfterFight(attackers, defenders, attacker_history, defender_history);
1411 bool exists =
1412 std::find(d_stacklist->begin(), d_stacklist->end(), *attacker)
1413 != d_stacklist->end();
1414
1415 if (!exists)
1416 {
1417 (*attacker) = 0;
1418 stackdied = true;
1419 }
1420 else
1421 stackdied = false;
1422
1423 schangingStats.emit();
1424 return result;
1425 }
1426
doStackSearchRuin(Stack * s,Ruin * r,Fight::Result result)1427 void Player::doStackSearchRuin(Stack *s, Ruin *r, Fight::Result result)
1428 {
1429 if (result == Fight::DEFENDER_WON)
1430 {
1431 r->setSearched(false);
1432 return;
1433 }
1434 else if (result == Fight::ATTACKER_WON)
1435 {
1436 r->setSearched(true);
1437 r->clearOccupant();
1438 r->setOwner(s->getOwner());
1439 }
1440 return;
1441 }
1442
stackSearchRuin(Stack * s,Ruin * r,bool & stackdied)1443 Reward* Player::stackSearchRuin(Stack* s, Ruin* r, bool &stackdied)
1444 {
1445 std::list<History*> attacker_history;
1446 std::list<History*> defender_history;
1447 Keeper *keeper = r->getOccupant();
1448 if (keeper)
1449 {
1450 Fight::Result result = stackRuinFight(&s, keeper, stackdied,
1451 attacker_history, defender_history);
1452 //we delete it here because keepers are not in any players' stacklist.
1453 if (result == Fight::ATTACKER_WON)
1454 delete keeper;
1455 for (std::list<History*>::iterator i = attacker_history.begin();
1456 i != attacker_history.end(); i++)
1457 addHistory(*i);
1458 clearHistorylist(defender_history);
1459
1460 if (result == Fight::ATTACKER_WON &&
1461 r->getReward() == NULL && r->hasSage() == false)
1462 r->populateWithRandomReward();
1463 doStackSearchRuin(s, r, result);
1464 if (result == Fight::DEFENDER_WON)
1465 {
1466 addAction(new Action_Ruin(r,s));
1467 return NULL;
1468 }
1469 }
1470 else
1471 {
1472 if (r->getReward() == NULL && r->hasSage() == false)
1473 r->populateWithRandomReward();
1474 doStackSearchRuin(s, r, Fight::ATTACKER_WON);
1475 }
1476
1477 Reward *reward = r->takeReward();
1478 addAction(new Action_Ruin(r, s));
1479 if (r->isSearched())
1480 {
1481 if (r->hasSage())
1482 addHistory(new History_FoundSage(dynamic_cast<Hero *>(s->getFirstHero())));
1483 addHistory(new History_HeroRuinExplored(dynamic_cast<Hero*>(s->getFirstHero()), r));
1484 }
1485 supdatingStack.emit(0);
1486 return reward;
1487 }
1488
doStackVisitTemple(Stack * s)1489 int Player::doStackVisitTemple(Stack *s)
1490 {
1491 // you have your stack blessed (+1 strength)
1492 int count = s->bless();
1493
1494 supdatingStack.emit(0);
1495
1496 return count;
1497 }
1498
stackVisitTemple(Stack * s,Temple * t)1499 int Player::stackVisitTemple(Stack* s, Temple* t)
1500 {
1501 debug("Player::stackVisitTemple");
1502
1503 addAction(new Action_Temple(t,s));
1504
1505 return doStackVisitTemple(s);
1506 }
1507
doHeroGetQuest(Hero * hero,bool except_raze)1508 Quest* Player::doHeroGetQuest(Hero *hero, bool except_raze)
1509 {
1510 std::vector<Quest*> quests =
1511 QuestsManager::getInstance()->getPlayerQuests(Playerlist::getActiveplayer());
1512 if (quests.size() > 0 && GameScenarioOptions::s_play_with_quests == GameParameters::ONE_QUEST_PER_PLAYER)
1513 return NULL;
1514
1515 Quest *q = NULL;
1516 if (hero)
1517 q = QuestsManager::getInstance()->createNewQuest (hero->getId(), except_raze);
1518
1519 supdatingStack.emit(0);
1520 // couldn't assign a quest for various reasons
1521 if (!q)
1522 return NULL;
1523 return q;
1524 }
1525
heroGetQuest(Hero * hero,Temple * t,bool except_raze)1526 Quest* Player::heroGetQuest(Hero *hero, Temple* t, bool except_raze)
1527 {
1528 debug("Player::stackGetQuest")
1529 (void) t;
1530 Quest *q = doHeroGetQuest(hero, except_raze);
1531 if (q == NULL)
1532 return q;
1533
1534 // Now fill the action item
1535 addAction(new Action_Quest(q));
1536
1537 // and record it for posterity
1538 addHistory(new History_HeroQuestStarted(hero));
1539 return q;
1540 }
1541
stackFightAdvise(Stack * s,Vector<int> tile,bool intense_combat)1542 float Player::stackFightAdvise(Stack* s, Vector<int> tile,
1543 bool intense_combat)
1544 {
1545 float percent = 0.0;
1546
1547 City* city = GameMap::getCity(tile);
1548 Stack* target = GameMap::getEnemyStack(tile);
1549
1550 if (!target && city)
1551 {
1552 std::vector<Stack*> def_in_city = city->getDefenders();
1553 if (def_in_city.empty())
1554 return 100.0;
1555 target = def_in_city[0];
1556 }
1557
1558 //what chance is there that stack will defeat defenders?
1559
1560 for (unsigned int i = 0; i < 100; i++)
1561 {
1562 Fight fight(s, target, Fight::FOR_KICKS);
1563 fight.battle(intense_combat);
1564 if (fight.getResult() == Fight::ATTACKER_WON)
1565 percent += 1.0;
1566 }
1567
1568 advice_asked.emit(percent);
1569 return percent;
1570 }
1571
adjustDiplomacyFromConqueringCity(City * city)1572 void Player::adjustDiplomacyFromConqueringCity(City *city)
1573 {
1574 Player *defender = city->getOwner();
1575
1576 // See if this is the last city for that player, and alter the
1577 // diplomatic scores.
1578 if (Citylist::getInstance()->countCities(defender) == 1)
1579 {
1580 if (defender->getDiplomaticRank() < getDiplomaticRank())
1581 deteriorateDiplomaticRelationship (2);
1582 else if (defender->getDiplomaticRank() > getDiplomaticRank())
1583 improveDiplomaticRelationship (2, defender);
1584 }
1585 }
1586
calculateLoot(Player * looted,guint32 & added,guint32 & subtracted)1587 void Player::calculateLoot(Player *looted, guint32 &added, guint32 &subtracted)
1588 {
1589 Player *defender = looted;
1590
1591 // if the attacked city isn't neutral, loot some gold
1592 if (defender != Playerlist::getInstance()->getNeutral())
1593 {
1594 int amt = (defender->getGold() /
1595 (2 * (Citylist::getInstance()->countCities (defender)+1)) * 2);
1596 // give (Enemy-Gold/(2Enemy-Cities)) to the attacker
1597 // and then take away twice that from the defender.
1598 // the idea here is that some money is taken in the invasion
1599 // and other monies are lost forever
1600 // NOTE: +1 because the looted player just lost a city
1601 subtracted = amt;
1602 amt /= 2;
1603 added = amt;
1604 }
1605
1606 return;
1607 }
1608
doConquerCity(City * city)1609 void Player::doConquerCity(City *city)
1610 {
1611 takeCityInPossession(city);
1612 }
1613
1614 //this helps us test.
conquerAllCities()1615 void Player::conquerAllCities()
1616 {
1617 for (auto city: *Citylist::getInstance())
1618 {
1619 if (city->getOwner() != this)
1620 {
1621 for (auto stack: city->getDefenders())
1622 GameMap::getInstance()->removeStack(stack);
1623 conquerCity (city, NULL);
1624 }
1625 }
1626 }
1627
conquerCity(City * city,Stack * stack)1628 void Player::conquerCity(City *city, Stack *stack)
1629 {
1630 /*
1631 fixme:
1632 there is some weirdness here where we conquer the initial cities twice.
1633 we have to make sure it works with the city history report dialog,
1634 and getFirstCity.
1635 i guess the histories are getting erased somewhere after we conquer
1636 the city the first time.
1637 */
1638 Player *original_owner = city->getOwner();
1639 Action_ConquerCity *action = new Action_ConquerCity(city);
1640
1641 doConquerCity(city);
1642 addAction(action);
1643 addHistory(new History_CityWon(city));
1644 if (stack && stack->hasHero())
1645 {
1646 Hero *hero = dynamic_cast<Hero *>(stack->getFirstHero());
1647 addHistory(new History_HeroCityWon(city, hero));
1648 }
1649 if (original_owner != this)
1650 lootCity(city, original_owner);
1651 }
1652
lootCity(City * city,Player * looted)1653 void Player::lootCity(City *city, Player *looted)
1654 {
1655 guint32 added = 0;
1656 guint32 subtracted = 0;
1657 calculateLoot(looted, added, subtracted);
1658 sinvadingCity.emit(city, added);
1659 doLootCity(looted, added, subtracted);
1660 addAction(new Action_Loot(this, looted, added, subtracted));
1661 return;
1662 }
1663
doLootCity(Player * looted,guint32 added,guint32 subtracted)1664 void Player::doLootCity(Player *looted, guint32 added, guint32 subtracted)
1665 {
1666 addGold(added);
1667 looted->withdrawGold(subtracted);
1668 return;
1669 }
1670
takeCityInPossession(City * c)1671 void Player::takeCityInPossession(City* c)
1672 {
1673 c->conquer(this);
1674
1675 //set the production to the cheapest armytype
1676 c->setActiveProductionSlot(-1);
1677 if (c->getArmytype(0) != -1)
1678 c->setActiveProductionSlot(0);
1679
1680 supdatingCity.emit(c);
1681 }
1682
doCityOccupy(City * c)1683 void Player::doCityOccupy(City *c)
1684 {
1685 assert (c->getOwner() == this);
1686
1687 soccupyingCity.emit(c, getActivestack());
1688 QuestsManager::getInstance()->cityOccupied(c, getActivestack());
1689 }
1690
cityOccupy(City * c)1691 void Player::cityOccupy(City* c)
1692 {
1693 debug("cityOccupy");
1694 doCityOccupy(c);
1695
1696 addAction(new Action_Occupy(c));
1697 }
1698
doCityPillage(City * c,int & gold,int * pillaged_army_type)1699 void Player::doCityPillage(City *c, int& gold, int* pillaged_army_type)
1700 {
1701 gold = 0;
1702 if (pillaged_army_type)
1703 *pillaged_army_type = -1;
1704
1705 // get rid of the most expensive army type and trade it in for
1706 // half it's cost
1707 // it is presumed that the last army type is the most expensive
1708
1709 if (c->getNoOfProductionBases() > 0)
1710 {
1711 unsigned int i;
1712 unsigned int max_cost = 0;
1713 int slot = -1;
1714 for (i = 0; i < c->getNoOfProductionBases(); i++)
1715 {
1716 const ArmyProdBase *a = c->getProductionBase(i);
1717 if (a != NULL)
1718 {
1719 if (a->getNewProductionCost() == 0)
1720 {
1721 slot = i;
1722 break;
1723 }
1724 if (a->getNewProductionCost() > max_cost)
1725 {
1726 max_cost = a->getNewProductionCost();
1727 slot = i;
1728 }
1729 }
1730 }
1731 if (slot > -1)
1732 {
1733 const ArmyProdBase *a = c->getProductionBase(slot);
1734 if (pillaged_army_type)
1735 *pillaged_army_type = a->getTypeId();
1736 if (a->getNewProductionCost() == 0)
1737 gold += 1500;
1738 else
1739 gold += a->getNewProductionCost() / 2;
1740 c->removeProductionBase(slot);
1741 }
1742 addGold(gold);
1743 Stack *s = getActivestack();
1744 spillagingCity.emit(c, s, gold, *pillaged_army_type);
1745 QuestsManager::getInstance()->cityPillaged(c, s, gold);
1746 }
1747
1748 }
1749
cityPillage(City * c,int & gold,int * pillaged_army_type)1750 void Player::cityPillage(City* c, int& gold, int* pillaged_army_type)
1751 {
1752 debug("Player::cityPillage");
1753
1754 addAction(new Action_Pillage(c));
1755
1756 doCityPillage(c, gold, pillaged_army_type);
1757 }
1758
doCitySack(City * c,int & gold,std::list<guint32> * sacked_types)1759 void Player::doCitySack(City* c, int& gold, std::list<guint32> *sacked_types)
1760 {
1761 gold = 0;
1762 //trade in all of the army types except for one
1763 //presumes that the army types are listed in order of expensiveness
1764
1765 if (c->getNoOfProductionBases() > 1)
1766 {
1767 const ArmyProdBase *a;
1768 unsigned int i, max = 0;
1769 for (i = 0; i < c->getNoOfProductionBases(); i++)
1770 {
1771 a = c->getProductionBase(i);
1772 if (a)
1773 max++;
1774 }
1775
1776 i = c->getNoOfProductionBases() - 1;
1777 while (max > 1)
1778 {
1779 a = c->getProductionBase(i);
1780 if (a != NULL)
1781 {
1782 sacked_types->push_back(a->getTypeId());
1783 if (a->getNewProductionCost() == 0)
1784 gold += 1500;
1785 else
1786 gold += a->getNewProductionCost() / 2;
1787 c->removeProductionBase(i);
1788 max--;
1789 }
1790 i--;
1791 }
1792 }
1793
1794 addGold(gold);
1795 Stack *s = getActivestack();
1796 ssackingCity.emit(c, s, gold, *sacked_types);
1797 QuestsManager::getInstance()->citySacked(c, s, gold);
1798 }
1799
citySack(City * c,int & gold,std::list<guint32> * sacked_types)1800 void Player::citySack(City* c, int& gold, std::list<guint32> *sacked_types)
1801 {
1802 debug("Player::citySack");
1803
1804 addAction(new Action_Sack(c));
1805
1806 doCitySack(c, gold, sacked_types);
1807 }
1808
doCityRaze(City * c)1809 void Player::doCityRaze(City *c)
1810 {
1811 c->conquer(this);
1812 c->setBurnt(true);
1813
1814 supdatingCity.emit(c);
1815
1816 srazingCity.emit(c, getActivestack());
1817 QuestsManager::getInstance()->cityRazed(c, getActivestack());
1818 }
1819
cityRaze(City * c)1820 void Player::cityRaze(City* c)
1821 {
1822 debug("Player::cityRaze");
1823
1824 addAction(new Action_Raze(c));
1825
1826 addHistory(new History_CityRazed(c));
1827
1828 doCityRaze(c);
1829 }
1830
doCityBuyProduction(City * c,int slot,int type)1831 void Player::doCityBuyProduction(City* c, int slot, int type)
1832 {
1833 guint32 as = c->getOwner()->getArmyset();
1834
1835 c->removeProductionBase(slot);
1836 c->addProductionBase(slot, new ArmyProdBase
1837 (*Armysetlist::getInstance()->getArmy(as, type)));
1838
1839 // and do the rest of the neccessary actions
1840 withdrawGold(Armysetlist::getInstance()->getArmy(as, type)->getNewProductionCost());
1841 }
1842
cityBuyProduction(City * c,int slot,int type)1843 bool Player::cityBuyProduction(City* c, int slot, int type)
1844 {
1845 guint32 as = c->getOwner()->getArmyset();
1846
1847 // sort out unusual values (-1 is allowed and means "scrap production")
1848 if (type <= -1 || Armysetlist::getInstance()->getArmy(d_armyset, type) == NULL)
1849 return false;
1850
1851 // return if we don't have enough money
1852 if (type != -1 &&
1853 (int)Armysetlist::getInstance()->getArmy(as, type)->getNewProductionCost() > d_gold)
1854 return false;
1855
1856 // return if the city already has the production
1857 if (c->hasProductionBase(type))
1858 return false;
1859
1860 // can't put it in that slot
1861 if (slot >= (int)c->getMaxNoOfProductionBases())
1862 return false;
1863
1864 addAction(new Action_Buy (c, slot, Armysetlist::getInstance()->getArmy(as, type)));
1865
1866 doCityBuyProduction(c, slot, type);
1867
1868 return true;
1869 }
1870
doCityChangeProduction(City * c,int slot)1871 void Player::doCityChangeProduction(City* c, int slot)
1872 {
1873 c->setActiveProductionSlot(slot);
1874 if (slot < 0)
1875 c->setVectoring(Vector<int>(-1,-1));
1876 }
1877
cityChangeProduction(City * c,int slot)1878 bool Player::cityChangeProduction(City* c, int slot)
1879 {
1880 doCityChangeProduction(c, slot);
1881 addAction(new Action_Production(c, slot));
1882 return true;
1883 }
1884
doGiveReward(Stack * s,Reward * reward,StackReflist * stacks)1885 void Player::doGiveReward(Stack *s, Reward *reward, StackReflist *stacks)
1886 {
1887 switch (reward->getType())
1888 {
1889 case Reward::GOLD:
1890 addGold(dynamic_cast<Reward_Gold*>(reward)->getGold());
1891 break;
1892 case Reward::ALLIES:
1893 {
1894 const ArmyProto *a = dynamic_cast<Reward_Allies*>(reward)->getArmy();
1895
1896 Reward_Allies::addAllies(s->getOwner(), s->getPos(), a,
1897 dynamic_cast<Reward_Allies*>(reward)->getNoOfAllies(), stacks);
1898 }
1899 break;
1900 case Reward::ITEM:
1901 {
1902 Item *i = new Item (*dynamic_cast<Reward_Item*>(reward)->getItem());
1903 Hero *hero = static_cast<Hero*>(s->getFirstHero());
1904 hero->getBackpack()->addToBackpack(i);
1905 }
1906 break;
1907 case Reward::RUIN:
1908 {
1909 //assign the hidden ruin to this player
1910 Ruin *r = dynamic_cast<Reward_Ruin*>(reward)->getRuin();
1911 r->setHidden(true);
1912 r->setOwner(this);
1913 r->deFog(this);
1914 }
1915 break;
1916 case Reward::MAP:
1917 {
1918 Reward_Map *map = dynamic_cast<Reward_Map*>(reward);
1919 d_fogmap->alterFog(map->getSightMap());
1920 }
1921 break;
1922 }
1923 }
1924
giveReward(Stack * s,Reward * reward,StackReflist * stacks,bool quest)1925 bool Player::giveReward(Stack *s, Reward *reward, StackReflist *stacks, bool quest)
1926 {
1927 debug("Player::give_reward");
1928
1929 Action_Reward *action = new Action_Reward(s, reward);
1930 doGiveReward(s, reward, stacks);
1931
1932 addAction(action);
1933
1934 if (reward->getType() == Reward::RUIN && !quest)
1935 {
1936 Ruin *r = dynamic_cast<Reward_Ruin*>(reward)->getRuin();
1937 addHistory(new History_HeroRewardRuin(dynamic_cast<Hero*>(s->getFirstHero()), r));
1938 }
1939 schangingStats.emit();
1940 return true;
1941 }
1942
doStackDisband(Stack * s)1943 bool Player::doStackDisband(Stack* s)
1944 {
1945 getStacklist()->setActivestack(0);
1946 s->kill();
1947 std::list<History*> history;
1948 removeDeadArmies(s, history);
1949 clearHistorylist(history);
1950 supdatingStack.emit(0);
1951 return true;
1952 }
1953
stackDisband(Stack * s)1954 bool Player::stackDisband(Stack* s)
1955 {
1956 debug("Player::stackDisband(Stack*)")
1957 if (!s)
1958 s = getActivestack();
1959
1960 addAction(new Action_Disband(s));
1961
1962 bool retval = doStackDisband(s);
1963 schangingStats.emit();
1964 return retval;
1965 }
1966
doHeroDropItem(Hero * h,Item * i,Vector<int> pos,bool & splash)1967 void Player::doHeroDropItem(Hero *h, Item *i, Vector<int> pos, bool &splash)
1968 {
1969 if (GameMap::getInstance()->canDropBag(pos) == false)
1970 {
1971 h->getBackpack()->removeFromBackpack(i);
1972 delete i;
1973 splash = true;
1974 }
1975 else
1976 {
1977 GameMap::getInstance()->getTile(pos)->getBackpack()->addToBackpack(i);
1978 h->getBackpack()->removeFromBackpack(i);
1979 splash = false;
1980 }
1981 supdatingStack.emit(0);
1982 }
1983
heroDropItem(Hero * h,Item * i,Vector<int> pos,bool & splash)1984 bool Player::heroDropItem(Hero *h, Item *i, Vector<int> pos, bool &splash)
1985 {
1986 doHeroDropItem(h, i, pos, splash);
1987 addAction(new Action_Equip(h, i, Action_Equip::GROUND, pos));
1988 return true;
1989 }
1990
heroDropAllItems(Hero * h,Vector<int> pos,bool & splash)1991 bool Player::heroDropAllItems(Hero *h, Vector<int> pos, bool &splash)
1992 {
1993 while (h->getBackpack()->empty() == false)
1994 heroDropItem(h, h->getBackpack()->front(), pos, splash);
1995 return true;
1996 }
1997
doHeroDropAllItems(Hero * h,Vector<int> pos,bool & splash)1998 bool Player::doHeroDropAllItems(Hero *h, Vector<int> pos, bool &splash)
1999 {
2000 while (h->getBackpack()->empty() == false)
2001 doHeroDropItem(h, h->getBackpack()->front(), pos, splash);
2002 sbagdropped.emit ();
2003 supdatingStack.emit(0);
2004 return true;
2005 }
2006
doHeroPickupItem(Hero * h,Item * i,Vector<int> pos)2007 void Player::doHeroPickupItem(Hero *h, Item *i, Vector<int> pos)
2008 {
2009 bool found = GameMap::getInstance()->getTile(pos)->getBackpack()->removeFromBackpack(i);
2010 if (found)
2011 h->getBackpack()->addToBackpack(i);
2012 supdatingStack.emit(0);
2013 }
2014
heroPickupItem(Hero * h,Item * i,Vector<int> pos)2015 bool Player::heroPickupItem(Hero *h, Item *i, Vector<int> pos)
2016 {
2017 doHeroPickupItem(h, i, pos);
2018 addAction(new Action_Equip(h, i, Action_Equip::BACKPACK, pos));
2019 return true;
2020 }
2021
doHeroPickupAllItems(Hero * h,Vector<int> pos)2022 bool Player::doHeroPickupAllItems(Hero *h, Vector<int> pos)
2023 {
2024 MapBackpack *backpack = GameMap::getInstance()->getTile(pos)->getBackpack();
2025 while (backpack->empty() == false)
2026 doHeroPickupItem(h, backpack->front(), pos);
2027 return true;
2028 }
2029
heroPickupAllItems(Hero * h,Vector<int> pos)2030 bool Player::heroPickupAllItems(Hero *h, Vector<int> pos)
2031 {
2032 MapBackpack *backpack = GameMap::getInstance()->getTile(pos)->getBackpack();
2033 while (backpack->empty() == false)
2034 heroPickupItem(h, backpack->front(), pos);
2035 return true;
2036 }
2037
heroCompletesQuest(Hero * h)2038 bool Player::heroCompletesQuest(Hero *h)
2039 {
2040 // record it for posterity
2041 addHistory(new History_HeroQuestCompleted(h));
2042 return true;
2043 }
2044
doResign(std::list<History * > & histories)2045 void Player::doResign(std::list<History*> &histories)
2046 {
2047 //disband all stacks
2048 std::list<Stack*> stacks = getStacklist()->kill();
2049 removeDeadArmies(stacks, histories);
2050
2051 //raze all cities
2052 for (auto city: *Citylist::getInstance())
2053 {
2054 if (city->getOwner() == this)
2055 {
2056 city->setBurnt(true);
2057 histories.push_back(new History_CityRazed(city));
2058 }
2059 }
2060 withdrawGold(getGold()); //empty the coffers!
2061
2062 getStacklist()->setActivestack(0);
2063 supdatingStack.emit(0);
2064 }
2065
resign()2066 void Player::resign()
2067 {
2068 std::list<History*> history;
2069 doResign(history);
2070 for (std::list<History*>::iterator i = history.begin(); i != history.end();
2071 i++)
2072 addHistory(*i);
2073
2074 addAction(new Action_Resign());
2075 schangingStats.emit();
2076 }
2077
doSignpostChange(Signpost * s,Glib::ustring message)2078 void Player::doSignpostChange(Signpost *s, Glib::ustring message)
2079 {
2080 s->setName(message);
2081 }
2082
signpostChange(Signpost * s,Glib::ustring message)2083 bool Player::signpostChange(Signpost *s, Glib::ustring message)
2084 {
2085 if (!s)
2086 return false;
2087
2088 doSignpostChange(s, message);
2089
2090 addAction(new Action_ModifySignpost(s, message));
2091 return true;
2092 }
2093
doCityRename(City * c,Glib::ustring name)2094 void Player::doCityRename(City *c, Glib::ustring name)
2095 {
2096 c->setName(name);
2097 }
2098
cityRename(City * c,Glib::ustring name)2099 bool Player::cityRename(City *c, Glib::ustring name)
2100 {
2101 if (!c)
2102 return false;
2103
2104 doCityRename(c, name);
2105
2106 addAction(new Action_RenameCity(c, name));
2107 return true;
2108 }
2109
doRename(Glib::ustring name)2110 void Player::doRename(Glib::ustring name)
2111 {
2112 setName(name);
2113 }
2114
rename(Glib::ustring name)2115 void Player::rename(Glib::ustring name)
2116 {
2117 doRename(name);
2118 addAction(new Action_RenamePlayer(name));
2119 return;
2120 }
2121
doVectorFromCity(City * c,Vector<int> dest)2122 void Player::doVectorFromCity(City * c, Vector<int> dest)
2123 {
2124 c->setVectoring(dest);
2125 }
2126
vectorFromCity(City * c,Vector<int> dest)2127 bool Player::vectorFromCity(City * c, Vector<int> dest)
2128 {
2129 if (dest != Vector<int>(-1,-1))
2130 {
2131 std::list<City*> cities;
2132 cities = Citylist::getInstance()->getCitiesVectoringTo(dest);
2133 if (cities.size() >= MAX_CITIES_VECTORED_TO_ONE_CITY)
2134 return false;
2135 }
2136 doVectorFromCity(c, dest);
2137
2138 addAction(new Action_Vector(c, dest));
2139 return true;
2140 }
2141
doChangeVectorDestination(Vector<int> src,Vector<int> dest,std::list<City * > & vectored)2142 bool Player::doChangeVectorDestination(Vector<int> src, Vector<int> dest,
2143 std::list<City*> &vectored)
2144 {
2145 //DEST can be a flag.
2146 //SRC can be a flag too.
2147 //Note: we don't actually have a way in the gui to change the vectoring
2148 //from the planted standard (flag).
2149 bool retval = true;
2150 //sanity checks:
2151 //disallow changing vectoring from or to a city that isn't ours
2152 //disallow vectoring to something that isn't our city or our planted
2153 //standard.
2154 City *src_city = GameMap::getCity(src);
2155 if (src_city == NULL)
2156 {
2157 //maybe it's a flag we're changing the vector destination from.
2158 if (GameMap::getInstance()->findPlantedStandard(this) != src)
2159 return false;
2160 }
2161 else
2162 {
2163 if (src_city->getOwner() != this)
2164 return false;
2165 }
2166 City *dest_city = GameMap::getCity(dest);
2167 if (dest_city == NULL)
2168 {
2169 if (GameMap::getInstance()->findPlantedStandard(this) != dest)
2170 return false;
2171 }
2172 else
2173 {
2174 if (dest_city->getOwner() != this)
2175 return false;
2176 }
2177
2178 //check to see if the destination has enough room to accept all of the
2179 //cities we want to send to it.
2180 std::list<City*> sources = Citylist::getInstance()->getCitiesVectoringTo(src);
2181 std::list<City*> alreadyvectored =
2182 Citylist::getInstance()->getCitiesVectoringTo(dest);
2183
2184 if (alreadyvectored.size() + sources.size() > MAX_CITIES_VECTORED_TO_ONE_CITY)
2185 return false;
2186
2187 //okay, do the vectoring changes.
2188 std::list<City*>::iterator it = sources.begin();
2189 for (; it != sources.end(); it++)
2190 retval &= (*it)->changeVectorDestination(dest);
2191 vectored = sources;
2192 return retval;
2193 }
2194
changeVectorDestination(Vector<int> src,Vector<int> dest)2195 bool Player::changeVectorDestination(Vector<int> src, Vector<int> dest)
2196 {
2197 std::list<City*> vectored;
2198 bool retval = doChangeVectorDestination(src, dest, vectored);
2199 if (retval == false)
2200 return retval;
2201
2202 std::list<City*>::iterator it = vectored.begin();
2203 for (; it != vectored.end(); it++)
2204 addAction(new Action_Vector((*it), dest));
2205 return true;
2206 }
2207
heroPlantStandard(Stack * s)2208 bool Player::heroPlantStandard(Stack* s)
2209 {
2210 debug("Player::heroPlantStandard(Stack*)");
2211 if (!s)
2212 s = getActivestack();
2213
2214 for (Stack::iterator it = s->begin(); it != s->end(); it++)
2215 {
2216 if ((*it)->isHero())
2217 {
2218 Hero *hero = dynamic_cast<Hero*>((*it));
2219 Item *item = hero->getBackpack()->getPlantableItem(this);
2220 if (item)
2221 {
2222 //drop the item, and plant it
2223 doHeroPlantStandard(hero, item, s->getPos());
2224
2225 addAction(new Action_Plant(hero, item));
2226 return true;
2227 }
2228 }
2229 }
2230 return true;
2231 }
2232
doHeroPlantStandard(Hero * hero,Item * item,Vector<int> pos)2233 void Player::doHeroPlantStandard(Hero *hero, Item *item, Vector<int> pos)
2234 {
2235 item->setPlanted(true);
2236 GameMap::getInstance()->getTile(pos)->getBackpack()->addToBackpack(item);
2237 hero->getBackpack()->removeFromBackpack(item);
2238 supdatingStack.emit(0);
2239 }
2240
getHeroes(const std::list<Stack * > stacks,std::vector<guint32> & dst)2241 void Player::getHeroes(const std::list<Stack*> stacks, std::vector<guint32>& dst)
2242 {
2243 std::list<Stack*>::const_iterator it;
2244 for (it = stacks.begin(); it != stacks.end(); it++)
2245 (*it)->getHeroes(dst);
2246 }
2247
removeDeadArmies(Stack * stack,std::list<History * > & history)2248 guint32 Player::removeDeadArmies(Stack *stack, std::list<History*> &history)
2249 {
2250 std::list<Stack*> stacks;
2251 stacks.push_back(stack);
2252 return removeDeadArmies(stacks, history);
2253 }
2254
removeDeadArmies(std::list<Stack * > & stacks,std::list<History * > & history)2255 guint32 Player::removeDeadArmies(std::list<Stack*>& stacks,
2256 std::list<History*> &history)
2257 {
2258 std::vector<guint32> culprits;
2259 return removeDeadArmies(stacks, culprits, history);
2260 }
2261
removeDeadArmies(std::list<Stack * > & stacks,std::vector<guint32> & culprits,std::list<History * > & history)2262 guint32 Player::removeDeadArmies(std::list<Stack*>& stacks,
2263 std::vector<guint32>& culprits,
2264 std::list<History*> &history)
2265 {
2266 guint32 count = 0;
2267 Player *owner = NULL;
2268 if (stacks.empty() == false)
2269 {
2270 owner = (*stacks.begin())->getOwner();
2271 debug("Owner = " << owner);
2272 if (owner)
2273 {
2274 debug("Owner of the stacks: " << owner->getName()
2275 << ", his stacklist = " << owner->getStacklist());
2276 }
2277 }
2278 for (unsigned int i = 0; i < culprits.size(); i++)
2279 debug("Culprit: " << culprits[i]);
2280
2281 tallyDeadArmyTriumphs(stacks);
2282 handleDeadHeroes(stacks, history);
2283 handleDeadArmiesForQuests(stacks, culprits);
2284
2285 std::list<Stack*>::iterator it;
2286 for (it = stacks.begin(); it != stacks.end(); )
2287 {
2288 debug("Stack: " << (*it))
2289 if ((*it))
2290 {
2291 debug("Stack id: " << (*it)->getId());
2292 }
2293 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end();)
2294 {
2295 debug("Army: " << (*sit) << " " << (*sit)->getId())
2296 if ((*sit)->getHP() <= 0)
2297 {
2298 debug("Dead Army: " << (*sit)->getName())
2299
2300 count++;
2301 sit = (*it)->flErase(sit);
2302 continue;
2303 }
2304
2305 sit++;
2306 }
2307
2308 debug("Is stack empty?")
2309
2310 if ((*it)->empty())
2311 {
2312 bool ruinstack = false;
2313 if (owner == Playerlist::getInstance ()->getNeutral () &&
2314 GameMap::getInstance ()->getBuilding ((*it)->getPos ()) ==
2315 Maptile::RUIN)
2316 ruinstack = true;
2317
2318 if (!ruinstack)
2319 {
2320 debug("Yes, removing this stack from the owner's stacklist");
2321 bool found = owner->deleteStack(*it);
2322 if (found == false)
2323 {
2324 printf("couldn't find stack id %d for player %d\n", (*it)->getId(), owner->getId());
2325 printf("is it in our own stacklist?");
2326 Stack *a = getStacklist()->getStackById((*it)->getId());
2327 if (a)
2328 printf(" yes\n");
2329 else
2330 printf(" no\n");
2331 }
2332 assert (found == true);
2333 }
2334 else // there is no owner - like for the ruin's occupants
2335 {
2336 debug("No owner for this stack - do stacklist too");
2337 }
2338
2339 debug("Removing from the vector too (the vector had "
2340 << stacks.size() << " left)");
2341 it = stacks.erase(it);
2342 }
2343 else
2344 it++;
2345 }
2346 debug("after removeDead: num stacks = " << stacks.size());
2347 return count;
2348 }
2349
doHeroGainsLevel(Hero * hero,Army::Stat stat)2350 void Player::doHeroGainsLevel(Hero *hero, Army::Stat stat)
2351 {
2352 hero->gainLevel(stat);
2353 }
2354
updateArmyValues(std::list<Stack * > & stacks,double xp_sum)2355 void Player::updateArmyValues(std::list<Stack*>& stacks, double xp_sum)
2356 {
2357 std::list<Stack*>::iterator it;
2358 double numberarmy = 0;
2359
2360 for (it = stacks.begin(); it != stacks.end(); it++)
2361 numberarmy += (*it)->size();
2362
2363 for (it = stacks.begin(); it != stacks.end(); )
2364 {
2365 debug("Stack: " << (*it))
2366
2367 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end();)
2368 {
2369 Army *army = *sit;
2370 debug("Army: " << army)
2371
2372 // here we adds XP
2373 army->gainXp((double)((xp_sum)/numberarmy));
2374 debug("Army gets " << (double)((xp_sum)/numberarmy) << " XP")
2375
2376 // here we adds 1 to number of battles
2377 army->setBattlesNumber(army->getBattlesNumber()+1);
2378 debug("Army battles " << army->getBattlesNumber())
2379
2380 // medals only go to non-ally armies.
2381 if ((*it)->hasHero() && army->isHero() == false &&
2382 army->getAwardable() == false)
2383 {
2384 if((army->getBattlesNumber())>10 &&
2385 !(army->getMedalBonus(2)))
2386 {
2387 army->setMedalBonus(2,true);
2388 // We must recalculate the XPValue of this unit since it
2389 // got a medal
2390 army->setXpReward(army->getXpReward()+1);
2391 // We get the medal bonus here
2392 army->setStat(Army::STRENGTH, army->getStat(Army::STRENGTH, false)+1);
2393 // Emit signal
2394 snewMedalArmy.emit(army, 2);
2395 }
2396
2397 debug("Army hits " << army->getNumberHasHit())
2398
2399 // Only give medals if the unit has attacked often enough, else
2400 // medals lose the flair of something special; a value of n
2401 // means roughly to hit an equally strong unit around n
2402 // times. (note: one hit! An attack can consist of up to
2403 // strength hits)
2404 if((army->getNumberHasHit()>50) && !army->getMedalBonus(0))
2405 {
2406 army->setMedalBonus(0,true);
2407 // We must recalculate the XPValue of this unit since it
2408 // got a medal
2409 army->setXpReward(army->getXpReward()+1);
2410 // We get the medal bonus here
2411 army->setStat(Army::STRENGTH, army->getStat(Army::STRENGTH, false)+1);
2412 // Emit signal
2413 snewMedalArmy.emit(army, 0);
2414 }
2415
2416 debug("army being hit " << army->getNumberHasBeenHit())
2417
2418 // Gives the medal for good defense. The more negative the
2419 // number the more blows the unit evaded. n means roughly
2420 // avoid n hits from an equally strong unit. Since we want
2421 // to punish the case of the unit hiding among many others,
2422 // we set this value quite high.
2423 if((army->getNumberHasBeenHit() < -100) && !army->getMedalBonus(1))
2424 {
2425 army->setMedalBonus(1,true);
2426 // We must recalculate the XPValue of this unit since it
2427 // got a medal
2428 army->setXpReward(army->getXpReward()+1);
2429 // We get the medal bonus here
2430 army->setStat(Army::STRENGTH, army->getStat(Army::STRENGTH, false)+1);
2431 // Emit signal
2432 snewMedalArmy.emit(army, 1);
2433 }
2434 debug("Army hits " << army->getNumberHasHit())
2435
2436 for(int i=0;i<3;i++)
2437 {
2438 debug("MEDAL[" << i << "]==" << army->getMedalBonus(i))
2439 }
2440 }
2441
2442 // We reset the hit values after the battle
2443 army->setNumberHasHit(0);
2444 army->setNumberHasBeenHit(0);
2445
2446 if (army->isHero() && getType() != Player::NETWORKED)
2447 {
2448 Hero *h = dynamic_cast<Hero*>(army);
2449 while(h->canGainLevel())
2450 {
2451 // Units not associated to a player never raise levels.
2452 if (h->getOwner() == Playerlist::getInstance()->getNeutral())
2453 break;
2454
2455 //Here this for is to check if army must raise 2 or more
2456 //levels per time depending on the XP and level itself
2457
2458 h->getOwner()->heroGainsLevel(h);
2459 }
2460 debug("Hero new XP=" << h->getXP())
2461 }
2462 sit++;
2463 }
2464 it++;
2465 }
2466 }
2467
doRecruitHero(HeroProto * herotemplate,City * city,int cost,int alliesCount,const ArmyProto * ally,StackReflist * stacks)2468 Hero* Player::doRecruitHero(HeroProto* herotemplate, City *city, int cost, int alliesCount, const ArmyProto *ally, StackReflist *stacks)
2469 {
2470 Hero *newhero = new Hero(*herotemplate);
2471 newhero->setOwner(this);
2472 Stack *s = GameMap::getInstance()->addArmy(city, newhero);
2473 if (stacks)
2474 {
2475 if (stacks->contains(s->getId()) == false)
2476 stacks->addStack(s);
2477 }
2478
2479 if (alliesCount > 0)
2480 {
2481 Reward_Allies::addAllies(this, city->getPos(), ally, alliesCount,
2482 stacks);
2483 hero_arrives_with_allies.emit(alliesCount);
2484 }
2485
2486 if (cost == 0)
2487 {
2488 // Initially give the first hero the player's standard.
2489 Glib::ustring name = String::ucompose(_("%1 Standard"), getName());
2490 Item *battle_standard = new Item (name, true, this);
2491 battle_standard->addBonus(Item::ADD1STACK);
2492 newhero->getBackpack()->addToBackpack(battle_standard, 0);
2493 }
2494 withdrawGold(cost);
2495 supdatingStack.emit(0);
2496 return newhero;
2497 }
2498
recruitHero(HeroProto * heroproto,City * city,int cost,int alliesCount,const ArmyProto * ally,StackReflist * stacks)2499 void Player::recruitHero(HeroProto* heroproto, City *city, int cost, int alliesCount, const ArmyProto *ally, StackReflist *stacks)
2500 {
2501 //alright, we may have picked another sex for the hero.
2502 HeroProto *h;
2503 Glib::ustring name = heroproto->getName();
2504 Hero::Gender g = Hero::Gender(heroproto->getGender());
2505 h = HeroTemplates::getInstance()->getRandomHero(g, getId());
2506 h->setGender(g);
2507 h->setName(name);
2508 addAction(new Action_RecruitHero(h, city, cost, alliesCount, ally));
2509
2510 Hero *hero = doRecruitHero(h, city, cost, alliesCount, ally, stacks);
2511 if (hero)
2512 addHistory(new History_HeroEmerges(hero, city));
2513 }
2514
doDeclareDiplomacy(DiplomaticState state,Player * player)2515 void Player::doDeclareDiplomacy (DiplomaticState state, Player *player)
2516 {
2517 if (Playerlist::getInstance()->getNeutral() == player)
2518 return;
2519 if (player == this)
2520 return;
2521 if (state == d_diplomatic_state[player->getId()])
2522 return;
2523 d_diplomatic_state[player->getId()] = state;
2524 }
2525
declareDiplomacy(DiplomaticState state,Player * player,bool treachery)2526 void Player::declareDiplomacy (DiplomaticState state, Player *player, bool treachery)
2527 {
2528 doDeclareDiplomacy(state, player);
2529
2530 addAction(new Action_DiplomacyState(player, state));
2531
2532 switch (state)
2533 {
2534 case AT_PEACE:
2535 addHistory(new History_DiplomacyPeace(player));
2536 break;
2537 case AT_WAR_IN_FIELD:
2538 break;
2539 case AT_WAR:
2540 addHistory(new History_DiplomacyWar(player));
2541 break;
2542 }
2543 if (treachery)
2544 addHistory(new History_DiplomacyTreachery(player));
2545 // FIXME: update diplomatic scores?
2546 }
2547
doProposeDiplomacy(DiplomaticProposal proposal,Player * player)2548 void Player::doProposeDiplomacy (DiplomaticProposal proposal, Player *player)
2549 {
2550 if (GameScenarioOptions::s_diplomacy == false)
2551 return;
2552 if (Playerlist::getInstance()->getNeutral() == player)
2553 return;
2554 if (player == this)
2555 return;
2556 if (proposal == d_diplomatic_proposal[player->getId()])
2557 return;
2558 if (proposal == PROPOSE_PEACE)
2559 {
2560 Glib::ustring s =
2561 String::ucompose(_("Peace negotiated with %1."),player->getName());
2562 if (getDiplomaticState(player) == AT_PEACE ||
2563 getDiplomaticProposal(player) == PROPOSE_PEACE)
2564 schangingStatus.emit(s);
2565 }
2566 else if (proposal == PROPOSE_WAR)
2567 {
2568 Glib::ustring s =
2569 String::ucompose(_("War declared with %1."), player->getName());
2570 if (getDiplomaticState(player) == AT_WAR ||
2571 getDiplomaticProposal(player) == PROPOSE_WAR)
2572 schangingStatus.emit(s);
2573 }
2574 d_diplomatic_proposal[player->getId()] = proposal;
2575 }
2576
proposeDiplomacy(DiplomaticProposal proposal,Player * player)2577 void Player::proposeDiplomacy (DiplomaticProposal proposal, Player *player)
2578 {
2579 doProposeDiplomacy(proposal, player);
2580
2581 addAction(new Action_DiplomacyProposal(player, proposal));
2582
2583 // FIXME: update diplomatic scores?
2584 }
2585
negotiateDiplomacy(Player * player)2586 Player::DiplomaticState Player::negotiateDiplomacy (Player *player)
2587 {
2588 DiplomaticState state = getDiplomaticState(player);
2589 DiplomaticProposal them = player->getDiplomaticProposal(this);
2590 DiplomaticProposal me = getDiplomaticProposal(player);
2591 DiplomaticProposal winning_proposal;
2592
2593 /* Check if we both want the status quo. */
2594 if (me == NO_PROPOSAL && them == NO_PROPOSAL)
2595 return state;
2596
2597 /* Okay, we both want a change from the status quo. */
2598
2599 /* In the absense of a new proposal, the status quo is the proposal. */
2600 if (me == NO_PROPOSAL)
2601 {
2602 switch (state)
2603 {
2604 case AT_PEACE: me = PROPOSE_PEACE; break;
2605 case AT_WAR_IN_FIELD: me = PROPOSE_WAR_IN_FIELD; break;
2606 case AT_WAR: me = PROPOSE_WAR; break;
2607 }
2608 }
2609 if (them == NO_PROPOSAL)
2610 {
2611 switch (state)
2612 {
2613 case AT_PEACE: them = PROPOSE_PEACE; break;
2614 case AT_WAR_IN_FIELD: them = PROPOSE_WAR_IN_FIELD; break;
2615 case AT_WAR: them = PROPOSE_WAR; break;
2616 }
2617 }
2618
2619 /* Check if we have agreement. */
2620 if (me == PROPOSE_PEACE && them == PROPOSE_PEACE)
2621 return AT_PEACE;
2622 else if (me == PROPOSE_WAR_IN_FIELD && them == PROPOSE_WAR_IN_FIELD)
2623 return AT_WAR_IN_FIELD;
2624 else if (me == PROPOSE_WAR && them == PROPOSE_WAR)
2625 return AT_WAR;
2626
2627 /* Still we don't have an agreement.
2628 Unfortunately the greater violence is the new diplomatic state.
2629 Because there are two different proposals and the proposal with
2630 greater violence will be the new status quo, there can't
2631 possibly be peace at this juncture. */
2632
2633 winning_proposal = me;
2634 if (them > me)
2635 winning_proposal = them;
2636
2637 switch (winning_proposal)
2638 {
2639 case PROPOSE_WAR_IN_FIELD: return AT_WAR_IN_FIELD; break;
2640 case PROPOSE_WAR: return AT_WAR; break;
2641 default: return AT_PEACE; break; //impossible
2642 }
2643
2644 }
2645
getDiplomaticState(Player * player) const2646 Player::DiplomaticState Player::getDiplomaticState (Player *player) const
2647 {
2648 if (player == Playerlist::getInstance()->getNeutral())
2649 return AT_WAR;
2650 if (player == this)
2651 return AT_PEACE;
2652 return d_diplomatic_state[player->getId()];
2653 }
2654
getDiplomaticProposal(Player * player) const2655 Player::DiplomaticProposal Player::getDiplomaticProposal (Player *player) const
2656 {
2657 if (player == Playerlist::getInstance()->getNeutral())
2658 return PROPOSE_WAR;
2659 if (player == this)
2660 return NO_PROPOSAL;
2661 return d_diplomatic_proposal[player->getId()];
2662 }
2663
getDiplomaticScore(Player * player) const2664 guint32 Player::getDiplomaticScore (Player *player) const
2665 {
2666 if (Playerlist::getInstance()->getNeutral() == player)
2667 return 8;
2668 return d_diplomatic_score[player->getId()];
2669 }
2670
alterDiplomaticRelationshipScore(Player * player,int amount)2671 void Player::alterDiplomaticRelationshipScore (Player *player, int amount)
2672 {
2673 if (amount > 0)
2674 {
2675 if (d_diplomatic_score[player->getId()] + amount > DIPLOMACY_MAX_SCORE)
2676 d_diplomatic_score[player->getId()] = DIPLOMACY_MAX_SCORE;
2677 else
2678 d_diplomatic_score[player->getId()] += amount;
2679 }
2680 else if (amount < 0)
2681 {
2682 if ((guint32) (amount * -1) > d_diplomatic_score[player->getId()])
2683 d_diplomatic_score[player->getId()] = DIPLOMACY_MIN_SCORE;
2684 else
2685 d_diplomatic_score[player->getId()] += amount;
2686 }
2687 }
2688
improveDiplomaticRelationship(Player * player,guint32 amount)2689 void Player::improveDiplomaticRelationship (Player *player, guint32 amount)
2690 {
2691 if (Playerlist::getInstance()->getNeutral() == player || player == this)
2692 return;
2693
2694 alterDiplomaticRelationshipScore (player, amount);
2695
2696 addAction(new Action_DiplomacyScore(player, amount));
2697 }
2698
deteriorateDiplomaticRelationship(Player * player,guint32 amount)2699 void Player::deteriorateDiplomaticRelationship (Player *player, guint32 amount)
2700 {
2701 if (Playerlist::getInstance()->getNeutral() == player || player == this)
2702 return;
2703
2704 alterDiplomaticRelationshipScore (player, -amount);
2705
2706 addAction(new Action_DiplomacyScore(player, -amount));
2707 }
2708
deteriorateDiplomaticRelationship(guint32 amount)2709 void Player::deteriorateDiplomaticRelationship (guint32 amount)
2710 {
2711 for (auto it: *Playerlist::getInstance())
2712 {
2713 if (it->isDead())
2714 continue;
2715 if (Playerlist::getInstance()->getNeutral() == it)
2716 continue;
2717 if (it == this)
2718 continue;
2719 it->deteriorateDiplomaticRelationship (this, amount);
2720 }
2721 }
2722
improveDiplomaticRelationship(guint32 amount,Player * except)2723 void Player::improveDiplomaticRelationship (guint32 amount, Player *except)
2724 {
2725 for (auto it: *Playerlist::getInstance())
2726 {
2727 if (it->isDead())
2728 continue;
2729 if (Playerlist::getInstance()->getNeutral() == it)
2730 continue;
2731 if (it == this)
2732 continue;
2733 if (except && it == except)
2734 continue;
2735 it->improveDiplomaticRelationship (this, amount);
2736 }
2737 }
2738
deteriorateAlliesRelationship(Player * player,guint32 amount,Player::DiplomaticState state)2739 void Player::deteriorateAlliesRelationship(Player *player, guint32 amount,
2740 Player::DiplomaticState state)
2741 {
2742 for (auto it: *Playerlist::getInstance())
2743 {
2744 if (it->isDead())
2745 continue;
2746 if (Playerlist::getInstance()->getNeutral() == it)
2747 continue;
2748 if (it == this)
2749 continue;
2750 if (getDiplomaticState(it) == state)
2751 it->deteriorateDiplomaticRelationship (player, amount);
2752 }
2753 }
2754
improveAlliesRelationship(Player * player,guint32 amount,Player::DiplomaticState state)2755 void Player::improveAlliesRelationship(Player *player, guint32 amount,
2756 Player::DiplomaticState state)
2757 {
2758 for (auto it: *Playerlist::getInstance())
2759 {
2760 if (it->isDead())
2761 continue;
2762 if (Playerlist::getInstance()->getNeutral() == it)
2763 continue;
2764 if (it == this)
2765 continue;
2766 if (player->getDiplomaticState(it) == state)
2767 it->improveDiplomaticRelationship (this, amount);
2768 }
2769 }
2770
AI_maybeBuyScout(City * c)2771 void Player::AI_maybeBuyScout(City *c)
2772 {
2773 if (c->getBuildProduction() == false)
2774 return;
2775 bool one_turn_army_exists = false;
2776 //do we already have something that can be produced in one turn?
2777 for (unsigned int i = 0; i < c->getMaxNoOfProductionBases(); i++)
2778 {
2779 if (c->getArmytype(i) == -1) // no production in this slot
2780 continue;
2781
2782 const ArmyProdBase *proto = c->getProductionBase(i);
2783 if (proto->getProduction() == 1)
2784 {
2785 one_turn_army_exists = true;
2786 break;
2787 }
2788 }
2789 if (one_turn_army_exists == false)
2790 {
2791 int free_slot = c->getFreeSlot();
2792 if (free_slot == -1)
2793 free_slot = 0;
2794 ArmyProto *scout =
2795 Armysetlist::getInstance()->lookupWeakestQuickestArmy(getArmyset());
2796 cityBuyProduction(c, free_slot, scout->getId());
2797 }
2798 }
2799
AI_maybeContinueQuest(Stack * s,Quest * quest,bool & completed_quest,bool & stack_died)2800 bool Player::AI_maybeContinueQuest(Stack *s, Quest *quest, bool &completed_quest, bool &stack_died)
2801 {
2802 bool stack_moved = false;
2803 Vector<int> quest_tile = AI_getQuestDestination(quest, s);
2804
2805 if (quest_tile == Vector<int>(-1,-1))
2806 return false;
2807
2808 //are we not standing on it?
2809 if (s->getPos() != quest_tile)
2810 {
2811 //can we really reach it?
2812 Vector<int> old_dest(-1,-1);
2813 if (s->getPath()->size())
2814 old_dest = s->getLastPointInPath();
2815 guint32 moves = 0, turns = 0, left = 0;
2816 s->getPath()->calculate(s, quest_tile, moves, turns, left);
2817 bool go_there = computerChooseContinueQuest(s, quest, quest_tile, moves,
2818 turns);
2819 if (!go_there)
2820 {
2821 s->clearPath();
2822 if (old_dest != Vector<int>(-1,-1))
2823 s->getPath()->calculate(s, old_dest);
2824 return false;
2825 }
2826 d_stacklist->setActivestack(s);
2827 stack_moved = stackMove(s);
2828 //maybe we died either en route or at our destination.
2829 if (!d_stacklist->getActivestack())
2830 {
2831 stack_died = true;
2832 return true;
2833 }
2834 s = d_stacklist->getActivestack();
2835 }
2836
2837 //are we standing on it now?
2838 if (s->getPos() == quest_tile)
2839 completed_quest = true;
2840
2841 return stack_moved;
2842 }
2843
AI_maybePickUpItems(Stack * s,int max_dist,bool & picked_up,bool & stack_died)2844 bool Player::AI_maybePickUpItems(Stack *s, int max_dist,
2845 bool &picked_up, bool &stack_died)
2846 {
2847 int min_dist = -1;
2848 bool stack_moved = false;
2849 Vector<int> item_tile(-1, -1);
2850
2851 // do we not have a hero?
2852 if (s->hasHero() == false)
2853 return false;
2854
2855 //ok, which bag of stuff is closest?
2856 for (auto tile: GameMap::getInstance()->getItems())
2857 {
2858 //don't consider bags of stuff that are inside enemy cities
2859 City *c = GameMap::getCity(tile);
2860 if (c)
2861 {
2862 if (c->getOwner() != s->getOwner())
2863 continue;
2864 }
2865
2866 int distance = dist (tile, s->getPos());
2867 if (distance < min_dist || min_dist == -1)
2868 {
2869 min_dist = distance;
2870 item_tile = tile;
2871 }
2872 }
2873
2874 //if no bags of stuff, or the bag is too far away
2875 if (min_dist == -1 || min_dist > max_dist)
2876 return false;
2877
2878 //are we not standing on it?
2879 if (s->getPos() != item_tile)
2880 {
2881 //can we really reach it?
2882 Vector<int> old_dest(-1,-1);
2883 if (s->getPath()->size())
2884 old_dest = s->getLastPointInPath();
2885 guint32 moves = 0, turns = 0, left = 0;
2886 s->getPath()->calculate(s, item_tile, moves, turns, left);
2887 bool go_there = computerChoosePickupBag(s, item_tile, moves, turns);
2888 if (!go_there)
2889 {
2890 s->clearPath();
2891 if (old_dest != Vector<int>(-1,-1))
2892 s->getPath()->calculate(s, old_dest);
2893 return false;
2894 }
2895 d_stacklist->setActivestack(s);
2896 stack_moved = stackMove(s);
2897 //maybe we died -- an enemy stack was guarding the bag.
2898 if (!d_stacklist->getActivestack())
2899 {
2900 stack_died = true;
2901 return true;
2902 }
2903 s = d_stacklist->getActivestack();
2904 }
2905
2906 //are we standing on it now?
2907 if (s->getPos() == item_tile)
2908 {
2909 bool pickitup = computerChoosePickupBag(s, item_tile, 0, 0);
2910 if (!pickitup)
2911 {
2912 s->clearPath();
2913 return stack_moved;
2914 }
2915 Hero *hero = static_cast<Hero*>(s->getFirstHero());
2916 if (hero)
2917 picked_up = heroPickupAllItems(hero, s->getPos());
2918 }
2919
2920 return stack_moved;
2921 }
2922
AI_maybeVisitTempleForQuest(Stack * s,int dist,bool & got_quest,bool & stack_died)2923 bool Player::AI_maybeVisitTempleForQuest(Stack *s, int dist, bool &got_quest, bool &stack_died)
2924 {
2925 bool stack_moved = false;
2926
2927 //if this stack doesn't have a hero then we can't get a quest with this stack.
2928 if (s->hasHero() == false)
2929 return false;
2930
2931 //if the player already has a hero who has a quest, then we can't get a
2932 //quest with this stack when playing one quest per player.
2933 if (QuestsManager::getInstance()->getPlayerQuests(this).size() > 0 &&
2934 GameScenarioOptions::s_play_with_quests ==
2935 GameParameters::ONE_QUEST_PER_PLAYER)
2936 return false;
2937
2938 Temple *temple =
2939 Templelist::getInstance()->getNearestVisibleTemple(s->getPos(), dist);
2940 if (!temple)
2941 return false;
2942
2943 //if we're not there yet
2944 if (temple->contains(s->getPos()) == false)
2945 {
2946 //can we really reach it?
2947 Vector<int> old_dest(-1,-1);
2948 if (s->getPath()->size())
2949 old_dest = s->getLastPointInPath();
2950 guint32 moves = 0, turns = 0, left = 0;
2951 s->getPath()->calculate(s, s->getPos(), moves, turns, left);
2952 bool go_there = computerChooseVisitTempleForQuest(s, temple->getPos(), moves, turns);
2953 if (!go_there)
2954 {
2955 s->clearPath();
2956 if (old_dest != Vector<int>(-1,-1))
2957 s->getPath()->calculate(s, old_dest);
2958 return false;
2959 }
2960 d_stacklist->setActivestack(s);
2961 stack_moved = stackMove(s);
2962
2963 //maybe we died -- an enemy stack was guarding the temple
2964 if (!d_stacklist->getActivestack())
2965 {
2966 stack_died = true;
2967 return true;
2968 }
2969 s = d_stacklist->getActivestack();
2970 }
2971
2972 //are we there yet?
2973 if (temple->contains(s->getPos()) == true && GameMap::can_search(s))
2974 {
2975 bool searchit = computerChooseVisitTempleForQuest(s, s->getPos(), 0, 0);
2976 if (!searchit)
2977 {
2978 s->clearPath();
2979 return stack_moved;
2980 }
2981 svisitingTemple.emit(temple, s);
2982 got_quest = true;
2983 }
2984
2985 return stack_moved;
2986 }
2987
AI_maybeVisitRuin(Stack * s,int dist,bool & visited_ruin,bool & stack_died)2988 bool Player::AI_maybeVisitRuin(Stack *s, int dist, bool &visited_ruin, bool &stack_died)
2989 {
2990 bool stack_moved = false;
2991
2992 //if this stack doesn't have a hero then we can't search the ruin.
2993 if (s->hasHero() == false)
2994 return false;
2995
2996 Ruin *ruin = Ruinlist::getInstance()->getNearestUnsearchedRuin(s->getPos(), dist);
2997 if (!ruin)
2998 return false;
2999
3000 //if we're not there yet
3001 if (ruin->contains(s->getPos()) == false)
3002 {
3003 //can we really reach it?
3004 Vector<int> old_dest(-1,-1);
3005 if (s->getPath()->size())
3006 old_dest = s->getLastPointInPath();
3007 guint32 moves = 0, turns = 0, left = 0;
3008 s->getPath()->calculate(s, ruin->getPos(), moves, turns, left);
3009 bool go_there = computerChooseVisitRuin(s, ruin->getPos(), moves, turns);
3010 if (!go_there)
3011 {
3012 s->clearPath();
3013 if (old_dest != Vector<int>(-1,-1))
3014 s->getPath()->calculate(s, old_dest);
3015 return false;
3016 }
3017 d_stacklist->setActivestack(s);
3018 stack_moved = stackMove(s);
3019
3020 //maybe we died -- an enemy stack was guarding the temple
3021 if (!d_stacklist->getActivestack())
3022 {
3023 stack_died = true;
3024 return true;
3025 }
3026 s = d_stacklist->getActivestack();
3027 }
3028
3029 //are we there yet?
3030 if (ruin->contains(s->getPos()) == true && GameMap::can_search(s))
3031 {
3032 bool searchit = computerChooseVisitRuin(s, s->getPos(), 0, 0);
3033 if (!searchit)
3034 {
3035 s->clearPath();
3036 return stack_moved;
3037 }
3038 stack_died = ssearchingRuin.emit(ruin, s);
3039 if (!stack_died)
3040 visited_ruin = true;
3041 }
3042
3043 return stack_moved;
3044 }
3045
AI_maybeVisitTempleForBlessing(Stack * s,int dist,double percent_can_be_blessed,bool & blessed,bool & stack_died)3046 bool Player::AI_maybeVisitTempleForBlessing(Stack *s, int dist,
3047 double percent_can_be_blessed,
3048 bool &blessed, bool &stack_died)
3049 {
3050 bool stack_moved = false;
3051
3052 Temple *temple = Templelist::getInstance()->getNearestVisibleAndUsefulTemple
3053 (s, percent_can_be_blessed, dist);
3054 if (!temple)
3055 return false;
3056
3057 //if we're not there yet
3058 if (s->getPos() != temple->getPos())
3059 {
3060 //can we really reach it?
3061 Vector<int> old_dest(-1,-1);
3062 if (s->getPath()->size())
3063 old_dest = s->getLastPointInPath();
3064 guint32 moves = 0, turns = 0, left = 0;
3065 s->getPath()->calculate(s, temple->getPos(), moves, turns, left);
3066 bool go_there = computerChooseVisitTempleForBlessing(s, temple->getPos(), moves, turns);
3067 if (!go_there)
3068 {
3069 s->clearPath();
3070 if (old_dest != Vector<int>(-1,-1))
3071 s->getPath()->calculate(s, old_dest);
3072 return false;
3073 }
3074 d_stacklist->setActivestack(s);
3075 stack_moved = stackMove(s);
3076
3077 //maybe we died -- an enemy stack was guarding the temple
3078 if (!d_stacklist->getActivestack())
3079 {
3080 stack_died = true;
3081 return true;
3082 }
3083 s = d_stacklist->getActivestack();
3084 }
3085
3086 int num_blessed = 0;
3087 //are we there yet?
3088 if (temple->contains(s->getPos()) == true && GameMap::can_search(s))
3089 {
3090 bool searchit = computerChooseVisitTempleForBlessing(s, s->getPos(),
3091 0, 0);
3092 if (!searchit)
3093 {
3094 s->clearPath();
3095 return stack_moved;
3096 }
3097 num_blessed = stackVisitTemple(s, temple);
3098 }
3099
3100 blessed = num_blessed > 0;
3101 return stack_moved;
3102 }
3103
safeFromAttack(City * c,guint32 safe_mp,guint32 min_defenders)3104 bool Player::safeFromAttack(City *c, guint32 safe_mp, guint32 min_defenders)
3105 {
3106 //if there isn't an enemy city nearby to the source
3107 // calculate mp to nearest enemy city
3108 // needs to be less than 18 mp with a scout
3109 //does the source city contain at least 3 defenders?
3110
3111 City *enemy_city = Citylist::getInstance()->getNearestEnemyCity(c->getPos());
3112 if (enemy_city)
3113 {
3114 PathCalculator pc(c->getOwner(), c->getPos());
3115 int mp = pc.calculate(enemy_city->getPos());
3116 if (mp <= 0 || mp >= (int)safe_mp)
3117 {
3118 if (c->countDefenders() >= min_defenders)
3119 return true;
3120 }
3121 }
3122
3123 return false;
3124 }
3125
AI_maybeDisband(Stack * s,int safe_mp,bool & stack_killed)3126 bool Player::AI_maybeDisband(Stack *s, int safe_mp, bool &stack_killed)
3127 {
3128 bool disbanded = false;
3129 //see if we're near to enemy stacks
3130 PathCalculator pc(s);
3131 if (GameMap::getEnemyStacks(pc.getReachablePositions(safe_mp)).size() > 0)
3132 return false;
3133
3134 //upgroup the whole stack if it doesn't contain a hero
3135 if (s->hasHero() == false)
3136 {
3137 stack_killed = stackDisband (s);
3138 return stack_killed;
3139 }
3140
3141 //ungroup the lucky ones not being disbanded
3142 for (Stack::reverse_iterator i = s->rbegin(); i != s->rend(); i++)
3143 {
3144 if ((*i)->isHero() == false)
3145 {
3146 Stack *new_stack = stackSplitArmy(s, *i);
3147 if (new_stack)
3148 {
3149 if (stackDisband(new_stack))
3150 disbanded = true;
3151 }
3152 }
3153 }
3154 return disbanded;
3155 }
3156
AI_maybeDisband(Stack * s,City * city,guint32 min_defenders,int safe_mp,bool & stack_killed)3157 bool Player::AI_maybeDisband(Stack *s, City *city, guint32 min_defenders,
3158 int safe_mp, bool &stack_killed)
3159 {
3160 bool disbanded = false;
3161 //is the city in danger from a city?
3162 if (safeFromAttack(city, safe_mp, 0) == false)
3163 return false;
3164
3165 if (city->countDefenders() - s->size() >= min_defenders)
3166 {
3167 if (s->hasHero())
3168 min_defenders = s->size() + 1;
3169 else
3170 {
3171 stack_killed = stackDisband(s);
3172 return stack_killed;
3173 }
3174 }
3175
3176 //okay, we need to disband part of our stack
3177
3178 //before we move, ungroup the lucky ones not being disbanded
3179 unsigned int count = 0;
3180 for (Stack::reverse_iterator i = s->rbegin(); i != s->rend(); i++)
3181 {
3182 if (count == min_defenders)
3183 break;
3184 if ((*i)->isHero() == false)
3185 {
3186 Stack *new_stack = stackSplitArmy(s, *i);
3187 if (new_stack)
3188 {
3189 count++;
3190 if (stackDisband(new_stack))
3191 disbanded = true;
3192 }
3193 }
3194 }
3195 return disbanded;
3196 }
3197
AI_maybeVector(City * c,guint32 safe_mp,guint32 min_defenders,City * target,City ** vector_city)3198 bool Player::AI_maybeVector(City *c, guint32 safe_mp, guint32 min_defenders,
3199 City *target, City **vector_city)
3200 {
3201 assert (c->getOwner() == this);
3202 if (vector_city)
3203 *vector_city = NULL;
3204
3205 //is this city producing anything that we can vector?
3206 if (c->getActiveProductionSlot() == -1)
3207 return false;
3208
3209 //is it safe to vector from this city?
3210 bool safe = safeFromAttack(c, safe_mp, min_defenders);
3211
3212 if (!safe)
3213 return false;
3214
3215 //get the nearest city to the enemy city that can accept vectored units
3216 City *near_city =
3217 Citylist::getInstance()->getNearestFriendlyVectorableCity(target->getPos());
3218 if (!near_city)
3219 return false;
3220 assert (near_city->getOwner() == this);
3221 if (GameMap::getCity(near_city->getPos()) != near_city)
3222 {
3223 printf("nearCity is %s (%d)\n", near_city->getName().c_str(), near_city->getId());
3224 printf("it is located at %d,%d\n", near_city->getPos().x, near_city->getPos().y);
3225 City *other = GameMap::getCity(near_city->getPos());
3226 if (other)
3227 {
3228 printf("the OTHER nearCity is %s (%d)\n", other->getName().c_str(), other->getId());
3229 printf("it is located at %d,%d\n", other->getPos().x, other->getPos().y);
3230 }
3231 else
3232 printf("no city there!\n");
3233 assert (1 == 0);
3234 }
3235
3236 //if it's us then it's easier to just walk.
3237 if (near_city == c)
3238 return false;
3239
3240 //is that city already vectoring?
3241 if (near_city->getVectoring() != Vector<int>(-1, -1))
3242 return false;
3243
3244 //can i just walk there faster?
3245
3246 //find turns from source to target city
3247 const ArmyProdBase *proto = c->getActiveProductionBase();
3248 PathCalculator pc1(c->getOwner(), c->getPos(), proto);
3249 guint32 moves1 = 0, turns1 = 0, left1 = 0;
3250 guint32 moves2 = 0, turns2 = 0, left2 = 0;
3251 Path *p = pc1.calculate(target->getPos(), moves1, turns1, left1);
3252 if (p)
3253 delete p;
3254
3255 //find turns from nearer vectorable city to target city
3256 PathCalculator pc2(c->getOwner(), near_city->getPos(), proto);
3257 p = pc2.calculate(target->getPos(), moves2, turns2, left2);
3258 if (p)
3259 delete p;
3260 turns2+=VectoredUnit::get_travel_turns(near_city->getPos(), target->getPos());
3261 if (turns1 <= turns2)
3262 return false;
3263
3264 //great. now do the vectoring.
3265 c->changeVectorDestination(near_city->getPos());
3266
3267 if (vector_city)
3268 *vector_city = near_city;
3269 return true;
3270 }
3271
AI_setupVectoring(guint32 safe_mp,guint32 min_defenders,guint32 mp_to_front)3272 void Player::AI_setupVectoring(guint32 safe_mp, guint32 min_defenders,
3273 guint32 mp_to_front)
3274 {
3275 //turn off vectoring where it isn't safe anymore
3276 //turn off vectoring for destinations that are far away from the
3277 //nearest enemy city
3278
3279 for (auto c: *Citylist::getInstance())
3280 {
3281 if (c->getOwner() != this || c->isBurnt())
3282 continue;
3283 Vector<int> dest = c->getVectoring();
3284 if (dest == Vector<int>(-1, -1))
3285 continue;
3286 if (safeFromAttack(c, safe_mp, min_defenders) == false)
3287 {
3288 //City *target_city = Citylist::getInstance()->getObjectAt(dest);
3289 //debug("stopping vectoring from " << c->getName() <<" to " << target_city->getName() << " because it's not safe to anymore!\n")
3290 c->setVectoring(Vector<int>(-1,-1));
3291 continue;
3292 }
3293
3294 City *enemy_city = Citylist::getInstance()->getNearestEnemyCity(dest);
3295 if (!enemy_city)
3296 {
3297 //City *target_city = Citylist::getInstance()->getObjectAt(dest);
3298 //debug("stopping vectoring from " << c->getName() <<" to " << target_city->getName() << " because there aren't any more enemy cities!\n")
3299 c->setVectoring(Vector<int>(-1,-1));
3300 continue;
3301 }
3302
3303 PathCalculator pc(this, dest, NULL);
3304 int mp = pc.calculate(enemy_city->getPos());
3305 if (mp <= 0 || mp > (int)mp_to_front)
3306 {
3307
3308 //City *target_city = Citylist::getInstance()->getObjectAt(dest);
3309 //debug("stopping vectoring from " << c->getName() <<" to " << target_city->getName() << " because it's too far away from an enemy city!\n")
3310 c->setVectoring(Vector<int>(-1,-1));
3311 continue;
3312 }
3313 }
3314
3315 for (auto c : *Citylist::getInstance())
3316 {
3317 if (c->getOwner() != this || c->isBurnt())
3318 continue;
3319 City *enemy_city = Citylist::getInstance()->getNearestEnemyCity(c->getPos());
3320 if (!enemy_city)
3321 continue;
3322 City *vector_city = NULL;
3323 //if the city isn't already vectoring
3324 if (c->getVectoring() == Vector<int>(-1,-1))
3325 {
3326 bool vectored = AI_maybeVector(c, safe_mp, min_defenders, enemy_city,
3327 &vector_city);
3328 if (vectored)
3329 {
3330 debug("begin vectoring from " << c->getName() <<" to " << vector_city->getName() << "!\n");
3331 }
3332 }
3333 }
3334 }
3335
doCityProducesArmy(City * city,Stack * & s,bool & vectored)3336 const Army * Player::doCityProducesArmy(City *city, Stack *& s, bool &vectored)
3337 {
3338 vectored = false;
3339 int cost = city->getActiveProductionBase()->getProductionCost();
3340 if (cost > d_gold)
3341 return NULL;
3342 withdrawGold(cost);
3343 const Army *a = city->armyArrives(s);
3344 if (city->getVectoring() != Vector<int>(-1,-1))
3345 vectored = true;
3346 return a;
3347 }
3348
cityProducesArmy(City * city)3349 bool Player::cityProducesArmy(City *city)
3350 {
3351 assert(city->getOwner() == this);
3352 Stack *stack = NULL;
3353 bool vectored = false;
3354 const Army *army = doCityProducesArmy(city, stack, vectored);
3355 if (army)
3356 {
3357 if (!stack)
3358 {
3359 printf("we dropped an army down but it doesn't have a stack!\n");
3360 return false;
3361 }
3362 const ArmyProdBase *source_army;
3363 source_army = city->getProductionBaseBelongingTo(army);
3364 if (stack)
3365 {
3366 addAction(new Action_Produce(source_army, city, false, stack->getPos(), army->getId(), stack->getId()));
3367 addAction(new Action_ReorderArmies(stack));
3368 }
3369 }
3370 else
3371 {
3372 if (vectored)
3373 {
3374 //send vectoring action.
3375 const ArmyProdBase *source_army = city->getActiveProductionBase();
3376 addAction(new Action_Produce(source_army, city, true,
3377 city->getVectoring(), 0, 0));
3378 }
3379 }
3380 return true;
3381 }
3382
doVectoredUnitArrives(VectoredUnit * unit,Stack * & s)3383 Army* Player::doVectoredUnitArrives(VectoredUnit *unit, Stack *& s)
3384 {
3385 Army *army = unit->armyArrives(s);
3386 return army;
3387 }
3388
vectoredUnitArrives(VectoredUnit * unit)3389 bool Player::vectoredUnitArrives(VectoredUnit *unit)
3390 {
3391 Stack *stack = NULL;
3392 Army *army = doVectoredUnitArrives(unit, stack);
3393 if (!army)
3394 {
3395 printf("this was supposed to be impossible because of operations on the vectoredunitlist after the city is conquered.\n");
3396 printf("whooops... this vectored unit failed to show up.\n");
3397 City *dest = GameMap::getCity(unit->getDestination());
3398 printf("the unit was being vectored to: %s, from %s by %s\n",
3399 dest->getName().c_str(),
3400 GameMap::getCity(unit->getPos())->getName().c_str(), getName().c_str());
3401 printf("Army is a %s, turns is %d + 1\n", unit->getArmy()->getName().c_str(), unit->getArmy()->getProduction());
3402
3403
3404 int turn = -1;
3405 std::list<History*> h = dest->getOwner()->getHistoryForCityId(dest->getId());
3406 std::list<History*>::const_iterator pit;
3407 for (pit = h.begin(); pit != h.end(); pit++)
3408 {
3409 switch ((*pit)->getType())
3410 {
3411 case History::START_TURN:
3412 {
3413 turn++;
3414 break;
3415 }
3416 case History::CITY_WON:
3417 break;
3418 case History::CITY_RAZED:
3419 break;
3420 default:
3421 break;
3422 }
3423 }
3424 printf("was the destination city owned by us way back then?\n");
3425 exit (1);
3426 }
3427 else
3428 addAction(new Action_ProduceVectored(unit->getArmy(),
3429 unit->getDestination(),
3430 unit->getPos(), army->getId(),
3431 stack->getId()));
3432
3433 return true;
3434 }
3435
getUnitsProducedThisTurn() const3436 std::list<Action_Produce *> Player::getUnitsProducedThisTurn() const
3437 {
3438 std::list<Action_Produce *> actions;
3439 std::list<Action *>::const_reverse_iterator it = d_actions.rbegin();
3440 for (; it != d_actions.rend(); it++)
3441 {
3442 if ((*it)->getType() == Action::PRODUCE_UNIT)
3443 actions.push_back(dynamic_cast<Action_Produce*>(*it));
3444 else if ((*it)->getType() == Action::INIT_TURN)
3445 break;
3446 }
3447 return actions;
3448 }
3449
getReportableActions() const3450 std::list<Action *> Player::getReportableActions() const
3451 {
3452 std::list<Action *> actions;
3453 for (auto it: d_actions)
3454 {
3455 if (it->getType() == Action::PRODUCE_UNIT ||
3456 it->getType() == Action::PRODUCE_VECTORED_UNIT ||
3457 it->getType() == Action::CITY_DESTITUTE)
3458 actions.push_back(it);
3459 }
3460 return actions;
3461 }
3462
cityTooPoorToProduce(City * city,int slot)3463 void Player::cityTooPoorToProduce(City *city, int slot)
3464 {
3465 cityChangeProduction(city, -1);
3466 const ArmyProdBase *a = city->getProductionBase(slot);
3467 addAction(new Action_CityTooPoorToProduce(city, a));
3468 }
3469
pruneActionlist()3470 void Player::pruneActionlist()
3471 {
3472 pruneActionlist(d_actions);
3473 }
3474
pruneCityProductions(std::list<Action * > & actions)3475 void Player::pruneCityProductions(std::list<Action*> &actions)
3476 {
3477 //remove duplicate city production actions
3478
3479 //enumerate the ones we want
3480 std::list<Action_Production*> keepers;
3481 std::list<Action*>::reverse_iterator ait;
3482 for (ait = actions.rbegin(); ait != actions.rend(); ait++)
3483 {
3484 if ((*ait)->getType() != Action::CITY_PROD)
3485 continue;
3486 //if this city isn't already in the keepers list, then add it.
3487
3488 Action_Production *action = static_cast<Action_Production*>(*ait);
3489 bool found = false;
3490 std::list<Action_Production*>::const_iterator it;
3491 for (it = keepers.begin(); it != keepers.end(); it++)
3492 {
3493 if (action->getCityId() == (*it)->getCityId())
3494 {
3495 found = true;
3496 break;
3497 }
3498 }
3499 if (found == false)
3500 keepers.push_back(action);
3501
3502 }
3503
3504 //now delete all city production events that aren't in keepers
3505 int total = 0;
3506 std::list<Action*>::iterator bit;
3507 for (bit = actions.begin(); bit != actions.end(); bit++)
3508 {
3509 if ((*bit)->getType() != Action::CITY_PROD)
3510 continue;
3511 if (find (keepers.begin(), keepers.end(), (*bit)) == keepers.end())
3512 {
3513 total++;
3514 delete *bit;
3515 actions.erase (bit);
3516 bit = actions.begin();
3517 continue;
3518 }
3519 }
3520 }
3521
pruneCityVectorings(std::list<Action * > & actions)3522 void Player::pruneCityVectorings(std::list<Action*> &actions)
3523 {
3524 //remove duplicate city vectoring actions
3525
3526 //enumerate the ones we want
3527 std::list<Action_Vector*> keepers;
3528 std::list<Action*>::reverse_iterator ait;
3529 for (ait = actions.rbegin(); ait != actions.rend(); ait++)
3530 {
3531 if ((*ait)->getType() != Action::CITY_VECTOR)
3532 continue;
3533 //if this city isn't already in the keepers list, then add it.
3534
3535 Action_Vector *action = static_cast<Action_Vector *>(*ait);
3536 bool found = false;
3537 std::list<Action_Vector*>::const_iterator it;
3538 for (it = keepers.begin(); it != keepers.end(); it++)
3539 {
3540 if (action->getCityId() == (*it)->getCityId())
3541 {
3542 found = true;
3543 break;
3544 }
3545 }
3546 if (found == false)
3547 keepers.push_back(action);
3548
3549 }
3550
3551 //now delete all city vector events that aren't in keepers
3552 int total = 0;
3553 std::list<Action*>::iterator bit;
3554 for (bit = actions.begin(); bit != actions.end(); bit++)
3555 {
3556 if ((*bit)->getType() != Action::CITY_VECTOR)
3557 continue;
3558 if (find (keepers.begin(), keepers.end(), (*bit)) == keepers.end())
3559 {
3560 total++;
3561 delete *bit;
3562 actions.erase (bit);
3563 bit = actions.begin();
3564 continue;
3565 }
3566 }
3567 }
3568
pruneActionlist(std::list<Action * > & actions)3569 void Player::pruneActionlist(std::list<Action*> &actions)
3570 {
3571 pruneCityProductions(actions);
3572 pruneCityVectorings(actions);
3573
3574 }
3575
playerTypeToString(const Player::Type type)3576 Glib::ustring Player::playerTypeToString(const Player::Type type)
3577 {
3578 switch (type)
3579 {
3580 case Player::HUMAN: return "Player::HUMAN";
3581 case Player::AI_FAST: return "Player::AI_FAST";
3582 case Player::AI_DUMMY: return "Player::AI_DUMMY";
3583 case Player::AI_SMART: return "Player::AI_SMART";
3584 case Player::NETWORKED: return "Player::NETWORKED";
3585 }
3586 return "Player::HUMAN";
3587 }
3588
playerTypeFromString(const Glib::ustring str)3589 Player::Type Player::playerTypeFromString(const Glib::ustring str)
3590 {
3591 if (str.size() > 0 && isdigit(str.c_str()[0]))
3592 return Player::Type(atoi(str.c_str()));
3593 if (str == "Player::HUMAN") return Player::HUMAN;
3594 else if (str == "Player::AI_FAST") return Player::AI_FAST;
3595 else if (str == "Player::AI_DUMMY") return Player::AI_DUMMY;
3596 else if (str == "Player::AI_SMART") return Player::AI_SMART;
3597 else if (str == "Player::NETWORKED") return Player::NETWORKED;
3598 return Player::HUMAN;
3599 }
3600
hasAlreadyInitializedTurn() const3601 bool Player::hasAlreadyInitializedTurn() const
3602 {
3603 for (auto it: d_actions)
3604 if (it->getType() == Action::INIT_TURN)
3605 return true;
3606 return false;
3607 }
3608
hasAlreadyCollectedTaxesAndPaidUpkeep() const3609 bool Player::hasAlreadyCollectedTaxesAndPaidUpkeep() const
3610 {
3611 for (auto it: d_actions)
3612 if (it->getType() == Action::COLLECT_TAXES_AND_PAY_UPKEEP)
3613 return true;
3614 return false;
3615 }
3616
hasAlreadyEndedTurn() const3617 bool Player::hasAlreadyEndedTurn() const
3618 {
3619 for (auto it: d_actions)
3620 if (it->getType() == Action::END_TURN)
3621 return true;
3622 return false;
3623 }
3624
countEndTurnHistoryEntries() const3625 guint32 Player::countEndTurnHistoryEntries() const
3626 {
3627 guint32 count = 0;
3628 for (std::list<History*>::const_iterator it = d_history.begin();
3629 it != d_history.end(); it++)
3630 {
3631 if ((*it)->getType() == History::END_TURN)
3632 count++;
3633 }
3634 return count;
3635 }
3636
searchedRuin(Ruin * r) const3637 bool Player::searchedRuin(Ruin *r) const
3638 {
3639 if (!r)
3640 return false;
3641 for (std::list<History*>::const_iterator it = d_history.begin();
3642 it != d_history.end(); it++)
3643 {
3644 if ((*it)->getType() == History::HERO_RUIN_EXPLORED)
3645 {
3646 History_HeroRuinExplored *event =
3647 dynamic_cast<History_HeroRuinExplored*>(*it);
3648 if (event->getRuinId() == r->getId())
3649 return true;
3650 }
3651 }
3652 return false;
3653 }
3654
conqueredCity(City * c,guint32 & turns_ago) const3655 bool Player::conqueredCity(City *c, guint32 &turns_ago) const
3656 {
3657 if (!c)
3658 return false;
3659 for (std::list<History*>::const_reverse_iterator it = d_history.rbegin();
3660 it != d_history.rend(); it++)
3661 {
3662 if ((*it)->getType() == History::CITY_WON)
3663 {
3664 History_CityWon *event = dynamic_cast<History_CityWon*>(*it);
3665 if (event->getCityId() == c->getId())
3666 return true;
3667 }
3668 else if ((*it)->getType() == History::START_TURN)
3669 turns_ago++;
3670
3671 }
3672 return false;
3673 }
3674
getStackTrack(Stack * s) const3675 std::list<Vector<int> > Player::getStackTrack(Stack *s) const
3676 {
3677 std::list<Vector<int> > points;
3678 Vector<int> delta = Vector<int>(0,0);
3679 for (auto it: d_actions)
3680 {
3681 if (it->getType() == Action::STACK_MOVE)
3682 {
3683 Action_Move *action = dynamic_cast<Action_Move*>(it);
3684 if (action->getStackId() == s->getId())
3685 {
3686 if (points.size() == 0)
3687 delta = action->getPositionDelta();
3688 points.push_back(action->getEndingPosition());
3689 }
3690 }
3691 }
3692 if (points.size() >= 1)
3693 {
3694 Vector<int> pos = points.front() - delta;
3695 if (pos != points.front())
3696 points.push_front(pos);
3697 }
3698 return points;
3699 }
3700
getHistoryForCityId(guint32 id) const3701 std::list<History *>Player::getHistoryForCityId(guint32 id) const
3702 {
3703 std::list<History*> events;
3704 std::list<History*>::const_iterator pit;
3705 for (pit = d_history.begin(); pit != d_history.end(); pit++)
3706 {
3707 switch ((*pit)->getType())
3708 {
3709 case History::START_TURN:
3710 {
3711 events.push_back(*pit);
3712 break;
3713 }
3714 case History::CITY_WON:
3715 {
3716 History_CityWon *event;
3717 event = dynamic_cast<History_CityWon*>(*pit);
3718 if (event->getCityId() == id)
3719 events.push_back(*pit);
3720 break;
3721 }
3722 case History::CITY_RAZED:
3723 {
3724 History_CityRazed *event;
3725 event = dynamic_cast<History_CityRazed*>(*pit);
3726 if (event->getCityId() == id)
3727 events.push_back(*pit);
3728 break;
3729 }
3730 default:
3731 break;
3732 }
3733 }
3734 return events;
3735 }
3736
getHistoryForHeroId(guint32 id) const3737 std::list<History *>Player::getHistoryForHeroId(guint32 id) const
3738 {
3739 Glib::ustring hero_name = "";
3740 std::list<History*> events;
3741 std::list<History*>::const_iterator pit;
3742 for (pit = d_history.begin(); pit != d_history.end(); pit++)
3743 {
3744 switch ((*pit)->getType())
3745 {
3746 case History::HERO_EMERGES:
3747 {
3748 History_HeroEmerges *event;
3749 event = dynamic_cast<History_HeroEmerges *>(*pit);
3750 if (event->getHeroId() == id)
3751 {
3752 hero_name = event->getHeroName();
3753 events.push_back(*pit);
3754 }
3755 break;
3756 }
3757 case History::FOUND_SAGE:
3758 {
3759 History_FoundSage *event;
3760 event = dynamic_cast<History_FoundSage*>(*pit);
3761 if (event->getHeroName() == hero_name)
3762 events.push_back(*pit);
3763 break;
3764 }
3765 case History::HERO_QUEST_STARTED:
3766 {
3767 History_HeroQuestStarted *event;
3768 event = dynamic_cast<History_HeroQuestStarted*>(*pit);
3769 if (event->getHeroName() == hero_name)
3770 events.push_back(*pit);
3771 break;
3772 }
3773 case History::HERO_QUEST_COMPLETED:
3774 {
3775 History_HeroQuestCompleted *event;
3776 event = dynamic_cast<History_HeroQuestCompleted*>(*pit);
3777 if (event->getHeroName() == hero_name)
3778 events.push_back(*pit);
3779 break;
3780 }
3781 case History::HERO_KILLED_IN_CITY:
3782 {
3783 History_HeroKilledInCity *event;
3784 event = dynamic_cast<History_HeroKilledInCity*>(*pit);
3785 if (event->getHeroName() == hero_name)
3786 events.push_back(*pit);
3787 break;
3788 }
3789 case History::HERO_KILLED_IN_BATTLE:
3790 {
3791 History_HeroKilledInBattle *event;
3792 event = dynamic_cast<History_HeroKilledInBattle*>(*pit);
3793 if (event->getHeroName() == hero_name)
3794 events.push_back(*pit);
3795 break;
3796 }
3797 case History::HERO_KILLED_SEARCHING:
3798 {
3799 History_HeroKilledSearching*event;
3800 event = dynamic_cast<History_HeroKilledSearching*>(*pit);
3801 if (event->getHeroName() == hero_name)
3802 events.push_back(*pit);
3803 break;
3804 }
3805 case History::HERO_CITY_WON:
3806 {
3807 History_HeroCityWon *event;
3808 event = dynamic_cast<History_HeroCityWon*>(*pit);
3809 if (event->getHeroName() == hero_name)
3810 events.push_back(*pit);
3811 break;
3812 }
3813 case History::HERO_FINDS_ALLIES:
3814 {
3815 History_HeroFindsAllies *event;
3816 event = dynamic_cast<History_HeroFindsAllies*>(*pit);
3817 if (event->getHeroName() == hero_name)
3818 events.push_back(*pit);
3819 break;
3820 }
3821 default:
3822 break;
3823 }
3824 }
3825 return events;
3826 }
3827
setSurrendered(bool surr)3828 void Player::setSurrendered(bool surr)
3829 {
3830 surrendered = surr;
3831 }
3832
getHeroes() const3833 std::list<Hero*> Player::getHeroes() const
3834 {
3835 return d_stacklist->getHeroes();
3836 }
3837
countArmies() const3838 guint32 Player::countArmies() const
3839 {
3840 return d_stacklist->countArmies();
3841 }
3842
getActivestack() const3843 Stack * Player::getActivestack() const
3844 {
3845 return d_stacklist->getActivestack();
3846 }
3847
setActivestack(Stack * s)3848 void Player::setActivestack(Stack *s)
3849 {
3850 d_stacklist->setActivestack(s);
3851 }
3852
getPositionOfArmyById(guint32 id) const3853 Vector<int> Player::getPositionOfArmyById(guint32 id) const
3854 {
3855 return d_stacklist->getPosition(id);
3856 }
3857
immobilize()3858 void Player::immobilize()
3859 {
3860 d_stacklist->drainAllMovement();
3861 }
3862
clearStacklist()3863 void Player::clearStacklist()
3864 {
3865 d_stacklist->flClear();
3866 }
3867
clearFogMap()3868 void Player::clearFogMap()
3869 {
3870 d_fogmap->fill(FogMap::OPEN);
3871 }
3872
getActionsThisTurn(int type) const3873 std::list<Action *> Player::getActionsThisTurn(int type) const
3874 {
3875 std::list<Action *> actions;
3876 for (auto it: d_actions)
3877 if (it->getType() == Action::Type(type))
3878 actions.push_back(it);
3879 return actions;
3880 }
3881
getMovesThisTurn() const3882 std::list<Action *> Player::getMovesThisTurn() const
3883 {
3884 return getActionsThisTurn(Action::STACK_MOVE);
3885 }
3886
countDestituteCitiesThisTurn() const3887 int Player::countDestituteCitiesThisTurn() const
3888 {
3889 return getActionsThisTurn(Action::CITY_DESTITUTE).size();
3890 }
3891
AI_getQuestDestination(Quest * quest,Stack * stack) const3892 Vector<int> Player::AI_getQuestDestination(Quest *quest, Stack *stack) const
3893 {
3894 Vector<int> dest = Vector<int>(-1,-1);
3895 switch (quest->getType())
3896 {
3897 case Quest::KILLHERO:
3898 {
3899 QuestKillHero *q = dynamic_cast<QuestKillHero*>(quest);
3900 guint32 hero_id = q->getVictim();
3901 Stack *enemy = NULL;
3902 for (auto it: *Playerlist::getInstance())
3903 {
3904 if (it == this)
3905 continue;
3906 enemy = it->getStacklist()->getArmyStackById(hero_id);
3907 if(enemy)
3908 break;
3909 }
3910 if (enemy)
3911 dest = enemy->getPos();
3912
3913 }
3914 break;
3915 case Quest::KILLARMYTYPE:
3916 {
3917 QuestEnemyArmytype *q = dynamic_cast<QuestEnemyArmytype*>(quest);
3918 guint32 army_type = q->getArmytypeToKill();
3919 std::vector<Stack*> s =
3920 GameMap::getNearbyEnemyStacks(stack->getPos(), GameMap::getWidth());
3921 for (std::vector<Stack*>::iterator i = s.begin(); i != s.end(); i++)
3922 {
3923 if ((*i)->hasArmyType(army_type) == true)
3924 {
3925 dest = (*i)->getPos();
3926 break;
3927 }
3928 }
3929 }
3930 break;
3931 case Quest::KILLARMIES:
3932 {
3933 QuestEnemyArmies *q = dynamic_cast<QuestEnemyArmies*>(quest);
3934 auto enemy = Playerlist::getInstance()->getPlayer(q->getVictimPlayerId());
3935 auto s = GameMap::getNearbyEnemyStacks(stack->getPos(), GameMap::getWidth());
3936 for (std::vector<Stack*>::iterator i = s.begin(); i != s.end(); i++)
3937 {
3938 if ((*i)->getOwner() != enemy)
3939 continue;
3940 dest = (*i)->getPos();
3941 }
3942 }
3943 break;
3944
3945 case Quest::PILLAGEGOLD:
3946 case Quest::CITYSACK:
3947 case Quest::CITYRAZE:
3948 case Quest::CITYOCCUPY:
3949 //attack the nearest enemy city.
3950 {
3951 City *c = Citylist::getInstance()->getClosestEnemyCity(stack);
3952 if (c)
3953 dest = c->getNearestPos(stack->getPos());
3954 }
3955 break;
3956 }
3957 return dest;
3958 }
3959
AI_invadeCityQuestPreference(City * c,CityDefeatedAction & action) const3960 bool Player::AI_invadeCityQuestPreference(City *c, CityDefeatedAction &action) const
3961 {
3962 bool found = false;
3963 std::vector<Quest*> q = QuestsManager::getInstance()->getPlayerQuests(this);
3964 for (std::vector<Quest*>::iterator i = q.begin(); i != q.end(); i++)
3965 {
3966 if (*i == NULL)
3967 continue;
3968 switch ((*i)->getType())
3969 {
3970 case Quest::CITYOCCUPY:
3971 {
3972 QuestCityOccupy* qu = dynamic_cast<QuestCityOccupy*>(*i);
3973 if (qu->getCityId() == c->getId())
3974 {
3975 action = CITY_DEFEATED_OCCUPY;
3976 found = true;
3977 }
3978 }
3979 break;
3980 case Quest::CITYSACK:
3981 {
3982 QuestCitySack * qu = dynamic_cast<QuestCitySack*>(*i);
3983 if (qu->getCityId() == c->getId())
3984 {
3985 action = CITY_DEFEATED_SACK;
3986 found = true;
3987 }
3988 }
3989 break;
3990 case Quest::CITYRAZE:
3991 {
3992 QuestCityRaze* qu = dynamic_cast<QuestCityRaze*>(*i);
3993 if (qu->getCityId() == c->getId())
3994 {
3995 action = CITY_DEFEATED_RAZE;
3996 found = true;
3997 }
3998 }
3999 break;
4000 case Quest::PILLAGEGOLD:
4001 action = CITY_DEFEATED_SACK;
4002 found = true;
4003 break;
4004 }
4005 }
4006 return found;
4007 }
4008
4009 /*
4010 *
4011 * what are the chances of a hero showing up?
4012 *
4013 * 1 in 6 if you have enough gold, where "enough gold" is...
4014 *
4015 * ... 1500 if the player already has a hero, then: 1500 is generally
4016 * enough to buy all the heroes. I forget the exact distribution of
4017 * hero prices but memory says from 1000 to 1500. (But, if you don't
4018 * have 1500 gold, and the price is less, you still get the offer...
4019 * So, calculate price, compare to available gold, then decided whether
4020 * or not to offer...)
4021 *
4022 * ...500 if all your heroes are dead: then prices are cut by about
4023 * a factor of 3.
4024 */
maybeRecruitHero()4025 bool Player::maybeRecruitHero ()
4026 {
4027 bool accepted = false;
4028
4029 City *city = NULL;
4030 int gold_needed = 0;
4031 if (Citylist::getInstance()->countCities(this) == 0)
4032 return false;
4033 //give the player a hero if it's the first round.
4034 //otherwise we get a hero based on chance
4035 //a hero costs a random number of gold pieces
4036 if (GameScenarioOptions::s_round == 1 && getHeroes().size() == 0)
4037 gold_needed = 0;
4038 else
4039 {
4040 bool exists = false;
4041 if (getHeroes().size() > 0)
4042 exists = true;
4043
4044 gold_needed = (Rnd::rand() % 500) + 1000;
4045 if (exists == false)
4046 gold_needed /= 2;
4047 }
4048
4049 if ((((Rnd::rand() % 6) == 0 && gold_needed < getGold()) || gold_needed == 0))
4050 {
4051 HeroProto *heroproto =
4052 HeroTemplates::getInstance()->getRandomHero(getId());
4053 if (gold_needed == 0)
4054 {
4055 //we do it this way because maybe quickstart is on.
4056 city = Citylist::getInstance()->getCapitalCity(this);
4057 if (!city || city->isBurnt() == true)
4058 city = getFirstCity();
4059 }
4060 else
4061 city = Citylist::getInstance()->getRandomCityForHero(this);
4062
4063 if (srecruitingHero.empty())
4064 accepted = true;
4065 else if (city)
4066 accepted = srecruitingHero.emit(heroproto, city, gold_needed);
4067
4068 if (accepted) {
4069 /* now maybe add a few allies */
4070 int alliesCount;
4071 if (gold_needed > 1300)
4072 alliesCount = 3;
4073 else if (gold_needed > 1000)
4074 alliesCount = 2;
4075 else if (gold_needed > 800)
4076 alliesCount = 1;
4077 else
4078 alliesCount = 0;
4079
4080 const ArmyProto *ally = 0;
4081 if (alliesCount > 0)
4082 {
4083 ally = Reward_Allies::randomArmyAlly();
4084 if (!ally)
4085 alliesCount = 0;
4086 }
4087
4088 StackReflist *stacks = new StackReflist();
4089 recruitHero(heroproto, city, gold_needed, alliesCount, ally, stacks);
4090 delete stacks;
4091 }
4092 }
4093 return accepted;
4094 }
4095
getStacksWithItems() const4096 std::list<Stack*> Player::getStacksWithItems() const
4097 {
4098 return getStacklist()->getStacksWithItems();
4099 }
4100
setPathOfStackToPreviousDestination(Stack * stack)4101 bool Player::setPathOfStackToPreviousDestination(Stack *stack)
4102 {
4103 std::list<Action*>moves = getMovesThisTurn();
4104 if (moves.size() > 0)
4105 {
4106 Vector<int> dest = Vector<int>(-1,-1);
4107 std::list<Action*>::const_reverse_iterator it =
4108 moves.rbegin();
4109 for (;it != moves.rend(); it++)
4110 {
4111 if ((*it)->getType() != Action::STACK_MOVE)
4112 continue;
4113 Action_Move *move = dynamic_cast<Action_Move*>(*it);
4114 guint32 id = move->getStackId();
4115 if (id == stack->getId())
4116 continue;
4117 Stack *prev = d_stacklist->getStackById(id);
4118 if (!prev)
4119 dest = move->getEndingPosition();
4120 else
4121 {
4122 dest = prev->getLastPointInPath();
4123 if (dest == Vector<int>(-1,-1))
4124 dest = move->getEndingPosition();
4125 }
4126 break;
4127 }
4128 if (dest != Vector<int>(-1,-1))
4129 {
4130 PathCalculator *path_calculator = new PathCalculator(stack);
4131 guint32 total_moves = 0, turns = 0, left = 0;
4132 Path *new_path = path_calculator->calculate(dest, total_moves, turns,
4133 left, true);
4134 if (new_path->size())
4135 stack->setPath(*new_path);
4136 delete new_path;
4137 delete path_calculator;
4138
4139 return true;
4140 }
4141 }
4142 return false;
4143 }
4144
doHeroUseItem(Hero * hero,Item * item,Player * victim,City * friendly_city,City * enemy_city,City * neutral_city,City * city)4145 bool Player::doHeroUseItem(Hero *hero, Item *item, Player *victim,
4146 City *friendly_city, City *enemy_city, City *neutral_city, City *city)
4147 {
4148 if (item->getBonus() & ItemProto::STEAL_GOLD)
4149 {
4150 assert (victim != NULL);
4151 double percent = item->getPercentGoldToSteal();
4152 if (percent > 100)
4153 percent = 100;
4154 else if (percent < 0)
4155 percent = 0;
4156 int gold = victim->getGold() * (percent / 100.0);
4157 if (gold > 0)
4158 {
4159 victim->withdrawGold(gold);
4160 addGold(gold);
4161 stole_gold.emit(victim, gold);
4162 }
4163 }
4164 if (item->getBonus() & ItemProto::SINK_SHIPS)
4165 {
4166 assert (victim != NULL);
4167 std::list<Stack*> sunk = victim->getStacklist()->killArmyUnitsInBoats();
4168 std::list<History*> history;
4169 guint32 num_armies = removeDeadArmies(sunk, history);
4170 sunk_ships.emit(victim, num_armies);
4171 }
4172 if (item->getBonus() & ItemProto::PICK_UP_BAGS)
4173 {
4174 guint32 num_bags = 0;
4175 std::list<MapBackpack*> bags = GameMap::getInstance()->getBackpacks();
4176 num_bags = bags.size();
4177 std::list<MapBackpack*>::iterator it = bags.begin();
4178 for (; it != bags.end(); it++)
4179 doHeroPickupAllItems(hero, (*it)->getPos());
4180 bags_picked_up.emit(hero, num_bags);
4181 }
4182 if (item->getBonus() & ItemProto::ADD_2MP_STACK)
4183 {
4184 guint32 mp = 2;
4185 Stack *stack = getStacklist()->getArmyStackById(hero->getId());
4186 stack->incrementMoves(mp);
4187 mp_added_to_hero_stack.emit(hero, mp);
4188 }
4189 if (item->getBonus() & ItemProto::BANISH_WORMS)
4190 {
4191 guint32 num_worms_killed = 0;
4192 std::list<History*> history;
4193 for (auto j: *Playerlist::getInstance())
4194 {
4195 std::list<Stack*> affected =
4196 j->getStacklist()->killArmies(item->getArmyTypeToKill());
4197 if (affected.size())
4198 num_worms_killed += removeDeadArmies(affected, history);
4199 }
4200 const ArmyProto *a = Armysetlist::getInstance()->getArmy(Playerlist::getActiveplayer()->getArmyset(), item->getArmyTypeToKill());
4201 worms_killed.emit(hero, a->getName(), num_worms_killed);
4202 }
4203 if (item->getBonus() & ItemProto::BURN_BRIDGE)
4204 {
4205 //am i on a bridge?
4206 Vector<int> pos = d_stacklist->getPosition(hero->getId());
4207 bool burned = GameMap::getInstance()->burnBridge(pos);
4208 if (burned)
4209 bridge_burned.emit(hero);
4210 }
4211 if (item->getBonus() & ItemProto::CAPTURE_KEEPER)
4212 {
4213 Vector<int> pos = d_stacklist->getPosition(hero->getId());
4214 Ruin *ruin = GameMap::getInstance()->getRuin(pos);
4215 if (ruin && ruin->isSearched() == false)
4216 {
4217 if (ruin->getOccupant() && ruin->getOccupant ()->getStack () &&
4218 ruin->getOccupant()->getStack ()->size() > 0)
4219 {
4220 Glib::ustring name = ruin->getOccupant()->getName();
4221 addStack(ruin->getOccupant()->getStack ());
4222 ruin->clearOccupant();
4223 keeper_captured.emit(hero, ruin, name);
4224 }
4225 }
4226 }
4227 if (item->getBonus() & ItemProto::SUMMON_MONSTER)
4228 {
4229 Vector<int> pos = d_stacklist->getPosition(hero->getId());
4230 Maptile::Building building = GameMap::getInstance()->getBuilding(pos);
4231 if (building == item->getBuildingTypeToSummonOn() ||
4232 item->getBuildingTypeToSummonOn() == 0)
4233 {
4234 Stack *stack = getStacklist()->getArmyStackById(hero->getId());
4235 StackReflist *stacks = new StackReflist();
4236 //okay we're going to add some allies now.
4237 const ArmyProto *a = Armysetlist::getInstance()->getArmy(Playerlist::getActiveplayer()->getArmyset(), item->getArmyTypeToSummon());
4238 Reward *reward = new Reward_Allies(a, 1);
4239 giveReward(stack, reward, stacks, false);
4240 delete reward;
4241 delete stacks;
4242 monster_summoned.emit(hero, a->getName());
4243 }
4244 }
4245 if (item->getBonus() & ItemProto::DISEASE_CITY)
4246 {
4247 if (enemy_city)
4248 {
4249 std::list<History*> history;
4250 std::list<Stack*> affected =
4251 enemy_city->diseaseDefenders(item->getPercentArmiesToKill());
4252 guint32 num_armies_killed = removeDeadArmies(affected, history);
4253 city_diseased.emit(hero, enemy_city->getName(), num_armies_killed);
4254 }
4255 }
4256 if (item->getBonus() & ItemProto::RAISE_DEFENDERS)
4257 {
4258 if (friendly_city)
4259 {
4260 //okay we're going to add some allies now.
4261 const ArmyProto *a = Armysetlist::getInstance()->getArmy(Playerlist::getActiveplayer()->getArmyset(), item->getArmyTypeToRaise());
4262 GameMap::getInstance()->addArmies(a, item->getNumberOfArmiesToRaise(),
4263 friendly_city->getPos());
4264 city_defended.emit(hero, friendly_city->getName(), a->getName(),
4265 item->getNumberOfArmiesToRaise());
4266 }
4267 }
4268 if (item->getBonus() & ItemProto::PERSUADE_NEUTRALS)
4269 {
4270 if (neutral_city)
4271 {
4272 Stack *stack = getStacklist()->getArmyStackById(hero->getId());
4273 neutral_city->persuadeDefenders(this);
4274 takeCityInPossession(neutral_city);
4275 QuestsManager::getInstance()->cityOccupied(neutral_city, stack);
4276 city_persuaded.emit(hero, neutral_city->getName(),
4277 neutral_city->countDefenders());
4278 }
4279 }
4280 if (item->getBonus() & ItemProto::TELEPORT_TO_CITY)
4281 {
4282 if (city)
4283 {
4284 Stack *s = getStacklist()->getArmyStackById(hero->getId());
4285 for (Stack::iterator i = s->begin(); i != s->end(); ++i)
4286 {
4287 if (city->getOwner() != s->getOwner())
4288 GameMap::getInstance()->addArmyAtPos(city->getPos(), *i);
4289 else
4290 GameMap::getInstance()->addArmy(city->getPos(), *i);
4291 }
4292 s->clear();
4293 deleteStack(s);
4294 //where do we teleport to?
4295 stack_teleported.emit(hero, city->getName());
4296 supdatingStack.emit(getStacklist()->getArmyStackById(hero->getId()));
4297 }
4298 }
4299
4300 hero->getBackpack()->useItem(item);
4301 supdatingStack.emit(0);
4302 return true;
4303 }
4304
heroUseItem(Hero * hero,Item * item,Player * victim,City * friendly_city,City * enemy_city,City * neutral_city,City * city)4305 bool Player::heroUseItem(Hero *hero, Item *item, Player *victim,
4306 City *friendly_city, City *enemy_city,
4307 City *neutral_city, City *city)
4308 {
4309 if (doHeroUseItem(hero, item, victim, friendly_city, enemy_city,
4310 neutral_city, city))
4311 {
4312 addAction(new Action_UseItem(hero, item, victim, friendly_city,
4313 enemy_city, neutral_city, city));
4314 addHistory (new History_HeroUseItem(hero, item, victim, friendly_city,
4315 enemy_city, neutral_city, city));
4316 return true;
4317 }
4318 return false;
4319 }
4320
getUsableItems() const4321 std::list<Item*> Player::getUsableItems() const
4322 {
4323 return d_stacklist->getUsableItems();
4324 }
4325
hasUsableItem() const4326 bool Player::hasUsableItem() const
4327 {
4328 return d_stacklist->hasUsableItem();
4329 }
4330
getItemHolder(Item * item,Stack ** stack,Hero ** hero) const4331 bool Player::getItemHolder(Item *item, Stack **stack, Hero **hero) const
4332 {
4333 return d_stacklist->getItemHolder(item, stack, hero);
4334 }
4335
tallyDeadArmyTriumphs(std::list<Stack * > & stacks)4336 void Player::tallyDeadArmyTriumphs(std::list<Stack*> &stacks)
4337 {
4338 std::list<Stack*>::iterator it;
4339 for (it = stacks.begin(); it != stacks.end(); it++)
4340 {
4341 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
4342 {
4343 if ((*sit)->getHP() > 0)
4344 continue;
4345 //Tally up the triumphs
4346 Player *enemy = (*sit)->getOwner();
4347 if ((*sit)->getAwardable()) //hey a special ally died
4348 d_triumphs->tallyTriumph(enemy, Triumphs::TALLY_SPECIAL);
4349 else if ((*sit)->isHero())
4350 {
4351 d_triumphs->tallyTriumph(enemy, Triumphs::TALLY_HERO);
4352 Hero *hero = dynamic_cast<Hero*>((*sit));
4353 guint32 count = hero->getBackpack()->countPlantableItems();
4354 for (guint32 i = 0; i < count; i++)
4355 d_triumphs->tallyTriumph(enemy, Triumphs::TALLY_FLAG);
4356 }
4357 else if ((*sit)->getStat(Army::SHIP, false)) //hey it was on a boat
4358 d_triumphs->tallyTriumph(enemy, Triumphs::TALLY_SHIP);
4359 else if ((*sit)->isHero() == false)
4360 d_triumphs->tallyTriumph(enemy, Triumphs::TALLY_NORMAL);
4361 }
4362 }
4363 return;
4364 }
4365
handleDeadHero(Hero * h,Maptile * tile,Vector<int> pos)4366 History* Player::handleDeadHero(Hero *h, Maptile *tile, Vector<int> pos)
4367 {
4368 if (tile->getBuilding() == Maptile::RUIN)
4369 return new History_HeroKilledSearching(h);
4370 else if (tile->getBuilding() == Maptile::CITY)
4371 {
4372 City* c = GameMap::getCity(pos);
4373 return new History_HeroKilledInCity(h, c);
4374 }
4375 else //somewhere else
4376 return new History_HeroKilledInBattle(h);
4377 return NULL;
4378 }
4379
handleDeadHeroes(std::list<Stack * > & stacks,std::list<History * > & history)4380 void Player::handleDeadHeroes(std::list<Stack*> &stacks, std::list<History*> &history)
4381 {
4382 std::list<Stack*>::iterator it;
4383 for (it = stacks.begin(); it != stacks.end(); it++)
4384 {
4385 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
4386 {
4387 if ((*sit)->getHP() > 0)
4388 continue;
4389 if ((*sit)->isHero() == false)
4390 continue;
4391 //one of our heroes died
4392 //drop hero's stuff
4393 //now record the details of the death
4394
4395 bool splash = false;
4396 doHeroDropAllItems (static_cast<Hero*>(*sit), (*it)->getPos(),
4397 splash);
4398 Maptile *tile = GameMap::getInstance()->getTile((*it)->getPos());
4399
4400 History *item = handleDeadHero (static_cast<Hero*>(*sit), tile,
4401 (*it)->getPos());
4402 if (item)
4403 history.push_back(item);
4404 }
4405 }
4406 return;
4407 }
4408
handleDeadArmiesForQuests(std::list<Stack * > & stacks,std::vector<guint32> & culprits)4409 void Player::handleDeadArmiesForQuests(std::list<Stack*> &stacks,
4410 std::vector<guint32> &culprits)
4411 {
4412 std::list<Stack*>::iterator it;
4413 for (it = stacks.begin(); it != stacks.end(); it++)
4414 {
4415 if ((*it)->getOwner() == this)
4416 continue;
4417 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
4418 {
4419 if ((*sit)->getHP() == 0)
4420 QuestsManager::getInstance()->armyDied(*sit, culprits);
4421 }
4422 }
4423 return;
4424 }
4425
countXPFromDeadArmies(std::list<Stack * > & stacks)4426 double Player::countXPFromDeadArmies(std::list<Stack*>& stacks)
4427 {
4428 double total = 0.0;
4429 std::list<Stack*>::iterator it;
4430 for (it = stacks.begin(); it != stacks.end(); it++)
4431 {
4432 if ((*it)->getOwner() == this)
4433 continue;
4434 for (Stack::iterator sit = (*it)->begin(); sit != (*it)->end(); sit++)
4435 {
4436 if ((*sit)->getHP() > 0)
4437 continue;
4438
4439 //Add the XP bonus to the total of the battle;
4440 total += (*sit)->getXpReward();
4441 }
4442 }
4443 return total;
4444 }
4445
doStackSort(Stack * s,std::list<guint32> army_ids)4446 void Player::doStackSort(Stack *s, std::list<guint32> army_ids)
4447 {
4448 return s->sortByIds(army_ids);
4449 }
4450
doStacksReset()4451 void Player::doStacksReset()
4452 {
4453 getStacklist()->resetStacks();
4454 }
4455
stacksReset()4456 void Player::stacksReset()
4457 {
4458 doStacksReset();
4459 addAction(new Action_ResetStacks(this));
4460 }
4461
doRuinsReset()4462 void Player::doRuinsReset()
4463 {
4464 if (this != Playerlist::getInstance()->getNeutral())
4465 return;
4466 for (auto it: *Ruinlist::getInstance())
4467 {
4468 Keeper* keeper = it->getOccupant();
4469 if (keeper)
4470 {
4471 if (keeper->getStack ())
4472 keeper->getStack ()->reset();
4473 }
4474 }
4475 }
4476
ruinsReset()4477 void Player::ruinsReset()
4478 {
4479 doRuinsReset();
4480 addAction(new Action_ResetRuins());
4481 }
4482
doCollectTaxesAndPayUpkeep()4483 void Player::doCollectTaxesAndPayUpkeep()
4484 {
4485 //collect monies from cities
4486 Citylist::getInstance()->collectTaxes(this);
4487
4488 //factor in the gold-per-city items that heroes may hold
4489 guint32 num_cities = Citylist::getInstance()->countCities(this);
4490 getStacklist()->collectTaxes(this, num_cities);
4491
4492 //pay for existing armies
4493 getStacklist()->payUpkeep(this);
4494 }
4495
collectTaxesAndPayUpkeep()4496 void Player::collectTaxesAndPayUpkeep()
4497 {
4498 if (hasAlreadyCollectedTaxesAndPaidUpkeep())
4499 return;
4500 int prev_gold = getGold();
4501 doCollectTaxesAndPayUpkeep();
4502 Action_CollectTaxesAndPayUpkeep *a =
4503 new Action_CollectTaxesAndPayUpkeep (prev_gold, getGold());
4504 addAction(a);
4505 }
4506
doStackDefend(Stack * s)4507 void Player::doStackDefend(Stack *s)
4508 {
4509 s->setDefending(true);
4510 }
4511
stackDefend(Stack * s)4512 void Player::stackDefend(Stack *s)
4513 {
4514 doStackDefend(s);
4515 addAction(new Action_DefendStack(s));
4516 }
4517
doStackUndefend(Stack * s)4518 void Player::doStackUndefend(Stack *s)
4519 {
4520 s->setDefending(false);
4521 }
4522
stackUndefend(Stack * s)4523 void Player::stackUndefend(Stack *s)
4524 {
4525 doStackUndefend(s);
4526 addAction(new Action_UndefendStack(s));
4527 }
4528
doStackPark(Stack * s)4529 void Player::doStackPark(Stack *s)
4530 {
4531 s->setParked(true);
4532 }
4533
stackPark(Stack * s)4534 void Player::stackPark(Stack *s)
4535 {
4536 doStackPark(s);
4537 addAction(new Action_ParkStack(s));
4538 }
4539
parkAllStacks()4540 void Player::parkAllStacks()
4541 {
4542 for (auto s : *getStacklist())
4543 {
4544 if (s->getParked() == false)
4545 stackPark (s);
4546 }
4547 }
4548
doStackUnpark(Stack * s)4549 void Player::doStackUnpark(Stack *s)
4550 {
4551 s->setParked(false);
4552 }
4553
stackUnpark(Stack * s)4554 void Player::stackUnpark(Stack *s)
4555 {
4556 doStackUnpark(s);
4557 addAction(new Action_UnparkStack(s));
4558 }
4559
doStackSelect(Stack * s)4560 void Player::doStackSelect(Stack *s)
4561 {
4562 d_stacklist->setActivestack(s);
4563 }
4564
stackSelect(Stack * s)4565 void Player::stackSelect(Stack *s)
4566 {
4567 doStackSelect(s);
4568 addAction(new Action_SelectStack(s));
4569 }
4570
doStackDeselect()4571 void Player::doStackDeselect ()
4572 {
4573 d_stacklist->setActivestack(0);
4574 }
4575
stackDeselect()4576 void Player::stackDeselect ()
4577 {
4578 doStackDeselect();
4579 addAction(new Action_DeselectStack());
4580 }
4581
reportEndOfRound(guint32 score)4582 void Player::reportEndOfRound(guint32 score)
4583 {
4584 addHistory(new History_Score(score));
4585 addHistory(new History_GoldTotal(d_gold));
4586 }
4587
reportEndOfTurn()4588 void Player::reportEndOfTurn()
4589 {
4590 addHistory(new History_EndTurn);
4591 addAction(new Action_EndTurn);
4592 }
4593
getFirstCity() const4594 City *Player::getFirstCity() const
4595 {
4596 std::list<History*>::const_iterator it;
4597 for (it = d_history.begin(); it != d_history.end(); it++)
4598 {
4599 if ((*it)->getType() == History::CITY_WON)
4600 {
4601 History_CityWon *h = dynamic_cast<History_CityWon*>(*it);
4602 City *c = Citylist::getInstance()->getById(h->getCityId());
4603 if (c->isBurnt() == false && c->getOwner() == this)
4604 return c;
4605 }
4606 }
4607 return NULL;
4608 }
4609 // End of file
4610