2
* Copyright (C) 2004 by The Widelands Development Team
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
#include "transport.h"
25
#include "constructionsite.h"
26
#include "computer_player.h"
28
class CheckStepRoadAI : public CheckStep {
30
CheckStepRoadAI(Player* player, uchar movecaps)
31
: m_player(player), m_movecaps(movecaps) { }
33
virtual bool allowed(Map* map, FCoords start, FCoords end, int dir, StepId id) const;
34
virtual bool reachabledest(Map* map, FCoords dest) const;
41
Computer_Player::Computer_Player (Game *g, uchar pid)
44
map = game->get_map();
47
player = g->get_player(player_number);
48
tribe = player->get_tribe();
50
log ("new Comp_Player for player %d\n", pid);
52
// collect information about which buildings our tribe can construct
53
for (int i=0; i<tribe->get_nrbuildings();i++) {
54
const char* name=tribe->get_building_descr(i)->get_name();
55
log ("\tcan build '%s', id is %d\n",name,i);
57
BuildingObserver& bo=buildings[name];
59
bo.is_constructionsite=false;
61
bo.cnt_under_construction=0;
64
buildings["constructionsite"].is_constructionsite=true;
66
total_constructionsites=0;
67
delay_frontierhouse=0;
70
Computer_Player::~Computer_Player ()
74
void Computer_Player::think ()
76
/* // update our fields
77
for (std::list<BuildableField>::iterator i=buildable_fields.begin(); i!=buildable_fields.end();) {
78
// check whether we lost ownership of the field
79
if (i->field->get_owned_by()!=player_number) {
80
log ("AI player %d lost field (%d,%d)\n", player_number, i->x, i->y);
81
i=buildable_fields.erase(i);
85
// check whether we can still build on the field
86
if ((player->get_buildcaps(*i) & BUILDCAPS_SIZEMASK)==0) {
87
log ("Field (%d,%d) can no longer be built upon\n", i->x, i->y);
88
unusable_fields.push_back (*i);
89
i=buildable_fields.erase(i);
96
// update statistics about only one field at a time
97
if (!buildable_fields.empty()) {
98
update_buildable_field (buildable_fields.front());
100
buildable_fields.push_back (buildable_fields.front());
101
buildable_fields.pop_front ();
104
for (std::list<FCoords>::iterator i=unusable_fields.begin(); i!=unusable_fields.end();) {
105
// check whether we lost ownership of the field
106
if (i->field->get_owned_by()!=player_number) {
107
log ("AI player %d lost field (%d,%d)\n", player_number, i->x, i->y);
108
i=unusable_fields.erase(i);
112
// check whether building capabilities have improved
113
if ((player->get_buildcaps(*i) & BUILDCAPS_SIZEMASK) != 0) {
114
log ("Field (%d,%d) can now be built upon\n", i->x, i->y);
115
buildable_fields.push_back (*i);
116
i=unusable_fields.erase(i);
118
update_buildable_field (buildable_fields.back());
125
// now build something if possible
126
int proposed_building=-1;
127
int proposed_priority=0;
128
Coords proposed_coords;
130
for (std::list<BuildableField>::iterator i=buildable_fields.begin(); i!=buildable_fields.end(); i++) {
134
int maxsize=i->field->get_caps() & BUILDCAPS_SIZEMASK;
138
if (delay_frontierhouse<=game->get_gametime()) {
139
prio=i->unowned_land;
140
prio-=i->frontierhouses*64;
142
if (prio>proposed_priority) {
143
proposed_building=buildings["frontierhouse"].id;
144
proposed_priority=prio;
151
prio-=i->lumberjacks*8;
152
prio+=i->foresters*4;
153
prio-=buildings["lumberjack"].cnt_built*4;
154
prio-=buildings["lumberjack"].cnt_under_construction*16;
156
if (maxsize>BUILDCAPS_SMALL)
159
if (prio>proposed_priority) {
160
proposed_building=buildings["lumberjack"].id;
161
proposed_priority=prio;
167
prio+=i->lumberjacks*4;
168
prio-=i->foresters*12;
169
prio-=buildings["forrester"].cnt_built*4;
170
prio-=buildings["forrester"].cnt_under_construction*16;
172
if (prio>proposed_priority) {
173
proposed_building=buildings["forrester"].id;
174
proposed_priority=prio;
181
prio-=buildings["quarry"].cnt_built*4;
182
prio-=buildings["quarry"].cnt_under_construction*16;
184
if (maxsize>BUILDCAPS_SMALL)
187
if (prio>proposed_priority) {
188
proposed_building=buildings["quarry"].id;
189
proposed_priority=prio;
194
if (maxsize>=BUILDCAPS_MEDIUM) {
196
prio-=buildings["sawmill"].get_total_count() * 8;
198
if (prio>proposed_priority) {
199
proposed_building=buildings["sawmill"].id;
200
proposed_priority=prio;
206
if (maxsize==BUILDCAPS_BIG) {
208
prio-=buildings["farm"].get_total_count() * 2;
211
prio-=i->foresters*8;
212
if (total_constructionsites>4)
215
if (prio>proposed_priority) {
216
proposed_building=buildings["farm"].id;
217
proposed_priority=prio;
223
if (maxsize>=BUILDCAPS_MEDIUM) {
224
prio=buildings["farm"].get_total_count() * 8;
225
prio-=buildings["mill"].get_total_count() * 8;
226
if (total_constructionsites>4)
229
if (prio>proposed_priority) {
230
proposed_building=buildings["mill"].id;
231
proposed_priority=prio;
237
if (maxsize>=BUILDCAPS_MEDIUM) {
238
prio=buildings["mill"].get_total_count() * 8;
239
prio-=buildings["bakery"].get_total_count() * 8;
240
if (total_constructionsites>4)
243
if (prio>proposed_priority) {
244
proposed_building=buildings["bakery"].id;
245
proposed_priority=prio;
251
// if we want to construct a new building, send the command now
252
if (proposed_building>=0) {
253
game->send_player_build (player_number, proposed_coords, proposed_building);
255
if (buildings["frontierhouse"].id==proposed_building)
256
delay_frontierhouse=game->get_gametime() + 10000;
261
// if nothing else is to do, update flags and economies
262
while (!new_flags.empty()) {
263
Flag* flag=new_flags.front();
264
new_flags.pop_front();
266
get_economy_observer(flag->get_economy()).flags.push_back (flag);
269
for (std::list<EconomyObserver>::iterator i=economies.begin(); i!=economies.end();) {
270
// check if any flag has changed its economy
271
for (std::list<Flag*>::iterator j=i->flags.begin(); j!=i->flags.end();) {
272
if (i->economy!=(*j)->get_economy()) {
273
log ("Flag at (%d,%d) changed economy\n", (*j)->get_position().x, (*j)->get_position().y);
275
get_economy_observer((*j)->get_economy()).flags.push_back (*j);
283
// if there are no more flags in this economy, we no longer need its observer
284
if (i->flags.empty()) {
285
i=economies.erase(i);
289
// try to connect to another economy
290
if (economies.size()>1) {
291
connect_flag_to_another_economy (i->flags.front());
293
// cycle through flags one at a time
294
i->flags.push_back (i->flags.front());
295
i->flags.pop_front ();
301
// force a split on roads that are extremely long
302
// note that having too many flags causes a loss of building capabilities
303
if (!roads.empty()) {
304
const Path& path=roads.front()->get_path();
306
if (path.get_nsteps()>6) {
310
// try to split near the middle
311
for (i=0;i<cp.get_nsteps()/2-2;i++) {
314
f=map->get_field(cp.get_coords()[cp.get_nsteps()/2-i]);
315
if ((f->get_caps()&BUILDCAPS_FLAG)!=0) {
316
game->send_player_build_flag (player_number, cp.get_coords()[cp.get_nsteps()/2-i]);
320
f=map->get_field(cp.get_coords()[cp.get_nsteps()/2+i+1]);
321
if ((f->get_caps()&BUILDCAPS_FLAG)!=0) {
322
game->send_player_build_flag (player_number, cp.get_coords()[cp.get_nsteps()/2+i+1]);
328
roads.push_back (roads.front());
334
struct FindFieldUnowned:FindField {
335
virtual bool accept (const FCoords) const;
338
bool FindFieldUnowned::accept (const FCoords fc) const
340
return fc.field->get_owned_by()==0;
343
void Computer_Player::update_buildable_field (BuildableField& field)
345
// look if there is any unowned land nearby
346
FindFieldUnowned find_unowned;
348
field.unowned_land=map->find_fields(field, 8, 0, find_unowned);
350
// collect information about resources in the area
351
std::vector<ImmovableFound> immovables;
353
const int tree_attr=Map_Object_Descr::get_attribute_id("tree");
354
const int stone_attr=Map_Object_Descr::get_attribute_id("stone");
356
map->find_immovables (field, 8, &immovables);
358
field.reachable=false;
359
field.frontierhouses=0;
366
for (unsigned int i=0;i<immovables.size();i++) {
367
if (immovables[i].object->get_type()>=BaseImmovable::BUILDING)
368
field.reachable=true;
370
if (immovables[i].object->get_type()==BaseImmovable::BUILDING && map->calc_distance(field,immovables[i].coords)<=6) {
371
std::string name=static_cast<Building*>(immovables[i].object)->get_name();
373
if (buildings[name].is_constructionsite)
374
name=static_cast<ConstructionSite*>(immovables[i].object)->get_building()->get_name();
376
if (name=="frontierhouse")
377
field.frontierhouses++;
379
if (name=="lumberjack")
382
if (name=="forrester")
391
if (immovables[i].object->has_attribute(tree_attr))
394
if (immovables[i].object->has_attribute(stone_attr))
399
Computer_Player::EconomyObserver& Computer_Player::get_economy_observer (Economy* economy)
401
std::list<EconomyObserver>::iterator i;
403
for (i=economies.begin(); i!=economies.end(); i++)
404
if (i->economy==economy)
407
economies.push_front (EconomyObserver(economy));
409
return economies.front();
412
void Computer_Player::gain_building (Building* b)
414
BuildingObserver& bo=buildings[b->get_name()];
416
if (bo.is_constructionsite) {
417
buildings[static_cast<ConstructionSite*>(b)->get_building()->get_name()].cnt_under_construction++;
418
total_constructionsites++;
424
void Computer_Player::lose_building (Building* b)
426
BuildingObserver& bo=buildings[b->get_name()];
428
if (bo.is_constructionsite) {
429
buildings[static_cast<ConstructionSite*>(b)->get_building()->get_name()].cnt_under_construction--;
430
total_constructionsites--;
437
struct FindFieldWithFlagOrRoad:FindField {
439
virtual bool accept(FCoords coord) const;
442
bool FindFieldWithFlagOrRoad::accept (FCoords fc) const
444
BaseImmovable* imm=fc.field->get_immovable();
449
if (imm->get_type()>=BaseImmovable::BUILDING && static_cast<PlayerImmovable*>(imm)->get_economy()==economy)
452
if (imm->get_type()==BaseImmovable::FLAG)
455
if (imm->get_type()==BaseImmovable::ROAD && (fc.field->get_caps()&BUILDCAPS_FLAG)!=0)
461
void Computer_Player::connect_flag_to_another_economy (Flag* flag)
463
FindFieldWithFlagOrRoad functor;
464
CheckStepRoadAI check(player, MOVECAPS_WALK);
465
std::vector<Coords> reachable;
467
// first look for possible destinations
468
functor.economy=flag->get_economy();
469
map->find_reachable_fields (flag->get_position(), 16, &reachable, &check, functor);
471
if (reachable.empty())
474
// then choose the one closest to the originating flag
475
int closest, distance;
478
distance=map->calc_distance(flag->get_position(), reachable[0]);
479
for (unsigned int i=1; i<reachable.size(); i++) {
480
int d=map->calc_distance(flag->get_position(), reachable[i]);
488
// if we join a road and there is no flag yet, build one
489
Field* field=map->get_field(reachable[closest]);
490
if (field->get_immovable()->get_type()==BaseImmovable::ROAD)
491
game->send_player_build_flag (player_number, reachable[closest]);
493
// and finally build the road
494
Path* path=new Path();
495
if (map->findpath(flag->get_position(), reachable[closest], 0, path, &check) < 0)
498
game->send_player_build_road (player_number, path);
501
// this is called whenever we gain ownership of a PlayerImmovable
502
void Computer_Player::gain_immovable (PlayerImmovable* pi)
504
switch (pi->get_type()) {
505
case BaseImmovable::BUILDING:
506
gain_building (static_cast<Building*>(pi));
508
case BaseImmovable::FLAG:
509
new_flags.push_back (static_cast<Flag*>(pi));
511
case BaseImmovable::ROAD:
512
roads.push_front (static_cast<Road*>(pi));
517
// this is called whenever we lose ownership of a PlayerImmovable
518
void Computer_Player::lose_immovable (PlayerImmovable* pi)
520
switch (pi->get_type()) {
521
case BaseImmovable::BUILDING:
522
lose_building (static_cast<Building*>(pi));
524
case BaseImmovable::ROAD:
525
roads.remove (static_cast<Road*>(pi));
530
// this is called whenever we gain ownership of a field on the map
531
void Computer_Player::gain_field (const FCoords& fc)
533
unusable_fields.push_back (fc);
536
// we don't use this - instead we check or fields regularly, see think()
537
void Computer_Player::lose_field (const FCoords& fc)
542
/* CheckStepRoadAI */
543
bool CheckStepRoadAI::allowed(Map* map, FCoords start, FCoords end, int dir, StepId id) const
545
uchar endcaps = m_player->get_buildcaps(end);
547
// Calculate cost and passability
548
if (!(endcaps & m_movecaps)) {
549
uchar startcaps = m_player->get_buildcaps(start);
551
if (!((endcaps & MOVECAPS_WALK) && (startcaps & m_movecaps & MOVECAPS_SWIM)))
555
// Check for blocking immovables
556
BaseImmovable *imm = map->get_immovable(end);
557
if (imm && imm->get_size() >= BaseImmovable::SMALL) {
558
// if (id != stepLast)
560
if (imm->get_type()==Map_Object::FLAG)
563
if ((imm->get_type() != Map_Object::ROAD || !(endcaps & BUILDCAPS_FLAG)))
570
bool CheckStepRoadAI::reachabledest(Map* map, FCoords dest) const
572
uchar caps = dest.field->get_caps();
574
if (!(caps & m_movecaps)) {
575
if (!((m_movecaps & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK)))
578
if (!map->can_reach_by_water(dest))