1 //---------------------------------------------------------------------------
2 #include "stdafx.h"
3
4 #include <cassert>
5 #include <cstdlib>
6
7 #include <stdexcept> // needed for Android at least
8
9 #include <sstream>
10
11 #include "player.h"
12 #include "game.h"
13 #include "gamestate.h"
14 #include "utils.h"
15 #include "sector.h"
16 #include "tutorial.h"
17 //---------------------------------------------------------------------------
18
19 bool Player::alliances[n_players_c][n_players_c];
20 int Player::alliance_last_asked[n_players_c][n_players_c];
21
getName(PlayerTypeID id)22 const char *PlayerType::getName(PlayerTypeID id) {
23 if( id == PLAYER_RED )
24 return "RED TEAM";
25 else if( id == PLAYER_GREEN )
26 return "GREEN TEAM";
27 else if( id == PLAYER_YELLOW )
28 return "YELLOW TEAM";
29 else if( id == PLAYER_BLUE )
30 return "BLUE TEAM";
31 ASSERT(false);
32 return NULL;
33 }
34
getColour(int * r,int * g,int * b,PlayerTypeID id)35 void PlayerType::getColour(int *r,int *g,int *b,PlayerTypeID id) {
36 *r = *g = *b = 0;
37 if( id == PLAYER_RED ) {
38 *r = 145;
39 *g = 36;
40 *b = 34;
41 }
42 else if( id == PLAYER_GREEN ) {
43 *r = 67;
44 *g = 160;
45 *b = 71;
46 }
47 else if( id == PLAYER_YELLOW ) {
48 *r = 209;
49 *g = 184;
50 *b = 0;
51 }
52 else if( id == PLAYER_BLUE ) {
53 *r = 63;
54 *g = 81;
55 *b = 181;
56 }
57 else {
58 ASSERT(false);
59 }
60 }
61
62 //Player::Player(int index, char *name) {
63 //Player::Player(int index, int personality) {
Player(bool is_human,int index)64 Player::Player(bool is_human, int index) :
65 index(index), dead(false), n_births(0), n_deaths(0), n_men_for_this_island(0), n_suspended(0), is_human(is_human), alliance_last_asked_human(-1)
66 {
67 for(int i=0;i<n_players_c;i++) {
68 if( i != index && game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
69 setAlliance(index, i, false);
70 setAllianceLastAsked(index, i, -1);
71 }
72 }
73 }
74
~Player()75 Player::~Player() {
76 }
77
saveState(stringstream & stream) const78 void Player::saveState(stringstream &stream) const {
79 stream << "<player ";
80 stream << "player_id=\"" << index << "\" ";
81 stream << "dead=\"" << (dead?1:0) << "\" ";
82 stream << "n_births=\"" << n_births << "\" ";
83 stream << "n_deaths=\"" << n_deaths << "\" ";
84 stream << "n_men_for_this_island=\"" << n_men_for_this_island << "\" ";
85 stream << "n_suspended=\"" << n_suspended << "\" ";
86 stream << "alliance_last_asked_human=\"" << alliance_last_asked_human << "\" ";
87 stream << ">\n";
88 stream << "</player>\n";
89 }
90
loadStateParseXMLNode(const TiXmlNode * parent)91 void Player::loadStateParseXMLNode(const TiXmlNode *parent) {
92 if( parent == NULL ) {
93 return;
94 }
95 bool read_children = true;
96
97 switch( parent->Type() ) {
98 case TiXmlNode::TINYXML_DOCUMENT:
99 break;
100 case TiXmlNode::TINYXML_ELEMENT:
101 {
102 const char *element_name = parent->Value();
103 const TiXmlElement *element = parent->ToElement();
104 const TiXmlAttribute *attribute = element->FirstAttribute();
105 if( strcmp(element_name, "player") == 0 ) {
106 while( attribute != NULL ) {
107 const char *attribute_name = attribute->Name();
108 if( strcmp(attribute_name, "player_id") == 0 ) {
109 // handled by caller
110 }
111 else if( strcmp(attribute_name, "dead") == 0 ) {
112 dead = atoi(attribute->Value())==1;
113 }
114 else if( strcmp(attribute_name, "n_births") == 0 ) {
115 n_births = atoi(attribute->Value());
116 }
117 else if( strcmp(attribute_name, "n_deaths") == 0 ) {
118 n_deaths = atoi(attribute->Value());
119 }
120 else if( strcmp(attribute_name, "n_men_for_this_island") == 0 ) {
121 n_men_for_this_island = atoi(attribute->Value());
122 }
123 else if( strcmp(attribute_name, "n_suspended") == 0 ) {
124 n_suspended = atoi(attribute->Value());
125 }
126 else if( strcmp(attribute_name, "alliance_last_asked_human") == 0 ) {
127 alliance_last_asked_human = atoi(attribute->Value());
128 }
129 else {
130 // don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
131 LOG("unknown player/player attribute: %s\n", attribute_name);
132 ASSERT(false);
133 }
134 attribute = attribute->Next();
135 }
136 }
137 else {
138 // don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
139 LOG("unknown player tag: %s\n", element_name);
140 ASSERT(false);
141 }
142 }
143 break;
144 case TiXmlNode::TINYXML_COMMENT:
145 break;
146 case TiXmlNode::TINYXML_UNKNOWN:
147 break;
148 case TiXmlNode::TINYXML_TEXT:
149 {
150 }
151 break;
152 case TiXmlNode::TINYXML_DECLARATION:
153 break;
154 }
155
156 for(const TiXmlNode *child=parent->FirstChild();child!=NULL && read_children;child=child->NextSibling()) {
157 loadStateParseXMLNode(child);
158 }
159 }
160
saveStateAlliances(stringstream & stream)161 void Player::saveStateAlliances(stringstream &stream) {
162 stream << "<player_alliances>\n";
163 for(int i=0;i<n_players_c;i++) {
164 for(int j=i+1;j<n_players_c;j++) {
165 stream << "<player_alliance ";
166 stream << "player_id_i=\"" << i << "\" ";
167 stream << "player_id_j=\"" << j << "\" ";
168 stream << "alliances=\"" << (alliances[i][j] ? 1 : 0) << "\" ";
169 stream << "alliance_last_asked=\"" << alliance_last_asked[i][j] << "\" ";
170 stream << "/>\n";
171 }
172 }
173 stream << "</player_alliances>\n";
174 }
175
loadStateParseXMLNodeAlliances(const TiXmlNode * parent)176 void Player::loadStateParseXMLNodeAlliances(const TiXmlNode *parent) {
177 if( parent == NULL ) {
178 return;
179 }
180 bool read_children = true;
181
182 switch( parent->Type() ) {
183 case TiXmlNode::TINYXML_DOCUMENT:
184 break;
185 case TiXmlNode::TINYXML_ELEMENT:
186 {
187 const char *element_name = parent->Value();
188 const TiXmlElement *element = parent->ToElement();
189 const TiXmlAttribute *attribute = element->FirstAttribute();
190 if( strcmp(element_name, "player_alliances") == 0 ) {
191 // handled entirely by caller
192 }
193 else if( strcmp(element_name, "player_alliance") == 0 ) {
194 int player_id_i = -1;
195 int player_id_j = -1;
196 bool alliance = false;
197 int last_asked = -1;
198 while( attribute != NULL ) {
199 const char *attribute_name = attribute->Name();
200 if( strcmp(attribute_name, "player_id_i") == 0 ) {
201 player_id_i = atoi(attribute->Value());
202 }
203 else if( strcmp(attribute_name, "player_id_j") == 0 ) {
204 player_id_j = atoi(attribute->Value());
205 }
206 else if( strcmp(attribute_name, "alliances") == 0 ) {
207 alliance = atoi(attribute->Value())==1;
208 }
209 else if( strcmp(attribute_name, "alliance_last_asked") == 0 ) {
210 last_asked = atoi(attribute->Value());
211 }
212 else {
213 // don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
214 LOG("unknown player_alliances/player_alliance attribute: %s\n", attribute_name);
215 ASSERT(false);
216 }
217 attribute = attribute->Next();
218 }
219 if( player_id_i < 0 || player_id_i >= n_players_c ) {
220 throw std::runtime_error("player_alliance invalid player_id_i");
221 }
222 else if( player_id_j < 0 || player_id_j >= n_players_c ) {
223 throw std::runtime_error("player_alliance invalid player_id_j");
224 }
225 alliances[player_id_i][player_id_j] = alliance;
226 alliance_last_asked[player_id_i][player_id_j] = last_asked;
227 }
228 else {
229 // don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
230 LOG("unknown player_alliances tag: %s\n", element_name);
231 ASSERT(false);
232 }
233 }
234 break;
235 case TiXmlNode::TINYXML_COMMENT:
236 break;
237 case TiXmlNode::TINYXML_UNKNOWN:
238 break;
239 case TiXmlNode::TINYXML_TEXT:
240 {
241 }
242 break;
243 case TiXmlNode::TINYXML_DECLARATION:
244 break;
245 }
246
247 for(const TiXmlNode *child=parent->FirstChild();child!=NULL && read_children;child=child->NextSibling()) {
248 loadStateParseXMLNodeAlliances(child);
249 }
250 }
251
setAlliance(int a,int b,bool alliance)252 void Player::setAlliance(int a, int b, bool alliance) {
253 LOG("Alliance %s between players %d and %d\n", alliance?"MADE":"BROKEN", a, b);
254 ASSERT(a != b);
255 ASSERT_PLAYER(a);
256 ASSERT_PLAYER(b);
257 if( a > b ) {
258 int dummy = a;
259 a = b;
260 b = dummy;
261 }
262 alliances[a][b] = alliance;
263 }
264
isAlliance(int a,int b)265 bool Player::isAlliance(int a, int b) {
266 ASSERT(a != b);
267 ASSERT_PLAYER(a);
268 ASSERT_PLAYER(b);
269 if( a > b ) {
270 int dummy = a;
271 a = b;
272 b = dummy;
273 }
274 return alliances[a][b];
275 }
276
resetAllAlliances()277 void Player::resetAllAlliances() {
278 for(int i=0;i<n_players_c;i++) {
279 for(int j=i+1;j<n_players_c;j++) {
280 setAlliance(i, j, false);
281 setAllianceLastAsked(i, j, -1);
282 }
283 }
284 }
285
setAllianceLastAsked(int a,int b,int time)286 void Player::setAllianceLastAsked(int a, int b,int time) {
287 ASSERT(a != b);
288 ASSERT_PLAYER(a);
289 ASSERT_PLAYER(b);
290 if( a > b ) {
291 int dummy = a;
292 a = b;
293 b = dummy;
294 }
295 alliance_last_asked[a][b] = time;
296 }
297
allianceLastAsked(int a,int b)298 int Player::allianceLastAsked(int a, int b) {
299 ASSERT(a != b);
300 ASSERT_PLAYER(a);
301 ASSERT_PLAYER(b);
302 if( a > b ) {
303 int dummy = a;
304 a = b;
305 b = dummy;
306 }
307 return alliance_last_asked[a][b];
308 }
309
askHuman()310 bool Player::askHuman() {
311 const int wait_time_human_c = 5000;
312 //ASSERT( !isAlliance(index, human_player) );
313 //ASSERT( index != human_player );
314 ASSERT( !this->is_human );
315 // whether to _consider_ asking the human player - we still have to go through the requestAlliance test afterwards
316 if( game_g->getTutorial() != NULL && !game_g->getTutorial()->aiAllowAskAlliance() ) {
317 return false;
318 }
319 int time = game_g->getGameTime();
320 if( alliance_last_asked_human == -1 ) {
321 // note - don't ask if alliance_last_asked_human==-1, to avoid being asked straight away
322 alliance_last_asked_human = time;
323 }
324 else if( time >= alliance_last_asked_human + wait_time_human_c ) {
325 alliance_last_asked_human = time;
326 if( rand() % 2 == 0 )
327 {
328 return true;
329 }
330 }
331 return false;
332 }
333
requestAlliance(int player)334 bool Player::requestAlliance(int player) {
335 // 'player' requests alliance with 'this'
336 const int wait_time_c = 5000;
337 ASSERT( !isAlliance(index, player) );
338 //ASSERT( index != player );
339 //ASSERT(this->index != human_player);
340 ASSERT( !this->is_human );
341 int last_asked = Player::allianceLastAsked(index, player);
342 int time = game_g->getGameTime();
343 if( last_asked == -1 || time >= last_asked + wait_time_c ) {
344 Player::setAllianceLastAsked(index, player, time);
345 bool has_diplomatic_bonus = player == PlayerType::PLAYER_YELLOW;
346 if( has_diplomatic_bonus ? (rand() % 2 == 0) : (rand() % 3 == 0) )
347 {
348 return true;
349 }
350 //return true;
351 }
352 return false;
353 }
354
355 //int Player::getShieldIndex() {
getShieldIndex(bool allied[n_players_c])356 int Player::getShieldIndex(bool allied[n_players_c]) {
357 int rtn = 0;
358 /*if(personality == 0)
359 rtn = 2;
360 else if(personality == 1)
361 rtn = 1;
362 else if(personality == 2)
363 rtn = 4;
364 else if(personality == 3)
365 rtn = 3;*/
366 int index = 0;
367 for(int i=0,c=1;i<n_players_c;i++,c*=2) {
368 if( allied[i] ) {
369 index += c;
370 }
371 }
372 /*if(index == 0)
373 rtn = 2;
374 else if(index == 1)
375 rtn = 1;
376 else if(index == 2)
377 rtn = 4;
378 else if(index == 3)
379 rtn = 3;*/
380 if( index == 0 )
381 rtn = 0;
382 else if( index == 1 )
383 rtn = 2;
384 else if( index == 2 )
385 rtn = 1;
386 else if( index == 3 )
387 rtn = 8;
388 else if( index == 4 )
389 rtn = 4;
390 else if( index == 5 )
391 rtn = 7;
392 else if( index == 6 )
393 rtn = 9;
394 else if( index == 7 )
395 rtn = 11;
396 else if( index == 8 )
397 rtn = 3;
398 else if( index == 9 )
399 rtn = 5;
400 else if( index == 10 )
401 rtn = 6;
402 else if( index == 11 )
403 rtn = 13;
404 else if( index == 12 )
405 rtn = 10;
406 else if( index == 13 )
407 rtn = 12;
408 else if( index == 14 )
409 rtn = 14;
410 else {
411 ASSERT(false);
412 }
413 return rtn;
414 }
415
kill(PlayingGameState * gamestate)416 void Player::kill(PlayingGameState *gamestate) {
417 // break alliances
418 for(int i=0;i<n_players_c;i++) {
419 if( i != this->index )
420 Player::setAlliance(i, index, false);
421 }
422
423 /*if( ((PlayingGameState *)gamestate)->getPlayerAskingAlliance() == this->index ) {
424 ((PlayingGameState *)gamestate)->cancelPlayerAskingAlliance();
425 }*/
426 if( gamestate->getPlayerAskingAlliance() == this->index ) {
427 gamestate->cancelPlayerAskingAlliance();
428 }
429
430 this->dead = true;
431
432 // check for only being one side
433 bool one_side = true;
434 for(int i=0;i<n_players_c && one_side;i++) {
435 if( game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
436 for(int j=0;j<n_players_c && one_side;j++) {
437 if( game_g->players[j] != NULL && !game_g->players[j]->isDead() ) {
438 if( i != j && !Player::isAlliance(i,j) ) {
439 one_side = false;
440 }
441 }
442 }
443 }
444 }
445 if( one_side ) {
446 // break all alliances
447 for(int i=0;i<n_players_c;i++) {
448 if( game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
449 for(int j=0;j<n_players_c && one_side;j++) {
450 if( game_g->players[j] != NULL && !game_g->players[j]->isDead() ) {
451 if( i != j ) {
452 Player::setAlliance(i, j, false);
453 }
454 }
455 }
456 }
457 }
458 }
459
460 //gamestate->reset(); // needed to update player shield buttons
461 //((PlayingGameState *)gamestate)->resetShieldButtons(); // needed to update player shield buttons
462 gamestate->resetShieldButtons(); // needed to update player shield buttons
463 }
464
doSectorAI(int client_player,PlayingGameState * gamestate,Sector * sector)465 void Player::doSectorAI(int client_player, PlayingGameState *gamestate, Sector *sector) {
466 const int MIN_POP = 5;
467 const int EVACUATE_LEVEL = 3;
468
469 ASSERT( this->index == sector->getPlayer() );
470
471 // reset to zero
472 sector->setDesigners( 0 );
473 for(int i=0;i<N_ID;i++) {
474 if( game_g->elements[i]->getType() != Element::GATHERABLE )
475 sector->setMiners((Id)i, 0);
476 }
477 sector->setWorkers( 0 );
478 for(int i=0;i<N_BUILDINGS;i++) {
479 sector->setBuilders((Type)i, 0);
480 }
481
482 bool enemiesPresent = sector->enemiesPresent();
483 bool enemiesPresentWithBombardment = sector->enemiesPresentWithBombardment();
484
485 int attack_pref[n_players_c];
486 {
487 int attack_order[n_players_c-1];
488 int choose_from[n_players_c-1];
489 for(int i=0,indx=0;i<n_players_c;i++) {
490 if( i != index ) {
491 choose_from[indx++] = i;
492 }
493 }
494 for(int i=0;i<n_players_c-1;i++) {
495 int n_choose_from = n_players_c - 1 - i;
496 int c = rand() % n_choose_from;
497 attack_order[i] = choose_from[c];
498 choose_from[c] = choose_from[n_choose_from-1];
499 }
500 attack_pref[index] = 0;
501 for(int i=0;i<n_players_c-1;i++) {
502 attack_pref[ attack_order[i] ] = i+1;
503 }
504 }
505
506 if( enemiesPresentWithBombardment && sector->getBuilding(BUILDING_TOWER)->getHealth() <= EVACUATE_LEVEL ) {
507 // evacuate!
508 sector->evacuate();
509 /*for(int i=0;i<N_BUILDINGS;i++) {
510 Building *building = sector->getBuilding((Type)i);
511 if( building != NULL ) {
512 for(int j=0;j<building->getNTurrets();j++) {
513 if( building->getTurretMan(j) != -1 )
514 sector->returnDefender(building, j);
515 }
516 }
517 }
518 int men = sector->getAvailablePopulation();
519 if( men > 0 ) {
520 sector->getAssembledArmy()->add(n_epochs_c, men);
521 int n_pop = sector->getPopulation() - men;
522 sector->setPopulation(n_pop);
523 }
524 sector->getArmy(this->index)->add(sector->getAssembledArmy());*/
525 }
526
527 // recall army
528 if( !enemiesPresent && sector->getArmy(this->index)->getTotal() > 0 ) {
529 sector->returnArmy();
530 }
531
532 if( sector->getPopulation() < MIN_POP && !enemiesPresent )
533 return; // reproduce
534
535 // defenders
536 for(int i=n_epochs_c-1;i>=0 /*&& enemiesPresent*/;i--) {
537 /*if( i == nuclear_epoch_c )
538 continue;*/
539 if( !enemiesPresentWithBombardment && i != nuclear_epoch_c && i != laser_epoch_c )
540 continue; // don't put out defenders if no enemies present, except for nuclear defence or laser
541 if( enemiesPresent && i == nuclear_epoch_c )
542 continue; // don't put out new nuclear defences if under attack
543 /*if( i == laser_epoch_c ) // test - disable lasers to test nuke defence
544 continue;*/
545 for(;;) {
546 if( i == nuclear_epoch_c ) {
547 int n_lasers = sector->getNDefenders(laser_epoch_c);
548 int n_nuke_defs = sector->getNDefenders(nuclear_epoch_c);
549 ASSERT(n_nuke_defs <= 1);
550 if( n_lasers > 0 || n_nuke_defs > 0 )
551 break; // don't need a nuclear defence
552 }
553 Design *design = NULL;
554 if( sector->getStoredDefenders(i) == 0 ) {
555 design = sector->canBuildDesign(Invention::DEFENCE, i);
556 if( design == NULL )
557 break;
558 }
559 // we can make this defence
560 bool placed = false;
561 for(int j=0;j<N_BUILDINGS && !placed && sector->getAvailablePopulation() > MIN_POP;j++) {
562 Building *building = sector->getBuilding((Type)j);
563 if( building != NULL ) {
564 for(int k=0;k<building->getNTurrets() && !placed;k++) {
565 if( building->getTurretMan(k) == -1 ) {
566 // new defender
567 placed = sector->deployDefender(building, k, i);
568 }
569 }
570 }
571 }
572 // try again, replacing poorer defences this time
573 for(int j=0;j<N_BUILDINGS && !placed;j++) {
574 Building *building = sector->getBuilding((Type)j);
575 if( building != NULL ) {
576 for(int k=0;k<building->getNTurrets() && !placed;k++) {
577 if( building->getTurretMan(k) != -1 && building->getTurretMan(k) < i ) {
578 // replace defender
579 placed = sector->deployDefender(building, k, i);
580 }
581 }
582 }
583 }
584 if( !placed ) {
585 // couldn't place it
586 if( i >= factory_epoch_c && sector->getStoredDefenders(i) == 0 &&
587 sector->getCurrentManufacture() == NULL ) {
588 // manufacture one
589 sector->setCurrentManufacture(design);
590 sector->setFAmount(1);
591
592 }
593 break;
594 }
595 }
596 }
597
598 if( !enemiesPresentWithBombardment ) {
599 // return defenders (except nuclear defence and lasers)
600 for(int j=0;j<N_BUILDINGS;j++) {
601 Building *building = sector->getBuilding((Type)j);
602 if( building != NULL ) {
603 //for(int k=0;k<max_building_turrets_c;k++) {
604 for(int k=0;k<building->getNTurrets();k++) {
605 if( building->getTurretMan(k) != -1 && building->getTurretMan(k) != nuclear_epoch_c && building->getTurretMan(k) != laser_epoch_c ) {
606 /*sector->stored_defenders[ building->turret_man[k] ]++;
607 building->turret_man[k] = -1;
608 int n_pop = sector->getPopulation() + 1;
609 sector->setPopulation(n_pop);*/
610 sector->returnDefender(building, k);
611 }
612 }
613 }
614 }
615 }
616
617 if( sector->getCurrentManufacture() == NULL ) {
618 // defences handled already, above
619 for(int i=game_g->getNSubEpochs()-1;i>=0;i--) {
620 if( game_g->getStartEpoch() + i == nuclear_epoch_c )
621 continue; // nuclear weapons handled later
622 if( game_g->getStartEpoch() + i >= factory_epoch_c ) {
623 Design *design = sector->canBuildDesign(Invention::WEAPON, game_g->getStartEpoch() + i);
624 if( design != NULL ) {
625 sector->setCurrentManufacture(design);
626 sector->setFAmount(1);
627 break;
628 }
629 }
630 }
631 }
632
633 // use shields?
634 for(int i=0;i<N_BUILDINGS;i++) {
635 Building *building = sector->getBuilding((Type)i);
636 if( building == NULL )
637 continue;
638 if( building->getHealth() < 30 ) {
639 bool healed = false;
640 for(int j=3;j>=0 && !healed;j--) {
641 healed = sector->useShield(building, j);
642 }
643 if( !healed && sector->getCurrentManufacture() != NULL ) {
644 // manufacture a shield
645 for(int j=game_g->getNSubEpochs()-1;j>=0;j--) {
646 Design *design = sector->canBuildDesign(Invention::SHIELD, game_g->getStartEpoch() + j);
647 if( design != NULL ) {
648 sector->setCurrentManufacture(design);
649 sector->setFAmount(1);
650 break;
651 }
652 }
653 }
654 }
655 }
656
657 // nuke a sector?
658 while( sector->getStoredArmy()->getSoldiers(nuclear_epoch_c) > 0 || sector->getCurrentManufacture() == NULL ) {
659 // look for tower to nuke
660 Sector *nuke_sector = NULL;
661 bool found_tower = false;
662 for(int x=0;x<map_width_c;x++) {
663 for(int y=0;y<map_height_c;y++) {
664 if( game_g->getMap()->isSectorAt(x, y) ) {
665 Sector *c_sector = game_g->getMap()->getSector(x, y);
666 int this_strength = c_sector->getArmy(sector->getPlayer())->getStrength();
667 if( this_strength > 0 && ( !enemiesPresentWithBombardment || sector->getBuilding(BUILDING_TOWER)->getHealth() > EVACUATE_LEVEL ) ) {
668 // only nuke our own men if this tower is under attack and nearly destroyed
669 continue;
670 }
671 // prefer nuking towers to men
672 if( c_sector->getActivePlayer() != -1 && c_sector->getPlayer() != sector->getPlayer() && !Player::isAlliance(c_sector->getPlayer(), sector->getPlayer()) ) {
673 if( nuke_sector == NULL || !found_tower || attack_pref[c_sector->getPlayer()] > attack_pref[nuke_sector->getPlayer()] ) {
674 nuke_sector = c_sector;
675 found_tower = true;
676 }
677 }
678 else if( !found_tower && c_sector->getActivePlayer() == -1 && c_sector->enemiesPresent(sector->getPlayer()) && !c_sector->getArmy(sector->getPlayer())->any(true) ) {
679 if( nuke_sector == NULL || attack_pref[c_sector->getPlayer()] > attack_pref[nuke_sector->getPlayer()] ) {
680 nuke_sector = c_sector;
681 }
682 }
683 }
684 }
685 }
686 if( nuke_sector == NULL ) {
687 break;
688 }
689 if( sector->getStoredArmy()->getSoldiers(nuclear_epoch_c) > 0 && !sector->isBeingNuked() ) {
690 // nuke
691 nuke_sector->nukeSector(sector);
692 sector->getStoredArmy()->remove(nuclear_epoch_c, 1);
693 }
694 else {
695 // start making a nuke, only if not already making something
696 Design *design = sector->canBuildDesign(Invention::WEAPON, nuclear_epoch_c);
697 if( design != NULL ) {
698 sector->setCurrentManufacture(design);
699 sector->setFAmount(1);
700 }
701 break;
702 }
703 }
704
705 // trash designs?
706 sector->autoTrashDesigns();
707
708 if( game_g->getTutorial() != NULL && !game_g->getTutorial()->aiAllowDesign() ) {
709 // don't allow designs
710 }
711 else if( sector->getCurrentDesign() == NULL ) {
712 // set new invention?
713 int best_weapon = -1;
714 int best_defence = -1;
715 int best_shield = -1;
716 for(int i=game_g->getNSubEpochs()-1;i>=0;i--) {
717 if( best_weapon == -1 && sector->inventionKnown(Invention::WEAPON, game_g->getStartEpoch() + i) )
718 best_weapon = game_g->getStartEpoch() + i;
719 if( best_defence == -1 && sector->inventionKnown(Invention::DEFENCE, game_g->getStartEpoch() + i) )
720 best_defence = game_g->getStartEpoch() + i;
721 if( best_shield == -1 && sector->inventionKnown(Invention::SHIELD, game_g->getStartEpoch() + i) )
722 best_shield = game_g->getStartEpoch() + i;
723 }
724 Design *design = NULL;
725 Design *reserve_design = NULL;
726 // prefer nuke!
727 design = sector->canResearch(Invention::WEAPON, nuclear_epoch_c);
728
729 bool try_mining_more = sector->tryMiningMore();
730 for(int i=0;i<game_g->getNSubEpochs() && design == NULL;i++) {
731 int eph = game_g->getStartEpoch() + i;
732 Design *this_design = NULL;
733
734 this_design = sector->canResearch(Invention::WEAPON, eph);
735 if( eph > best_weapon )
736 design = this_design;
737 else if( reserve_design == NULL )
738 reserve_design = this_design;
739
740 if( design == NULL ) {
741 this_design = sector->canResearch(Invention::DEFENCE, eph);
742 if( eph > best_defence )
743 design = this_design;
744 else if( reserve_design == NULL )
745 reserve_design = this_design;
746 }
747 if( design == NULL && ( best_weapon != -1 || best_defence != -1 || !try_mining_more ) ) {
748 // (only design shield if we've already designed either a weapon or a defence, or there's no point waiting)
749 this_design = sector->canResearch(Invention::SHIELD, eph);
750 if( eph > best_shield )
751 design = this_design;
752 else if( reserve_design == NULL )
753 reserve_design = this_design;
754 }
755 }
756
757 if( design == NULL && sector->getEpoch() < game_g->getStartEpoch() + 3 )
758 design = reserve_design;
759
760 if( design != NULL ) {
761 sector->setCurrentDesign(design);
762 }
763 }
764
765 bool used_up = game_g->getStartEpoch() != end_epoch_c && sector->usedUp();
766 bool can_design = sector->getCurrentDesign() != NULL;
767 bool can_mine = false;
768 if( !used_up ) {
769 // even if there are elements remaining to mine, we might still consider a sector "used up" if we've already mined at least 6 of that element, and we still can't design anything
770 //
771 for(int i=0;i<N_ID && !can_mine;i++) {
772 if( sector->canMine((Id)i) && game_g->elements[i]->getType() != Element::GATHERABLE )
773 can_mine = true;
774 }
775 }
776 bool build_mine = sector->canBuild(BUILDING_MINE);
777 bool build_factory = sector->canBuild(BUILDING_FACTORY);
778 bool build_lab = sector->canBuild(BUILDING_LAB);
779 bool need_workers = sector->getCurrentManufacture() != NULL;
780
781 if( enemiesPresentWithBombardment && sector->getBuilding(BUILDING_TOWER)->getHealth() <= EVACUATE_LEVEL+1 )
782 can_design = false;
783 if( enemiesPresentWithBombardment && sector->getBuilding(BUILDING_TOWER)->getHealth() <= EVACUATE_LEVEL+1 )
784 can_mine = false;
785 if( enemiesPresentWithBombardment && sector->getBuilding(BUILDING_TOWER)->getHealth() <= EVACUATE_LEVEL+1 )
786 need_workers = false;
787
788 if( enemiesPresentWithBombardment && sector->getBuilding(BUILDING_TOWER)->getHealth() <= EVACUATE_LEVEL+1 ) {
789 build_mine = false;
790 build_factory = false;
791 build_lab = false;
792 }
793
794 int split = 1;
795 int design_weight = 0;
796 int work_weight = 0;
797 if( can_design ) {
798 design_weight = 1;
799 if( sector->getCurrentDesign()->getInvention()->getEpoch() == nuclear_epoch_c )
800 design_weight = 4; // rush!
801 split += design_weight;
802 }
803 if( can_mine )
804 split++;
805 if( build_mine )
806 split++;
807 if( build_factory )
808 split++;
809 if( build_lab )
810 split++;
811 if( need_workers ) {
812 work_weight = 1;
813 if( sector->getCurrentManufacture()->getInvention()->getEpoch() == nuclear_epoch_c )
814 work_weight = 4; // rush!
815 split += work_weight;
816 }
817
818 int pop = sector->getAvailablePopulation();
819
820 if( can_design ) {
821 sector->setDesigners((design_weight * pop) / split);
822 }
823 if( can_mine ) {
824 int n_miners = 0;
825 while( n_miners < pop/split ) {
826 for(int i=0;i<N_ID && n_miners < pop/split;i++) {
827 if( sector->canMine((Id)i) && game_g->elements[i]->getType() != Element::GATHERABLE ) {
828 int n = sector->getMiners((Id)i) + 1;
829 sector->setMiners((Id)i, n);
830 n_miners++;
831 }
832 }
833 }
834 }
835 if( build_mine ) {
836 sector->setBuilders(BUILDING_MINE, pop / split);
837 }
838 if( build_factory ) {
839 sector->setBuilders(BUILDING_FACTORY, pop / split);
840 }
841 if( build_lab ) {
842 sector->setBuilders(BUILDING_LAB, pop / split);
843 }
844 if( need_workers ) {
845 sector->setWorkers((work_weight * pop) / split);
846 }
847
848
849 if( game_g->getTutorial() != NULL && !game_g->getTutorial()->aiAllowDeploy() ) {
850 // don't allow deployment
851 }
852 else if( sector->getCurrentDesign() == NULL || enemiesPresentWithBombardment ) {
853 //if( used_up || enemiesPresentWithBombardment ) {
854 // think about attacking?
855 Sector *target_sector = NULL;
856 bool by_land = false;
857 bool new_sector = false;
858 int strength = 0;
859 bool temp[map_width_c][map_height_c];
860 game_g->getMap()->canMoveTo(temp, sector->getXPos(),sector->getYPos(),sector->getPlayer());
861
862 // if used up, look for a new sector
863 bool look_for_new_sector = used_up || ( rand() % 3 == 0 );
864 if( look_for_new_sector ) {
865 vector<Sector *> candidate_sectors;
866 int max_n_men = 0;
867 for(int x=0;x<map_width_c;x++) {
868 for(int y=0;y<map_height_c;y++) {
869 Sector *c_sector = game_g->getMap()->getSector(x, y);
870 if( c_sector == NULL )
871 continue;
872 // Only worth moving to a sector that has no other players
873 // If we were to move to a sector with an ally army, the army would then be immediately moved back to the tower by code in Player::doSectorAI() (this bug was fixed in 0.28)
874 // No need to move to a sector with enemies - the decision to attack is done below
875 if( c_sector->getActivePlayer() == -1 ) {
876 if( temp[x][y] ) {
877 bool has_others = false;
878 for(int i=0;i<n_players_c && !has_others;i++) {
879 if( i != index && c_sector->getArmy(i)->any(true) ) {
880 has_others = true;
881 }
882 }
883 if( !has_others ) {
884 int n_men = c_sector->getArmy(index)->getTotal();
885 // prefer sectors that already have our men - and pick the largest number
886 if( n_men >= max_n_men ) {
887 if( n_men > max_n_men ) {
888 candidate_sectors.clear();
889 max_n_men = n_men;
890 }
891 candidate_sectors.push_back(c_sector);
892 }
893 }
894 }
895 }
896 }
897 }
898 if( candidate_sectors.size() > 0 ) {
899 // randomly pick out of the candidate sectors
900 int r = rand() % candidate_sectors.size();
901 target_sector = candidate_sectors.at(r);
902 by_land = true;
903 new_sector = true;
904 }
905 }
906
907 // look for tower to attack
908 for(int x=0;x<map_width_c;x++) {
909 for(int y=0;y<map_height_c;y++) {
910 Sector *c_sector = game_g->getMap()->getSector(x, y);
911 if( c_sector == NULL )
912 continue;
913 if( c_sector->getActivePlayer() != -1 && c_sector->getPlayer() != sector->getPlayer()
914 && !Player::isAlliance(c_sector->getPlayer(), sector->getPlayer())
915 && !new_sector // only consider attacking if aren't moving to a new sector
916 ) {
917 //int this_strength = c_sector->getArmy(sector->getPlayer())->getTotal();
918 int this_strength = c_sector->getArmy(sector->getPlayer())->getStrength();
919 if( target_sector == NULL // we haven't chosen anywhere yet
920 || ( temp[x][y] && !by_land ) // prefer by land over by air
921 || ( temp[x][y] == by_land && this_strength > strength ) // prefer where we're already attacking
922 || ( temp[x][y] == by_land && this_strength == strength && attack_pref[c_sector->getPlayer()] > attack_pref[target_sector->getPlayer()] ) // prefer a particular player
923 ) {
924 target_sector = c_sector;
925 strength = this_strength;
926 by_land = temp[x][y];
927 }
928 }
929 }
930 }
931 if( target_sector == NULL ) {
932 // look for men to attack
933 for(int x=0;x<map_width_c;x++) {
934 for(int y=0;y<map_height_c;y++) {
935 Sector *c_sector = game_g->getMap()->getSector(x, y);
936 if( c_sector == NULL )
937 continue;
938 bool enemy = false;
939 for(int i=0;i<n_players_c && !enemy;i++) {
940 if( i != sector->getPlayer() && c_sector->getArmy(i)->getTotal() > 0 &&
941 !Player::isAlliance(i, sector->getPlayer()) )
942 enemy = true;
943 }
944 if( enemy ) {
945 //int this_strength = c_sector->getArmy(sector->getPlayer())->getTotal();
946 int this_strength = c_sector->getArmy(sector->getPlayer())->getStrength();
947 if( target_sector == NULL ||
948 ( temp[x][y] && !by_land ) ||
949 ( temp[x][y] == by_land && this_strength > strength ) ) {
950 target_sector = c_sector;
951 by_land = temp[x][y];
952 strength = this_strength;
953 }
954 }
955 }
956 }
957 }
958 if( enemiesPresentWithBombardment && !used_up ) {
959 target_sector = sector;
960 by_land = true;
961 new_sector = false;
962 }
963
964 if( target_sector != NULL ) {
965 int min_pop = MIN_POP;
966 //if( enemiesPresent && sector->getBuilding(BUILDING_TOWER)->health <= EVACUATE_LEVEL+1 )
967 //if( enemiesPresent || new_sector )
968 if( enemiesPresent || used_up )
969 min_pop = 0;
970 for(int i=n_epochs_c-1;i>=game_g->getStartEpoch();i--) {
971 if( i == nuclear_epoch_c )
972 continue;
973 if( !by_land && !isAirUnit(i) )
974 continue;
975 while(sector->getAvailablePopulation() > min_pop) {
976 if( !sector->assembleArmy(i, 1) )
977 break;
978 }
979 }
980 /*if( new_sector ) {
981 // add unarmed men
982 while(sector->getAvailablePopulation() > min_pop) {
983 if( !sector->assembleArmy(n_epochs_c, 1) )
984 break;
985 }
986 }*/
987
988 //int assembled_strength = sector->getAssembledArmy()->getTotal();
989 int assembled_strength = sector->getAssembledArmy()->getStrength();
990 //int min_req = 8;
991 //int min_req = 4 * (game_g->getStartEpoch()+1);
992 int min_req = 8 * (game_g->getStartEpoch()+1);
993 min_req = std::min(min_req, 50);
994 for(int i=0;i<=game_g->getStartEpoch();i++)
995 min_req *= 2;
996 if( used_up ) {
997 // no point waiting
998 min_req = 0;
999 }
1000
1001 /*if( by_land && sector->getCurrentDesign() == NULL && sector->getCurrentManufacture() == NULL &&
1002 ( enemiesPresent || assembled_strength > min_req || game_g->getStartEpoch() == end_epoch_c ) ) {
1003 // only use unarmed men if we aren't designing or manufacturing anything
1004 // and either we are under attack, or we are able to destroy enemy buildings, or moving to a new sector
1005 // assemble unarmed men*/
1006 if( by_land && sector->getCurrentDesign() == NULL && sector->getCurrentManufacture() == NULL &&
1007 ( enemiesPresentWithBombardment || game_g->getStartEpoch() == end_epoch_c || new_sector ) ) {
1008 // only use unarmed men if we aren't designing or manufacturing anything
1009 // and either we are under attack, or we are able to destroy enemy buildings, or we are moving to a new sector
1010 // assemble unarmed men
1011 int n_unarmed = sector->getAvailablePopulation() - min_pop;
1012 if( n_unarmed > 0 ) {
1013 int n_population = sector->getPopulation();
1014 sector->getAssembledArmy()->add(n_epochs_c, n_unarmed);
1015 sector->setPopulation( n_population - n_unarmed );
1016 }
1017 }
1018
1019 if( sector->getAssembledArmy()->any(true) ) {
1020 assembled_strength = sector->getAssembledArmy()->getStrength();
1021
1022 if( new_sector && used_up && sector->getStoredArmy()->any(false) && (sector->getSparePopulation() + sector->getAssembledArmy()->getTotalMen()) < 0.75f*max_grow_population_c ) {
1023 // If moving to a new sector because the sector is used up, we don't want to leave weapons behind - if we didn't have enough men to use them, better to wait until the population grows.
1024 // However we need to have the population not too close to the max_grow_population_c (otherwise we'll no longer be growing very much)
1025 // Arguably this logic should apply even if sending an army to attack (when not used up), but have to be careful - we don't want to make the AI take ages to decide to attack even though it has a reasonable strength.
1026 sector->returnAssembledArmy();
1027 }
1028 else if( strength + assembled_strength >= min_req || enemiesPresentWithBombardment ) {
1029 ASSERT( !target_sector->isNuked() );
1030 if( target_sector->getPlayer() == client_player && !target_sector->getArmy(this->index)->any(true) ) {
1031 game_g->setTimeRate(1); // auto-slow if attacking a player sector (but not if already being attacked by this player)
1032 gamestate->refreshTimeRate();
1033 }
1034 bool moved_all = target_sector->moveArmy(sector->getAssembledArmy());
1035 ASSERT(moved_all);
1036 }
1037 else {
1038 sector->returnAssembledArmy();
1039 }
1040 }
1041 }
1042 }
1043 }
1044
1045
doAIUpdate(int client_player,PlayingGameState * gamestate)1046 void Player::doAIUpdate(int client_player, PlayingGameState *gamestate) {
1047 if( game_g->players[index]->isDead() ) {
1048 return;
1049 }
1050 //LOG("Player::doAIUpdate()\n");
1051
1052 int loop_time = game_g->getLoopTime();
1053
1054 // TODO: currently breaking/making alliances is entirely random, should improve this...
1055
1056 // break alliances
1057 int p_break_alliance = poisson(20000, loop_time);
1058 bool break_alliance = false;
1059 if( (rand() % RAND_MAX) <= p_break_alliance ) {
1060 for(int i=0;i<n_players_c;i++) {
1061 if( i != index && Player::isAlliance(i, index) ) {
1062 Player::setAlliance(i, index, false);
1063 break_alliance = true;
1064 }
1065 }
1066 }
1067 if( break_alliance ) {
1068 //gamestate->reset(); // reset shield buttons
1069 //((PlayingGameState *)gamestate)->resetShieldButtons(); // needed to update player shield buttons
1070 gamestate->resetShieldButtons(); // needed to update player shield buttons
1071 }
1072
1073 // make alliances
1074 for(int i=0;i<n_players_c;i++) {
1075 if( i != this->index && game_g->players[i] != NULL && !game_g->players[i]->isDead() /*&& i != human_player*/ ) {
1076 //if( this->index == ((PlayingGameState *)gamestate)->getPlayerAskingAlliance() || i == ((PlayingGameState *)gamestate)->getPlayerAskingAlliance() ) {
1077 if( this->index == gamestate->getPlayerAskingAlliance() || i == gamestate->getPlayerAskingAlliance() ) {
1078 // one of these AIs is asking the player, so don't request
1079 continue;
1080 }
1081 // request alliance
1082 /*if( ((PlayingGameState *)gamestate)->canRequestAlliance(index, i) ) {
1083 ((PlayingGameState *)gamestate)->requestAlliance(index, i, false);
1084 }*/
1085 if( gamestate->canRequestAlliance(index, i) ) {
1086 gamestate->requestAlliance(index, i, false);
1087 }
1088 }
1089 }
1090
1091 // update sectors
1092 for(int x=0;x<map_width_c;x++) {
1093 for(int y=0;y<map_height_c;y++) {
1094 Sector *sector = game_g->getMap()->getSector(x, y);
1095 if( sector == NULL )
1096 continue;
1097 if( sector->getActivePlayer() == this->index ) {
1098 //game_g->getMap()->sectors[x][y]->doAIUpdate();
1099 doSectorAI(client_player, gamestate, sector);
1100 }
1101 else {
1102 Army *army = sector->getArmy(index);
1103 if( !army->any(true) ) {
1104 // no army to move
1105 }
1106 else if( !army->canLeaveSafely() ) {
1107 // can't retreat safely
1108 }
1109 else {
1110 // at this point, we have an army, with no enemies present, so check if we can build here
1111 bool move = false;
1112 if( sector->isShutdown() )
1113 move = true;
1114 else if( sector->getPlayer() != -1 ) {
1115 ASSERT( Player::isAlliance(sector->getPlayer(), index) ); // must be true, otherwise we should not be able to retreat safely
1116 move = true;
1117 }
1118 for(int i=0;i<n_players_c && !move;i++) {
1119 if( i != index && sector->getArmy(i)->any(true) ) {
1120 ASSERT( Player::isAlliance(i, index) ); // must be true, otherwise we should not be able to retreat safely
1121 move = true;
1122 }
1123 }
1124 if( move ) {
1125 // find somewhere to move
1126 // TODO: move to attack players, if can't return to a tower
1127 bool done = false;
1128 for(int cx=0;cx<map_width_c && !done;cx++) {
1129 for(int cy=0;cy<map_height_c && !done;cy++) {
1130 Sector *c_sector = game_g->getMap()->getSector(cx, cy);
1131 if( c_sector != NULL && c_sector->getActivePlayer() == this->index ) {
1132 ASSERT( c_sector != sector );
1133 done = c_sector->moveArmy(army);
1134 }
1135 }
1136 }
1137 }
1138 }
1139 }
1140 }
1141 }
1142 //LOG("EXIT Player::doAIUpdate()\n");
1143 }
1144
getFinalMen() const1145 int Player::getFinalMen() const {
1146 int final_men = n_men_for_this_island + n_births - n_deaths;
1147 ASSERT(final_men >= 0);
1148 return final_men;
1149 }
1150