00001
00002
00003 #include "../../stdafx.h"
00004 #include "../../openttd.h"
00005 #include "../../aircraft.h"
00006 #include "../../bridge_map.h"
00007 #include "../../tile_cmd.h"
00008 #include "../../landscape.h"
00009 #include "../../rail_map.h"
00010 #include "../../road_map.h"
00011 #include "../../roadveh.h"
00012 #include "../../station_map.h"
00013 #include "../../tunnel_map.h"
00014 #include "../../engine.h"
00015 #include "../../command_func.h"
00016 #include "../../town.h"
00017 #include "../../industry.h"
00018 #include "../../station.h"
00019 #include "../../pathfind.h"
00020 #include "../../airport.h"
00021 #include "../../depot.h"
00022 #include "../../variables.h"
00023 #include "../../bridge.h"
00024 #include "../../date_func.h"
00025 #include "../../tunnelbridge_map.h"
00026 #include "../../window_func.h"
00027 #include "../../vehicle_func.h"
00028 #include "../../functions.h"
00029 #include "../../saveload.h"
00030 #include "../../player_func.h"
00031 #include "../../player_base.h"
00032 #include "../../settings_type.h"
00033 #include "default.h"
00034 #include "../../tunnelbridge.h"
00035
00036 #include "../../table/ai_rail.h"
00037
00038
00039 static uint _ai_service_interval;
00040 PlayerAI _players_ai[MAX_PLAYERS];
00041
00042 typedef void AiStateAction(Player *p);
00043
00044 enum {
00045 AIS_0 = 0,
00046 AIS_1 = 1,
00047 AIS_VEH_LOOP = 2,
00048 AIS_VEH_CHECK_REPLACE_VEHICLE = 3,
00049 AIS_VEH_DO_REPLACE_VEHICLE = 4,
00050 AIS_WANT_NEW_ROUTE = 5,
00051 AIS_BUILD_DEFAULT_RAIL_BLOCKS = 6,
00052 AIS_BUILD_RAIL = 7,
00053 AIS_BUILD_RAIL_VEH = 8,
00054 AIS_DELETE_RAIL_BLOCKS = 9,
00055 AIS_BUILD_DEFAULT_ROAD_BLOCKS = 10,
00056 AIS_BUILD_ROAD = 11,
00057 AIS_BUILD_ROAD_VEHICLES = 12,
00058 AIS_DELETE_ROAD_BLOCKS = 13,
00059 AIS_AIRPORT_STUFF = 14,
00060 AIS_BUILD_DEFAULT_AIRPORT_BLOCKS = 15,
00061 AIS_BUILD_AIRCRAFT_VEHICLES = 16,
00062 AIS_CHECK_SHIP_STUFF = 17,
00063 AIS_BUILD_DEFAULT_SHIP_BLOCKS = 18,
00064 AIS_DO_SHIP_STUFF = 19,
00065 AIS_SELL_VEHICLE = 20,
00066 AIS_REMOVE_STATION = 21,
00067 AIS_REMOVE_TRACK = 22,
00068 AIS_REMOVE_SINGLE_RAIL_TILE = 23
00069 };
00070
00071
00072 static inline TrackBits GetRailTrackStatus(TileIndex tile)
00073 {
00074 return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00075 }
00076
00077
00078 static void AiCase0(Player *p)
00079 {
00080 _players_ai[p->index].state = AIS_REMOVE_TRACK;
00081 _players_ai[p->index].state_counter = 0;
00082 }
00083
00084 static void AiCase1(Player *p)
00085 {
00086 _players_ai[p->index].cur_veh = NULL;
00087 _players_ai[p->index].state = AIS_VEH_LOOP;
00088 }
00089
00090 static void AiStateVehLoop(Player *p)
00091 {
00092 Vehicle *v;
00093 uint index;
00094
00095 index = (_players_ai[p->index].cur_veh == NULL) ? 0 : _players_ai[p->index].cur_veh->index + 1;
00096
00097 FOR_ALL_VEHICLES_FROM(v, index) {
00098 if (v->owner != _current_player) continue;
00099
00100 if ((v->type == VEH_TRAIN && v->subtype == 0) ||
00101 v->type == VEH_ROAD ||
00102 (v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) ||
00103 v->type == VEH_SHIP) {
00104
00105 if (v->type == VEH_TRAIN && v->engine_type < 3 &&
00106 (_price.build_railvehicle >> 3) < p->player_money) {
00107 _players_ai[p->index].state = AIS_VEH_CHECK_REPLACE_VEHICLE;
00108 _players_ai[p->index].cur_veh = v;
00109 return;
00110 }
00111
00112
00113 if (v->age >= 730 &&
00114 v->profit_last_year < _price.station_value * 5 * 256 &&
00115 v->profit_this_year < _price.station_value * 5 * 256) {
00116 _players_ai[p->index].state_counter = 0;
00117 _players_ai[p->index].state = AIS_SELL_VEHICLE;
00118 _players_ai[p->index].cur_veh = v;
00119 return;
00120 }
00121
00122
00123 if (v->age >= v->max_age || (
00124 v->age != 0 &&
00125 GetEngine(v->engine_type)->reliability < 35389
00126 )) {
00127 _players_ai[p->index].state = AIS_VEH_CHECK_REPLACE_VEHICLE;
00128 _players_ai[p->index].cur_veh = v;
00129 return;
00130 }
00131 }
00132 }
00133
00134 _players_ai[p->index].state = AIS_WANT_NEW_ROUTE;
00135 _players_ai[p->index].state_counter = 0;
00136 }
00137
00138 static EngineID AiChooseTrainToBuild(RailType railtype, Money money, byte flag, TileIndex tile)
00139 {
00140 EngineID best_veh_index = INVALID_ENGINE;
00141 byte best_veh_score = 0;
00142 EngineID i;
00143
00144 FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_TRAIN) {
00145 const RailVehicleInfo *rvi = RailVehInfo(i);
00146 const Engine* e = GetEngine(i);
00147
00148 if (!IsCompatibleRail(rvi->railtype, railtype) ||
00149 rvi->railveh_type == RAILVEH_WAGON ||
00150 (rvi->railveh_type == RAILVEH_MULTIHEAD && flag & 1) ||
00151 !HasBit(e->player_avail, _current_player) ||
00152 e->reliability < 0x8A3D) {
00153 continue;
00154 }
00155
00156
00157 if (rvi->ai_passenger_only != 0 && flag == 1) continue;
00158
00159 CommandCost ret = DoCommand(tile, i, 0, 0, CMD_BUILD_RAIL_VEHICLE);
00160 if (CmdSucceeded(ret) && ret.GetCost() <= money && rvi->ai_rank >= best_veh_score) {
00161 best_veh_score = rvi->ai_rank;
00162 best_veh_index = i;
00163 }
00164 }
00165
00166 return best_veh_index;
00167 }
00168
00169 static EngineID AiChooseRoadVehToBuild(CargoID cargo, Money money, TileIndex tile)
00170 {
00171 EngineID best_veh_index = INVALID_ENGINE;
00172 int32 best_veh_rating = 0;
00173 EngineID i;
00174
00175 FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_ROAD) {
00176 const RoadVehicleInfo *rvi = RoadVehInfo(i);
00177 const Engine* e = GetEngine(i);
00178
00179 if (!HasBit(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
00180 continue;
00181 }
00182
00183
00184 if (rvi->cargo_type != cargo && !CanRefitTo(i, cargo)) continue;
00185
00186
00187 int rating = rvi->max_speed * rvi->capacity;
00188 if (rating <= best_veh_rating) continue;
00189
00190 CommandCost ret = DoCommand(tile, i, 0, 0, CMD_BUILD_ROAD_VEH);
00191 if (CmdFailed(ret)) continue;
00192
00193
00194 if (rvi->cargo_type != cargo) ret.AddCost(GetRefitCost(i));
00195 if (ret.GetCost() > money) continue;
00196
00197 best_veh_rating = rating;
00198 best_veh_index = i;
00199 }
00200
00201 return best_veh_index;
00202 }
00203
00210 static EngineID AiChooseAircraftToBuild(Money money, byte forbidden)
00211 {
00212 EngineID best_veh_index = INVALID_ENGINE;
00213 Money best_veh_cost = 0;
00214 EngineID i;
00215
00216 FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_AIRCRAFT) {
00217 const Engine* e = GetEngine(i);
00218
00219 if (!HasBit(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
00220 continue;
00221 }
00222
00223 if ((AircraftVehInfo(i)->subtype & forbidden) != 0) continue;
00224
00225 CommandCost ret = DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_AIRCRAFT);
00226 if (CmdSucceeded(ret) && ret.GetCost() <= money && ret.GetCost() >= best_veh_cost) {
00227 best_veh_cost = ret.GetCost();
00228 best_veh_index = i;
00229 }
00230 }
00231
00232 return best_veh_index;
00233 }
00234
00235 static Money AiGetBasePrice(const Player* p)
00236 {
00237 Money base = _price.station_value;
00238
00239
00240 switch (_players_ai[p->index].railtype_to_use) {
00241 default: NOT_REACHED();
00242 case RAILTYPE_RAIL: break;
00243 case RAILTYPE_ELECTRIC: break;
00244 case RAILTYPE_MONO: base = (base * 3) >> 1; break;
00245 case RAILTYPE_MAGLEV: base *= 2; break;
00246 }
00247
00248 return base;
00249 }
00250
00251 static EngineID AiChooseRoadVehToReplaceWith(const Player* p, const Vehicle* v)
00252 {
00253 Money avail_money = p->player_money + v->value;
00254 return AiChooseRoadVehToBuild(v->cargo_type, avail_money, v->tile);
00255 }
00256
00257 static EngineID AiChooseAircraftToReplaceWith(const Player* p, const Vehicle* v)
00258 {
00259 Money avail_money = p->player_money + v->value;
00260
00261
00262 byte forbidden = 0;
00263 const Order *o;
00264
00265 FOR_VEHICLE_ORDERS(v, o) {
00266 if (!o->IsValid()) continue;
00267 if (!IsValidStationID(o->dest)) continue;
00268 const Station *st = GetStation(o->dest);
00269 if (!(st->facilities & FACIL_AIRPORT)) continue;
00270
00271 AirportFTAClass::Flags flags = st->Airport()->flags;
00272 if (!(flags & AirportFTAClass::AIRPLANES)) forbidden |= AIR_CTOL | AIR_FAST;
00273 if (flags & AirportFTAClass::SHORT_STRIP) forbidden |= AIR_FAST;
00274 }
00275
00276 return AiChooseAircraftToBuild(
00277 avail_money, forbidden
00278 );
00279 }
00280
00281 static EngineID AiChooseTrainToReplaceWith(const Player* p, const Vehicle* v)
00282 {
00283 Money avail_money = p->player_money + v->value;
00284 const Vehicle* u = v;
00285 int num = 0;
00286
00287 while (++num, u->Next() != NULL) {
00288 u = u->Next();
00289 }
00290
00291
00292 return AiChooseTrainToBuild(v->u.rail.railtype, avail_money, 0, v->tile);
00293 }
00294
00295 static EngineID AiChooseShipToReplaceWith(const Player* p, const Vehicle* v)
00296 {
00297
00298 return INVALID_ENGINE;
00299 }
00300
00301 static void AiHandleGotoDepot(Player *p, int cmd)
00302 {
00303 if (_players_ai[p->index].cur_veh->current_order.type != OT_GOTO_DEPOT)
00304 DoCommand(0, _players_ai[p->index].cur_veh->index, 0, DC_EXEC, cmd);
00305
00306 if (++_players_ai[p->index].state_counter <= 1387) {
00307 _players_ai[p->index].state = AIS_VEH_DO_REPLACE_VEHICLE;
00308 return;
00309 }
00310
00311 if (_players_ai[p->index].cur_veh->current_order.type == OT_GOTO_DEPOT) {
00312 _players_ai[p->index].cur_veh->current_order.type = OT_DUMMY;
00313 _players_ai[p->index].cur_veh->current_order.flags = 0;
00314 InvalidateWindow(WC_VEHICLE_VIEW, _players_ai[p->index].cur_veh->index);
00315 }
00316 }
00317
00318 static void AiRestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
00319 {
00320 if (bak->order == NULL) return;
00321
00322 for (uint i = 0; bak->order[i].type != OT_NOTHING; i++) {
00323 if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
00324 break;
00325 }
00326 }
00327
00328 static void AiHandleReplaceTrain(Player *p)
00329 {
00330 const Vehicle* v = _players_ai[p->index].cur_veh;
00331 BackuppedOrders orderbak;
00332 EngineID veh;
00333
00334
00335 if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
00336 AiHandleGotoDepot(p, CMD_SEND_TRAIN_TO_DEPOT);
00337 return;
00338 }
00339
00340 veh = AiChooseTrainToReplaceWith(p, v);
00341 if (veh != INVALID_ENGINE) {
00342 TileIndex tile;
00343
00344 BackupVehicleOrders(v, &orderbak);
00345 tile = v->tile;
00346
00347 if (CmdSucceeded(DoCommand(0, v->index, 2, DC_EXEC, CMD_SELL_RAIL_WAGON)) &&
00348 CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE))) {
00349 VehicleID veh = _new_vehicle_id;
00350 AiRestoreVehicleOrders(GetVehicle(veh), &orderbak);
00351 DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_TRAIN);
00352
00353 DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
00354 }
00355 }
00356 }
00357
00358 static void AiHandleReplaceRoadVeh(Player *p)
00359 {
00360 const Vehicle* v = _players_ai[p->index].cur_veh;
00361 BackuppedOrders orderbak;
00362 EngineID veh;
00363
00364 if (!v->IsStoppedInDepot()) {
00365 AiHandleGotoDepot(p, CMD_SEND_ROADVEH_TO_DEPOT);
00366 return;
00367 }
00368
00369 veh = AiChooseRoadVehToReplaceWith(p, v);
00370 if (veh != INVALID_ENGINE) {
00371 TileIndex tile;
00372
00373 BackupVehicleOrders(v, &orderbak);
00374 tile = v->tile;
00375
00376 if (CmdSucceeded(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH)) &&
00377 CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) {
00378 VehicleID veh = _new_vehicle_id;
00379
00380 AiRestoreVehicleOrders(GetVehicle(veh), &orderbak);
00381 DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
00382 DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
00383 }
00384 }
00385 }
00386
00387 static void AiHandleReplaceAircraft(Player *p)
00388 {
00389 const Vehicle* v = _players_ai[p->index].cur_veh;
00390 BackuppedOrders orderbak;
00391 EngineID veh;
00392
00393 if (!v->IsStoppedInDepot()) {
00394 AiHandleGotoDepot(p, CMD_SEND_AIRCRAFT_TO_HANGAR);
00395 return;
00396 }
00397
00398 veh = AiChooseAircraftToReplaceWith(p, v);
00399 if (veh != INVALID_ENGINE) {
00400 TileIndex tile;
00401
00402 BackupVehicleOrders(v, &orderbak);
00403 tile = v->tile;
00404
00405 if (CmdSucceeded(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
00406 CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) {
00407 VehicleID veh = _new_vehicle_id;
00408 AiRestoreVehicleOrders(GetVehicle(veh), &orderbak);
00409 DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
00410
00411 DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
00412 }
00413 }
00414 }
00415
00416 static void AiHandleReplaceShip(Player *p)
00417 {
00418
00419 }
00420
00421 typedef EngineID CheckReplaceProc(const Player* p, const Vehicle* v);
00422
00423 static CheckReplaceProc* const _veh_check_replace_proc[] = {
00424 AiChooseTrainToReplaceWith,
00425 AiChooseRoadVehToReplaceWith,
00426 AiChooseShipToReplaceWith,
00427 AiChooseAircraftToReplaceWith,
00428 };
00429
00430 typedef void DoReplaceProc(Player *p);
00431 static DoReplaceProc* const _veh_do_replace_proc[] = {
00432 AiHandleReplaceTrain,
00433 AiHandleReplaceRoadVeh,
00434 AiHandleReplaceShip,
00435 AiHandleReplaceAircraft
00436 };
00437
00438 static void AiStateCheckReplaceVehicle(Player *p)
00439 {
00440 const Vehicle* v = _players_ai[p->index].cur_veh;
00441
00442 if (!v->IsValid() ||
00443 v->owner != _current_player ||
00444 v->type > VEH_SHIP ||
00445 _veh_check_replace_proc[v->type - VEH_TRAIN](p, v) == INVALID_ENGINE) {
00446 _players_ai[p->index].state = AIS_VEH_LOOP;
00447 } else {
00448 _players_ai[p->index].state_counter = 0;
00449 _players_ai[p->index].state = AIS_VEH_DO_REPLACE_VEHICLE;
00450 }
00451 }
00452
00453 static void AiStateDoReplaceVehicle(Player *p)
00454 {
00455 const Vehicle* v = _players_ai[p->index].cur_veh;
00456
00457 _players_ai[p->index].state = AIS_VEH_LOOP;
00458
00459 if (!v->IsValid() || v->owner != _current_player) return;
00460 _veh_do_replace_proc[v->type - VEH_TRAIN](p);
00461 }
00462
00463 struct FoundRoute {
00464 int distance;
00465 CargoID cargo;
00466 void *from;
00467 void *to;
00468 };
00469
00470 static Town *AiFindRandomTown()
00471 {
00472 return GetRandomTown();
00473 }
00474
00475 static Industry *AiFindRandomIndustry()
00476 {
00477 int num = RandomRange(GetMaxIndustryIndex());
00478 if (IsValidIndustryID(num)) return GetIndustry(num);
00479
00480 return NULL;
00481 }
00482
00483 static void AiFindSubsidyIndustryRoute(FoundRoute *fr)
00484 {
00485 uint i;
00486 CargoID cargo;
00487 const Subsidy* s;
00488 Industry* from;
00489 TileIndex to_xy;
00490
00491
00492 fr->distance = -1;
00493
00494
00495 i = RandomRange(lengthof(_subsidies) * 3);
00496 if (i >= lengthof(_subsidies)) return;
00497
00498 s = &_subsidies[i];
00499
00500
00501 cargo = s->cargo_type;
00502 if (cargo == CT_INVALID ||
00503 cargo == CT_PASSENGERS ||
00504 cargo == CT_MAIL ||
00505 s->age > 7) {
00506 return;
00507 }
00508 fr->cargo = cargo;
00509
00510 fr->from = from = GetIndustry(s->from);
00511
00512 if (cargo == CT_GOODS || cargo == CT_FOOD) {
00513 Town* to_tow = GetTown(s->to);
00514
00515 if (to_tow->population < (cargo == CT_FOOD ? 200U : 900U)) return;
00516 fr->to = to_tow;
00517 to_xy = to_tow->xy;
00518 } else {
00519 Industry* to_ind = GetIndustry(s->to);
00520
00521 fr->to = to_ind;
00522 to_xy = to_ind->xy;
00523 }
00524
00525 fr->distance = DistanceManhattan(from->xy, to_xy);
00526 }
00527
00528 static void AiFindSubsidyPassengerRoute(FoundRoute *fr)
00529 {
00530 uint i;
00531 const Subsidy* s;
00532 Town *from, *to;
00533
00534
00535 fr->distance = -1;
00536
00537
00538 i = RandomRange(lengthof(_subsidies) * 3);
00539 if (i >= lengthof(_subsidies)) return;
00540
00541 s = &_subsidies[i];
00542
00543
00544 if (s->cargo_type != CT_PASSENGERS || s->age > 7) return;
00545 fr->cargo = s->cargo_type;
00546
00547 fr->from = from = GetTown(s->from);
00548 fr->to = to = GetTown(s->to);
00549
00550
00551 if (from->population < 400 || to->population < 400) return;
00552
00553 fr->distance = DistanceManhattan(from->xy, to->xy);
00554 }
00555
00556 static void AiFindRandomIndustryRoute(FoundRoute *fr)
00557 {
00558 Industry* i;
00559 uint32 r;
00560 CargoID cargo;
00561
00562
00563 fr->distance = -1;
00564
00565 r = Random();
00566
00567
00568 fr->from = i = AiFindRandomIndustry();
00569 if (i == NULL) return;
00570
00571
00572 cargo = i->produced_cargo[0];
00573 if (r & 1 && i->produced_cargo[1] != CT_INVALID) cargo = i->produced_cargo[1];
00574
00575 fr->cargo = cargo;
00576
00577
00578 if (cargo == CT_INVALID || cargo == CT_PASSENGERS) return;
00579
00580 if (cargo != CT_GOODS && cargo != CT_FOOD) {
00581
00582 Industry* i2 = AiFindRandomIndustry();
00583 if (i2 == NULL || i == i2 ||
00584 (i2->accepts_cargo[0] != cargo &&
00585 i2->accepts_cargo[1] != cargo &&
00586 i2->accepts_cargo[2] != cargo)) {
00587 return;
00588 }
00589
00590 fr->to = i2;
00591 fr->distance = DistanceManhattan(i->xy, i2->xy);
00592 } else {
00593
00594 Town* t = AiFindRandomTown();
00595
00596 if (t == NULL || t->population < (cargo == CT_FOOD ? 200U : 900U)) return;
00597
00598 fr->to = t;
00599 fr->distance = DistanceManhattan(i->xy, t->xy);
00600 }
00601 }
00602
00603 static void AiFindRandomPassengerRoute(FoundRoute *fr)
00604 {
00605 Town* source;
00606 Town* dest;
00607
00608
00609 fr->distance = -1;
00610
00611 fr->from = source = AiFindRandomTown();
00612 if (source == NULL || source->population < 400) return;
00613
00614 fr->to = dest = AiFindRandomTown();
00615 if (dest == NULL || source == dest || dest->population < 400) return;
00616
00617 fr->distance = DistanceManhattan(source->xy, dest->xy);
00618 }
00619
00620
00621 #define GET_TOWN_OR_INDUSTRY_TILE(p) (((Town*)(p))->xy)
00622
00623 static bool AiCheckIfRouteIsGood(Player *p, FoundRoute *fr, byte bitmask)
00624 {
00625 TileIndex from_tile, to_tile;
00626 Station *st;
00627 int dist;
00628 uint same_station = 0;
00629
00630 from_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->from);
00631 to_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->to);
00632
00633 dist = 0xFFFF;
00634 FOR_ALL_STATIONS(st) {
00635 int cur;
00636
00637 if (st->owner != _current_player) continue;
00638 cur = DistanceMax(from_tile, st->xy);
00639 if (cur < dist) dist = cur;
00640 cur = DistanceMax(to_tile, st->xy);
00641 if (cur < dist) dist = cur;
00642 if (to_tile == from_tile && st->xy == to_tile) same_station++;
00643 }
00644
00645
00646
00647 if ((bitmask == 2 || bitmask == 4) &&
00648 same_station > 2 &&
00649 ((Town*)fr->from)->population < same_station * 350) {
00650 return false;
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 int min_distance = 36 + (1 << (Random() % 9));
00663
00664
00665 if (dist != 0xFFFF && dist > min_distance) return false;
00666
00667 if (_players_ai[p->index].route_type_mask != 0 &&
00668 !(_players_ai[p->index].route_type_mask & bitmask) &&
00669 !Chance16(1, 5)) {
00670 return false;
00671 }
00672
00673 if (fr->cargo == CT_PASSENGERS || fr->cargo == CT_MAIL) {
00674 const Town* from = (const Town*)fr->from;
00675 const Town* to = (const Town*)fr->to;
00676
00677 if (from->pct_pass_transported > 0x99 ||
00678 to->pct_pass_transported > 0x99) {
00679 return false;
00680 }
00681
00682
00683 if (from->ratings[_current_player] < -100 ||
00684 to->ratings[_current_player] < -100) {
00685 return false;
00686 }
00687 } else {
00688 const Industry* i = (const Industry*)fr->from;
00689
00690 if (i->last_month_pct_transported[fr->cargo != i->produced_cargo[0]] > 0x99 ||
00691 i->last_month_production[fr->cargo != i->produced_cargo[0]] == 0) {
00692 return false;
00693 }
00694 }
00695
00696 _players_ai[p->index].route_type_mask |= bitmask;
00697 return true;
00698 }
00699
00700 static byte AiGetDirectionBetweenTiles(TileIndex a, TileIndex b)
00701 {
00702 byte i = (TileX(a) < TileX(b)) ? 1 : 0;
00703 if (TileY(a) >= TileY(b)) i ^= 3;
00704 return i;
00705 }
00706
00707 static TileIndex AiGetPctTileBetween(TileIndex a, TileIndex b, byte pct)
00708 {
00709 return TileXY(
00710 TileX(a) + ((TileX(b) - TileX(a)) * pct >> 8),
00711 TileY(a) + ((TileY(b) - TileY(a)) * pct >> 8)
00712 );
00713 }
00714
00715 static void AiWantLongIndustryRoute(Player *p)
00716 {
00717 int i;
00718 FoundRoute fr;
00719
00720 i = 60;
00721 for (;;) {
00722
00723 AiFindSubsidyIndustryRoute(&fr);
00724 if (IsInsideMM(fr.distance, 60, 90 + 1)) break;
00725
00726
00727 AiFindRandomIndustryRoute(&fr);
00728 if (IsInsideMM(fr.distance, 60, 90 + 1)) break;
00729
00730
00731 if (--i == 0) return;
00732 }
00733
00734 if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
00735
00736
00737 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
00738 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
00739
00740 _players_ai[p->index].src.use_tile = 0;
00741 _players_ai[p->index].src.rand_rng = 9;
00742 _players_ai[p->index].src.cur_building_rule = 0xFF;
00743 _players_ai[p->index].src.unk6 = 1;
00744 _players_ai[p->index].src.unk7 = 0;
00745 _players_ai[p->index].src.buildcmd_a = 0x24;
00746 _players_ai[p->index].src.buildcmd_b = 0xFF;
00747 _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles(
00748 _players_ai[p->index].src.spec_tile,
00749 _players_ai[p->index].dst.spec_tile
00750 );
00751 _players_ai[p->index].src.cargo = fr.cargo | 0x80;
00752
00753
00754
00755 _players_ai[p->index].dst.use_tile = 0;
00756 _players_ai[p->index].dst.rand_rng = 9;
00757 _players_ai[p->index].dst.cur_building_rule = 0xFF;
00758 _players_ai[p->index].dst.unk6 = 1;
00759 _players_ai[p->index].dst.unk7 = 0;
00760 _players_ai[p->index].dst.buildcmd_a = 0x34;
00761 _players_ai[p->index].dst.buildcmd_b = 0xFF;
00762 _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles(
00763 _players_ai[p->index].dst.spec_tile,
00764 _players_ai[p->index].src.spec_tile
00765 );
00766 _players_ai[p->index].dst.cargo = fr.cargo;
00767
00768
00769 _players_ai[p->index].mid1.spec_tile = AiGetPctTileBetween(
00770 _players_ai[p->index].src.spec_tile,
00771 _players_ai[p->index].dst.spec_tile,
00772 0x55
00773 );
00774 _players_ai[p->index].mid1.use_tile = 0;
00775 _players_ai[p->index].mid1.rand_rng = 6;
00776 _players_ai[p->index].mid1.cur_building_rule = 0xFF;
00777 _players_ai[p->index].mid1.unk6 = 2;
00778 _players_ai[p->index].mid1.unk7 = 1;
00779 _players_ai[p->index].mid1.buildcmd_a = 0x30;
00780 _players_ai[p->index].mid1.buildcmd_b = 0xFF;
00781 _players_ai[p->index].mid1.direction = _players_ai[p->index].src.direction;
00782 _players_ai[p->index].mid1.cargo = fr.cargo;
00783
00784
00785 _players_ai[p->index].mid2.spec_tile = AiGetPctTileBetween(
00786 _players_ai[p->index].src.spec_tile,
00787 _players_ai[p->index].dst.spec_tile,
00788 0xAA
00789 );
00790 _players_ai[p->index].mid2.use_tile = 0;
00791 _players_ai[p->index].mid2.rand_rng = 6;
00792 _players_ai[p->index].mid2.cur_building_rule = 0xFF;
00793 _players_ai[p->index].mid2.unk6 = 2;
00794 _players_ai[p->index].mid2.unk7 = 1;
00795 _players_ai[p->index].mid2.buildcmd_a = 0xFF;
00796 _players_ai[p->index].mid2.buildcmd_b = 0xFF;
00797 _players_ai[p->index].mid2.direction = _players_ai[p->index].dst.direction;
00798 _players_ai[p->index].mid2.cargo = fr.cargo;
00799
00800
00801 _players_ai[p->index].cargo_type = fr.cargo;
00802 _players_ai[p->index].num_wagons = 3;
00803 _players_ai[p->index].build_kind = 2;
00804 _players_ai[p->index].num_build_rec = 4;
00805 _players_ai[p->index].num_loco_to_build = 2;
00806 _players_ai[p->index].num_want_fullload = 2;
00807 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
00808 _players_ai[p->index].order_list_blocks[0] = 0;
00809 _players_ai[p->index].order_list_blocks[1] = 1;
00810 _players_ai[p->index].order_list_blocks[2] = 255;
00811
00812 _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
00813 _players_ai[p->index].state_mode = UCHAR_MAX;
00814 _players_ai[p->index].state_counter = 0;
00815 _players_ai[p->index].timeout_counter = 0;
00816 }
00817
00818 static void AiWantMediumIndustryRoute(Player *p)
00819 {
00820 int i;
00821 FoundRoute fr;
00822
00823 i = 60;
00824 for (;;) {
00825
00826 AiFindSubsidyIndustryRoute(&fr);
00827 if (IsInsideMM(fr.distance, 40, 60 + 1)) break;
00828
00829
00830 AiFindRandomIndustryRoute(&fr);
00831 if (IsInsideMM(fr.distance, 40, 60 + 1)) break;
00832
00833
00834 if (--i == 0) return;
00835 }
00836
00837 if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
00838
00839
00840 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
00841 _players_ai[p->index].src.use_tile = 0;
00842 _players_ai[p->index].src.rand_rng = 9;
00843 _players_ai[p->index].src.cur_building_rule = 0xFF;
00844 _players_ai[p->index].src.unk6 = 1;
00845 _players_ai[p->index].src.unk7 = 0;
00846 _players_ai[p->index].src.buildcmd_a = 0x10;
00847 _players_ai[p->index].src.buildcmd_b = 0xFF;
00848 _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles(
00849 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
00850 GET_TOWN_OR_INDUSTRY_TILE(fr.to)
00851 );
00852 _players_ai[p->index].src.cargo = fr.cargo | 0x80;
00853
00854
00855 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
00856 _players_ai[p->index].dst.use_tile = 0;
00857 _players_ai[p->index].dst.rand_rng = 9;
00858 _players_ai[p->index].dst.cur_building_rule = 0xFF;
00859 _players_ai[p->index].dst.unk6 = 1;
00860 _players_ai[p->index].dst.unk7 = 0;
00861 _players_ai[p->index].dst.buildcmd_a = 0xFF;
00862 _players_ai[p->index].dst.buildcmd_b = 0xFF;
00863 _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles(
00864 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
00865 GET_TOWN_OR_INDUSTRY_TILE(fr.from)
00866 );
00867 _players_ai[p->index].dst.cargo = fr.cargo;
00868
00869
00870 _players_ai[p->index].cargo_type = fr.cargo;
00871 _players_ai[p->index].num_wagons = 3;
00872 _players_ai[p->index].build_kind = 1;
00873 _players_ai[p->index].num_build_rec = 2;
00874 _players_ai[p->index].num_loco_to_build = 1;
00875 _players_ai[p->index].num_want_fullload = 1;
00876 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
00877 _players_ai[p->index].order_list_blocks[0] = 0;
00878 _players_ai[p->index].order_list_blocks[1] = 1;
00879 _players_ai[p->index].order_list_blocks[2] = 255;
00880 _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
00881 _players_ai[p->index].state_mode = UCHAR_MAX;
00882 _players_ai[p->index].state_counter = 0;
00883 _players_ai[p->index].timeout_counter = 0;
00884 }
00885
00886 static void AiWantShortIndustryRoute(Player *p)
00887 {
00888 int i;
00889 FoundRoute fr;
00890
00891 i = 60;
00892 for (;;) {
00893
00894 AiFindSubsidyIndustryRoute(&fr);
00895 if (IsInsideMM(fr.distance, 15, 40 + 1)) break;
00896
00897
00898 AiFindRandomIndustryRoute(&fr);
00899 if (IsInsideMM(fr.distance, 15, 40 + 1)) break;
00900
00901
00902 if (--i == 0) return;
00903 }
00904
00905 if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
00906
00907
00908 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
00909 _players_ai[p->index].src.use_tile = 0;
00910 _players_ai[p->index].src.rand_rng = 9;
00911 _players_ai[p->index].src.cur_building_rule = 0xFF;
00912 _players_ai[p->index].src.unk6 = 1;
00913 _players_ai[p->index].src.unk7 = 0;
00914 _players_ai[p->index].src.buildcmd_a = 0x10;
00915 _players_ai[p->index].src.buildcmd_b = 0xFF;
00916 _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles(
00917 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
00918 GET_TOWN_OR_INDUSTRY_TILE(fr.to)
00919 );
00920 _players_ai[p->index].src.cargo = fr.cargo | 0x80;
00921
00922
00923 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
00924 _players_ai[p->index].dst.use_tile = 0;
00925 _players_ai[p->index].dst.rand_rng = 9;
00926 _players_ai[p->index].dst.cur_building_rule = 0xFF;
00927 _players_ai[p->index].dst.unk6 = 1;
00928 _players_ai[p->index].dst.unk7 = 0;
00929 _players_ai[p->index].dst.buildcmd_a = 0xFF;
00930 _players_ai[p->index].dst.buildcmd_b = 0xFF;
00931 _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles(
00932 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
00933 GET_TOWN_OR_INDUSTRY_TILE(fr.from)
00934 );
00935 _players_ai[p->index].dst.cargo = fr.cargo;
00936
00937
00938 _players_ai[p->index].cargo_type = fr.cargo;
00939 _players_ai[p->index].num_wagons = 2;
00940 _players_ai[p->index].build_kind = 1;
00941 _players_ai[p->index].num_build_rec = 2;
00942 _players_ai[p->index].num_loco_to_build = 1;
00943 _players_ai[p->index].num_want_fullload = 1;
00944 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
00945 _players_ai[p->index].order_list_blocks[0] = 0;
00946 _players_ai[p->index].order_list_blocks[1] = 1;
00947 _players_ai[p->index].order_list_blocks[2] = 255;
00948 _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
00949 _players_ai[p->index].state_mode = UCHAR_MAX;
00950 _players_ai[p->index].state_counter = 0;
00951 _players_ai[p->index].timeout_counter = 0;
00952 }
00953
00954 static void AiWantMailRoute(Player *p)
00955 {
00956 int i;
00957 FoundRoute fr;
00958
00959 i = 60;
00960 for (;;) {
00961
00962 AiFindSubsidyPassengerRoute(&fr);
00963 if (IsInsideMM(fr.distance, 60, 110 + 1)) break;
00964
00965
00966 AiFindRandomPassengerRoute(&fr);
00967 if (IsInsideMM(fr.distance, 60, 110 + 1)) break;
00968
00969
00970 if (--i == 0) return;
00971 }
00972
00973 fr.cargo = CT_MAIL;
00974 if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
00975
00976
00977 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
00978 _players_ai[p->index].src.use_tile = 0;
00979 _players_ai[p->index].src.rand_rng = 7;
00980 _players_ai[p->index].src.cur_building_rule = 0xFF;
00981 _players_ai[p->index].src.unk6 = 1;
00982 _players_ai[p->index].src.unk7 = 0;
00983 _players_ai[p->index].src.buildcmd_a = 0x24;
00984 _players_ai[p->index].src.buildcmd_b = 0xFF;
00985 _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles(
00986 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
00987 GET_TOWN_OR_INDUSTRY_TILE(fr.to)
00988 );
00989 _players_ai[p->index].src.cargo = fr.cargo;
00990
00991
00992 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
00993 _players_ai[p->index].dst.use_tile = 0;
00994 _players_ai[p->index].dst.rand_rng = 7;
00995 _players_ai[p->index].dst.cur_building_rule = 0xFF;
00996 _players_ai[p->index].dst.unk6 = 1;
00997 _players_ai[p->index].dst.unk7 = 0;
00998 _players_ai[p->index].dst.buildcmd_a = 0x34;
00999 _players_ai[p->index].dst.buildcmd_b = 0xFF;
01000 _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles(
01001 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
01002 GET_TOWN_OR_INDUSTRY_TILE(fr.from)
01003 );
01004 _players_ai[p->index].dst.cargo = fr.cargo;
01005
01006
01007 _players_ai[p->index].mid1.spec_tile = AiGetPctTileBetween(
01008 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
01009 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
01010 0x55
01011 );
01012 _players_ai[p->index].mid1.use_tile = 0;
01013 _players_ai[p->index].mid1.rand_rng = 6;
01014 _players_ai[p->index].mid1.cur_building_rule = 0xFF;
01015 _players_ai[p->index].mid1.unk6 = 2;
01016 _players_ai[p->index].mid1.unk7 = 1;
01017 _players_ai[p->index].mid1.buildcmd_a = 0x30;
01018 _players_ai[p->index].mid1.buildcmd_b = 0xFF;
01019 _players_ai[p->index].mid1.direction = _players_ai[p->index].src.direction;
01020 _players_ai[p->index].mid1.cargo = fr.cargo;
01021
01022
01023 _players_ai[p->index].mid2.spec_tile = AiGetPctTileBetween(
01024 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
01025 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
01026 0xAA
01027 );
01028 _players_ai[p->index].mid2.use_tile = 0;
01029 _players_ai[p->index].mid2.rand_rng = 6;
01030 _players_ai[p->index].mid2.cur_building_rule = 0xFF;
01031 _players_ai[p->index].mid2.unk6 = 2;
01032 _players_ai[p->index].mid2.unk7 = 1;
01033 _players_ai[p->index].mid2.buildcmd_a = 0xFF;
01034 _players_ai[p->index].mid2.buildcmd_b = 0xFF;
01035 _players_ai[p->index].mid2.direction = _players_ai[p->index].dst.direction;
01036 _players_ai[p->index].mid2.cargo = fr.cargo;
01037
01038
01039 _players_ai[p->index].cargo_type = fr.cargo;
01040 _players_ai[p->index].num_wagons = 3;
01041 _players_ai[p->index].build_kind = 2;
01042 _players_ai[p->index].num_build_rec = 4;
01043 _players_ai[p->index].num_loco_to_build = 2;
01044 _players_ai[p->index].num_want_fullload = 0;
01045 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
01046 _players_ai[p->index].order_list_blocks[0] = 0;
01047 _players_ai[p->index].order_list_blocks[1] = 1;
01048 _players_ai[p->index].order_list_blocks[2] = 255;
01049 _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
01050 _players_ai[p->index].state_mode = UCHAR_MAX;
01051 _players_ai[p->index].state_counter = 0;
01052 _players_ai[p->index].timeout_counter = 0;
01053 }
01054
01055 static void AiWantPassengerRoute(Player *p)
01056 {
01057 int i;
01058 FoundRoute fr;
01059
01060 i = 60;
01061 for (;;) {
01062
01063 AiFindSubsidyPassengerRoute(&fr);
01064 if (IsInsideMM(fr.distance, 0, 55 + 1)) break;
01065
01066
01067 AiFindRandomPassengerRoute(&fr);
01068 if (IsInsideMM(fr.distance, 0, 55 + 1)) break;
01069
01070
01071 if (--i == 0) return;
01072 }
01073
01074 fr.cargo = CT_PASSENGERS;
01075 if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
01076
01077
01078 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
01079 _players_ai[p->index].src.use_tile = 0;
01080 _players_ai[p->index].src.rand_rng = 7;
01081 _players_ai[p->index].src.cur_building_rule = 0xFF;
01082 _players_ai[p->index].src.unk6 = 1;
01083 _players_ai[p->index].src.unk7 = 0;
01084 _players_ai[p->index].src.buildcmd_a = 0x10;
01085 _players_ai[p->index].src.buildcmd_b = 0xFF;
01086 _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles(
01087 GET_TOWN_OR_INDUSTRY_TILE(fr.from),
01088 GET_TOWN_OR_INDUSTRY_TILE(fr.to)
01089 );
01090 _players_ai[p->index].src.cargo = fr.cargo;
01091
01092
01093 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
01094 _players_ai[p->index].dst.use_tile = 0;
01095 _players_ai[p->index].dst.rand_rng = 7;
01096 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01097 _players_ai[p->index].dst.unk6 = 1;
01098 _players_ai[p->index].dst.unk7 = 0;
01099 _players_ai[p->index].dst.buildcmd_a = 0xFF;
01100 _players_ai[p->index].dst.buildcmd_b = 0xFF;
01101 _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles(
01102 GET_TOWN_OR_INDUSTRY_TILE(fr.to),
01103 GET_TOWN_OR_INDUSTRY_TILE(fr.from)
01104 );
01105 _players_ai[p->index].dst.cargo = fr.cargo;
01106
01107
01108 _players_ai[p->index].cargo_type = fr.cargo;
01109 _players_ai[p->index].num_wagons = 2;
01110 _players_ai[p->index].build_kind = 1;
01111 _players_ai[p->index].num_build_rec = 2;
01112 _players_ai[p->index].num_loco_to_build = 1;
01113 _players_ai[p->index].num_want_fullload = 0;
01114 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
01115 _players_ai[p->index].order_list_blocks[0] = 0;
01116 _players_ai[p->index].order_list_blocks[1] = 1;
01117 _players_ai[p->index].order_list_blocks[2] = 255;
01118 _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
01119 _players_ai[p->index].state_mode = UCHAR_MAX;
01120 _players_ai[p->index].state_counter = 0;
01121 _players_ai[p->index].timeout_counter = 0;
01122 }
01123
01124 static void AiWantTrainRoute(Player *p)
01125 {
01126 uint16 r = GB(Random(), 0, 16);
01127
01128 _players_ai[p->index].railtype_to_use = GetBestRailtype(p->index);
01129
01130 if (r > 0xD000) {
01131 AiWantLongIndustryRoute(p);
01132 } else if (r > 0x6000) {
01133 AiWantMediumIndustryRoute(p);
01134 } else if (r > 0x1000) {
01135 AiWantShortIndustryRoute(p);
01136 } else if (r > 0x800) {
01137 AiWantPassengerRoute(p);
01138 } else {
01139 AiWantMailRoute(p);
01140 }
01141 }
01142
01143 static void AiWantLongRoadIndustryRoute(Player *p)
01144 {
01145 int i;
01146 FoundRoute fr;
01147
01148 i = 60;
01149 for (;;) {
01150
01151 AiFindSubsidyIndustryRoute(&fr);
01152 if (IsInsideMM(fr.distance, 35, 55 + 1)) break;
01153
01154
01155 AiFindRandomIndustryRoute(&fr);
01156 if (IsInsideMM(fr.distance, 35, 55 + 1)) break;
01157
01158
01159 if (--i == 0) return;
01160 }
01161
01162 if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
01163
01164
01165 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
01166 _players_ai[p->index].src.use_tile = 0;
01167 _players_ai[p->index].src.rand_rng = 9;
01168 _players_ai[p->index].src.cur_building_rule = 0xFF;
01169 _players_ai[p->index].src.buildcmd_a = 1;
01170 _players_ai[p->index].src.direction = 0;
01171 _players_ai[p->index].src.cargo = fr.cargo | 0x80;
01172
01173
01174 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
01175 _players_ai[p->index].dst.use_tile = 0;
01176 _players_ai[p->index].dst.rand_rng = 9;
01177 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01178 _players_ai[p->index].dst.buildcmd_a = 0xFF;
01179 _players_ai[p->index].dst.direction = 0;
01180 _players_ai[p->index].dst.cargo = fr.cargo;
01181
01182
01183 _players_ai[p->index].cargo_type = fr.cargo;
01184 _players_ai[p->index].num_build_rec = 2;
01185 _players_ai[p->index].num_loco_to_build = 5;
01186 _players_ai[p->index].num_want_fullload = 5;
01187
01188
01189 _players_ai[p->index].order_list_blocks[0] = 0;
01190 _players_ai[p->index].order_list_blocks[1] = 1;
01191 _players_ai[p->index].order_list_blocks[2] = 255;
01192
01193 _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
01194 _players_ai[p->index].state_mode = UCHAR_MAX;
01195 _players_ai[p->index].state_counter = 0;
01196 _players_ai[p->index].timeout_counter = 0;
01197 }
01198
01199 static void AiWantMediumRoadIndustryRoute(Player *p)
01200 {
01201 int i;
01202 FoundRoute fr;
01203
01204 i = 60;
01205 for (;;) {
01206
01207 AiFindSubsidyIndustryRoute(&fr);
01208 if (IsInsideMM(fr.distance, 15, 40 + 1)) break;
01209
01210
01211 AiFindRandomIndustryRoute(&fr);
01212 if (IsInsideMM(fr.distance, 15, 40 + 1)) break;
01213
01214
01215 if (--i == 0) return;
01216 }
01217
01218 if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
01219
01220
01221 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
01222 _players_ai[p->index].src.use_tile = 0;
01223 _players_ai[p->index].src.rand_rng = 9;
01224 _players_ai[p->index].src.cur_building_rule = 0xFF;
01225 _players_ai[p->index].src.buildcmd_a = 1;
01226 _players_ai[p->index].src.direction = 0;
01227 _players_ai[p->index].src.cargo = fr.cargo | 0x80;
01228
01229
01230 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
01231 _players_ai[p->index].dst.use_tile = 0;
01232 _players_ai[p->index].dst.rand_rng = 9;
01233 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01234 _players_ai[p->index].dst.buildcmd_a = 0xFF;
01235 _players_ai[p->index].dst.direction = 0;
01236 _players_ai[p->index].dst.cargo = fr.cargo;
01237
01238
01239 _players_ai[p->index].cargo_type = fr.cargo;
01240 _players_ai[p->index].num_build_rec = 2;
01241 _players_ai[p->index].num_loco_to_build = 3;
01242 _players_ai[p->index].num_want_fullload = 3;
01243
01244
01245 _players_ai[p->index].order_list_blocks[0] = 0;
01246 _players_ai[p->index].order_list_blocks[1] = 1;
01247 _players_ai[p->index].order_list_blocks[2] = 255;
01248
01249 _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
01250 _players_ai[p->index].state_mode = UCHAR_MAX;
01251 _players_ai[p->index].state_counter = 0;
01252 _players_ai[p->index].timeout_counter = 0;
01253 }
01254
01255 static void AiWantLongRoadPassengerRoute(Player *p)
01256 {
01257 int i;
01258 FoundRoute fr;
01259
01260 i = 60;
01261 for (;;) {
01262
01263 AiFindSubsidyPassengerRoute(&fr);
01264 if (IsInsideMM(fr.distance, 55, 180 + 1)) break;
01265
01266
01267 AiFindRandomPassengerRoute(&fr);
01268 if (IsInsideMM(fr.distance, 55, 180 + 1)) break;
01269
01270
01271 if (--i == 0) return;
01272 }
01273
01274 fr.cargo = CT_PASSENGERS;
01275
01276 if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
01277
01278
01279 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
01280 _players_ai[p->index].src.use_tile = 0;
01281 _players_ai[p->index].src.rand_rng = 10;
01282 _players_ai[p->index].src.cur_building_rule = 0xFF;
01283 _players_ai[p->index].src.buildcmd_a = 1;
01284 _players_ai[p->index].src.direction = 0;
01285 _players_ai[p->index].src.cargo = CT_PASSENGERS;
01286
01287
01288 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
01289 _players_ai[p->index].dst.use_tile = 0;
01290 _players_ai[p->index].dst.rand_rng = 10;
01291 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01292 _players_ai[p->index].dst.buildcmd_a = 0xFF;
01293 _players_ai[p->index].dst.direction = 0;
01294 _players_ai[p->index].dst.cargo = CT_PASSENGERS;
01295
01296
01297 _players_ai[p->index].cargo_type = CT_PASSENGERS;
01298 _players_ai[p->index].num_build_rec = 2;
01299 _players_ai[p->index].num_loco_to_build = 4;
01300 _players_ai[p->index].num_want_fullload = 0;
01301
01302
01303 _players_ai[p->index].order_list_blocks[0] = 0;
01304 _players_ai[p->index].order_list_blocks[1] = 1;
01305 _players_ai[p->index].order_list_blocks[2] = 255;
01306
01307 _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
01308 _players_ai[p->index].state_mode = UCHAR_MAX;
01309 _players_ai[p->index].state_counter = 0;
01310 _players_ai[p->index].timeout_counter = 0;
01311 }
01312
01313 static void AiWantPassengerRouteInsideTown(Player *p)
01314 {
01315 int i;
01316 FoundRoute fr;
01317 Town *t;
01318
01319 i = 60;
01320 for (;;) {
01321
01322 t = AiFindRandomTown();
01323 if (t != NULL && t->population >= 700) break;
01324
01325
01326 if (--i == 0) return;
01327 }
01328
01329 fr.cargo = CT_PASSENGERS;
01330 fr.from = fr.to = t;
01331
01332 if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
01333
01334
01335 _players_ai[p->index].src.spec_tile = t->xy;
01336 _players_ai[p->index].src.use_tile = 0;
01337 _players_ai[p->index].src.rand_rng = 10;
01338 _players_ai[p->index].src.cur_building_rule = 0xFF;
01339 _players_ai[p->index].src.buildcmd_a = 1;
01340 _players_ai[p->index].src.direction = 0;
01341 _players_ai[p->index].src.cargo = CT_PASSENGERS;
01342
01343
01344 _players_ai[p->index].dst.spec_tile = t->xy;
01345 _players_ai[p->index].dst.use_tile = 0;
01346 _players_ai[p->index].dst.rand_rng = 10;
01347 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01348 _players_ai[p->index].dst.buildcmd_a = 0xFF;
01349 _players_ai[p->index].dst.direction = 0;
01350 _players_ai[p->index].dst.cargo = CT_PASSENGERS;
01351
01352
01353 _players_ai[p->index].cargo_type = CT_PASSENGERS;
01354 _players_ai[p->index].num_build_rec = 2;
01355 _players_ai[p->index].num_loco_to_build = 2;
01356 _players_ai[p->index].num_want_fullload = 0;
01357
01358
01359 _players_ai[p->index].order_list_blocks[0] = 0;
01360 _players_ai[p->index].order_list_blocks[1] = 1;
01361 _players_ai[p->index].order_list_blocks[2] = 255;
01362
01363 _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
01364 _players_ai[p->index].state_mode = UCHAR_MAX;
01365 _players_ai[p->index].state_counter = 0;
01366 _players_ai[p->index].timeout_counter = 0;
01367 }
01368
01369 static void AiWantRoadRoute(Player *p)
01370 {
01371 uint16 r = GB(Random(), 0, 16);
01372
01373 if (r > 0x4000) {
01374 AiWantLongRoadIndustryRoute(p);
01375 } else if (r > 0x2000) {
01376 AiWantMediumRoadIndustryRoute(p);
01377 } else if (r > 0x1000) {
01378 AiWantLongRoadPassengerRoute(p);
01379 } else {
01380 AiWantPassengerRouteInsideTown(p);
01381 }
01382 }
01383
01384 static void AiWantPassengerAircraftRoute(Player *p)
01385 {
01386 FoundRoute fr;
01387 int i;
01388
01389
01390
01391
01392 EngineID veh = AiChooseAircraftToBuild(p->player_money, _players_ai[p->index].build_kind != 0 ? AIR_CTOL : 0);
01393
01394
01395 if (veh == INVALID_ENGINE) return;
01396
01397 const AircraftVehicleInfo *avi = AircraftVehInfo(veh);
01398
01399
01400
01401
01402
01403
01404
01405
01406 int max_squares = avi->max_speed * 448 / 100;
01407
01408
01409
01410
01411
01412
01413 int map_size = max(MapSizeX(), MapSizeY());
01414
01415
01416
01417
01418
01419
01420
01421 int min_squares = max(20, max(max_squares / 100, min(max_squares / 5, map_size / 2)));
01422
01423
01424
01425
01426 if (max_squares < min_squares) return;
01427
01428 i = 60;
01429 for (;;) {
01430
01431
01432 AiFindSubsidyPassengerRoute(&fr);
01433 if (IsInsideMM(fr.distance, min_squares, max_squares + 1)) break;
01434
01435
01436 AiFindRandomPassengerRoute(&fr);
01437 if (IsInsideMM(fr.distance, min_squares, max_squares + 1)) break;
01438
01439
01440 if (--i == 0) return;
01441 }
01442
01443 fr.cargo = CT_PASSENGERS;
01444 if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
01445
01446
01447
01448 _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
01449 _players_ai[p->index].src.use_tile = 0;
01450 _players_ai[p->index].src.rand_rng = 12;
01451 _players_ai[p->index].src.cur_building_rule = 0xFF;
01452 _players_ai[p->index].src.cargo = fr.cargo;
01453
01454
01455 _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
01456 _players_ai[p->index].dst.use_tile = 0;
01457 _players_ai[p->index].dst.rand_rng = 12;
01458 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01459 _players_ai[p->index].dst.cargo = fr.cargo;
01460
01461
01462 _players_ai[p->index].cargo_type = fr.cargo;
01463 _players_ai[p->index].build_kind = 0;
01464 _players_ai[p->index].num_build_rec = 2;
01465 _players_ai[p->index].num_loco_to_build = 1;
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478 _players_ai[p->index].num_want_fullload = Chance16(1, 5);
01479
01480 _players_ai[p->index].order_list_blocks[0] = 0;
01481 _players_ai[p->index].order_list_blocks[1] = 1;
01482 _players_ai[p->index].order_list_blocks[2] = 255;
01483
01484 _players_ai[p->index].state = AIS_AIRPORT_STUFF;
01485 _players_ai[p->index].timeout_counter = 0;
01486 }
01487
01488 static void AiWantOilRigAircraftRoute(Player *p)
01489 {
01490 int i;
01491 FoundRoute fr;
01492 Town *t;
01493 Industry *in;
01494
01495 i = 60;
01496 for (;;) {
01497
01498 t = AiFindRandomTown();
01499 if (t != NULL) {
01500
01501 in = AiFindRandomIndustry();
01502 if (in != NULL && GetIndustrySpec(in->type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) {
01503 if (DistanceManhattan(t->xy, in->xy) < 60)
01504 break;
01505 }
01506 }
01507
01508
01509 if (--i == 0) return;
01510 }
01511
01512 fr.cargo = CT_PASSENGERS;
01513 fr.from = fr.to = t;
01514
01515 if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
01516
01517
01518 _players_ai[p->index].src.spec_tile = t->xy;
01519 _players_ai[p->index].src.use_tile = 0;
01520 _players_ai[p->index].src.rand_rng = 12;
01521 _players_ai[p->index].src.cur_building_rule = 0xFF;
01522 _players_ai[p->index].src.cargo = CT_PASSENGERS;
01523
01524
01525 _players_ai[p->index].dst.spec_tile = in->xy;
01526 _players_ai[p->index].dst.use_tile = 0;
01527 _players_ai[p->index].dst.rand_rng = 5;
01528 _players_ai[p->index].dst.cur_building_rule = 0xFF;
01529 _players_ai[p->index].dst.cargo = CT_PASSENGERS;
01530
01531
01532 _players_ai[p->index].cargo_type = CT_PASSENGERS;
01533 _players_ai[p->index].build_kind = 1;
01534 _players_ai[p->index].num_build_rec = 2;
01535 _players_ai[p->index].num_loco_to_build = 1;
01536 _players_ai[p->index].num_want_fullload = 0;
01537
01538 _players_ai[p->index].order_list_blocks[0] = 0;
01539 _players_ai[p->index].order_list_blocks[1] = 1;
01540 _players_ai[p->index].order_list_blocks[2] = 255;
01541
01542 _players_ai[p->index].state = AIS_AIRPORT_STUFF;
01543 _players_ai[p->index].timeout_counter = 0;
01544 }
01545
01546 static void AiWantAircraftRoute(Player *p)
01547 {
01548 uint16 r = (uint16)Random();
01549
01550 if (r >= 0x2AAA || _date < 0x3912 + DAYS_TILL_ORIGINAL_BASE_YEAR) {
01551 AiWantPassengerAircraftRoute(p);
01552 } else {
01553 AiWantOilRigAircraftRoute(p);
01554 }
01555 }
01556
01557
01558
01559 static void AiStateWantNewRoute(Player *p)
01560 {
01561 uint16 r;
01562 int i;
01563
01564 if (p->player_money < AiGetBasePrice(p) * 500) {
01565 _players_ai[p->index].state = AIS_0;
01566 return;
01567 }
01568
01569 i = 200;
01570 for (;;) {
01571 r = (uint16)Random();
01572
01573 if (_patches.ai_disable_veh_train &&
01574 _patches.ai_disable_veh_roadveh &&
01575 _patches.ai_disable_veh_aircraft &&
01576 _patches.ai_disable_veh_ship) {
01577 return;
01578 }
01579
01580 if (r < 0x7626) {
01581 if (_patches.ai_disable_veh_train) continue;
01582 AiWantTrainRoute(p);
01583 } else if (r < 0xC4EA) {
01584 if (_patches.ai_disable_veh_roadveh) continue;
01585 AiWantRoadRoute(p);
01586 } else if (r < 0xD89B) {
01587 if (_patches.ai_disable_veh_aircraft) continue;
01588 AiWantAircraftRoute(p);
01589 } else {
01590
01591 }
01592
01593
01594 if (_players_ai[p->index].state != AIS_WANT_NEW_ROUTE) break;
01595
01596
01597 if (--i == 0) {
01598 if (++_players_ai[p->index].state_counter == 556) _players_ai[p->index].state = AIS_0;
01599 break;
01600 }
01601 }
01602 }
01603
01604 static bool AiCheckTrackResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
01605 {
01606 uint rad = (_patches.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED;
01607
01608 for (; p->mode != 4; p++) {
01609 AcceptedCargo values;
01610 TileIndex tile2;
01611 uint w;
01612 uint h;
01613
01614 if (p->mode != 1) continue;
01615
01616 tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
01617 w = GB(p->attr, 1, 3);
01618 h = GB(p->attr, 4, 3);
01619
01620 if (p->attr & 1) Swap(w, h);
01621
01622 if (cargo & 0x80) {
01623 GetProductionAroundTiles(values, tile2, w, h, rad);
01624 return values[cargo & 0x7F] != 0;
01625 } else {
01626 GetAcceptanceAroundTiles(values, tile2, w, h, rad);
01627 if (!(values[cargo] & ~7))
01628 return false;
01629 if (cargo != CT_MAIL)
01630 return true;
01631 return !!((values[cargo] >> 1) & ~7);
01632 }
01633 }
01634
01635 return true;
01636 }
01637
01638 static CommandCost AiDoBuildDefaultRailTrack(TileIndex tile, const AiDefaultBlockData* p, RailType railtype, byte flag)
01639 {
01640 CommandCost ret;
01641 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01642 Town *t = NULL;
01643 int rating = 0;
01644 int i, j, k;
01645
01646 for (;;) {
01647
01648 uint c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
01649
01650 _cleared_town = NULL;
01651
01652 if (p->mode < 2) {
01653 if (p->mode == 0) {
01654
01655 ret = DoCommand(c, railtype, p->attr, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_TRAIN_DEPOT);
01656 } else {
01657
01658 ret = DoCommand(c, (p->attr & 1) | (p->attr >> 4) << 8 | (p->attr >> 1 & 7) << 16, railtype, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_RAILROAD_STATION);
01659 }
01660
01661 if (CmdFailed(ret)) return CMD_ERROR;
01662 total_cost.AddCost(ret);
01663
01664 clear_town_stuff:;
01665 if (_cleared_town != NULL) {
01666 if (t != NULL && t != _cleared_town)
01667 return CMD_ERROR;
01668 t = _cleared_town;
01669 rating += _cleared_town_rating;
01670 }
01671 } else if (p->mode == 2) {
01672
01673 if (IsTileType(c, MP_RAILWAY)) return CMD_ERROR;
01674
01675 j = p->attr;
01676 k = 0;
01677
01678
01679
01680
01681 for (i = 0; i != 6; i++, j >>= 1) {
01682 if (j & 1) {
01683 k = i;
01684 ret = DoCommand(c, railtype, i, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
01685 if (CmdFailed(ret)) return CMD_ERROR;
01686 total_cost.AddCost(ret);
01687 }
01688 }
01689
01690
01691 if (j & 3) {
01692
01693 if (IsTileType(c, MP_ROAD)) return CMD_ERROR;
01694
01695 if (flag & DC_EXEC) {
01696 j = 4 - j;
01697 do {
01698 ret = DoCommand(c, k, 0, flag, CMD_BUILD_SIGNALS);
01699 } while (--j);
01700 } else {
01701 ret.AddCost(_price.build_signals);
01702 }
01703 if (CmdFailed(ret)) return CMD_ERROR;
01704 total_cost.AddCost(ret);
01705 }
01706 } else if (p->mode == 3) {
01707
01708 if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
01709 ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
01710 if (CmdFailed(ret)) return CMD_ERROR;
01711 total_cost.AddCost(ret);
01712 total_cost.AddCost(_price.build_rail);
01713
01714 if (flag & DC_EXEC) {
01715 DoCommand(c, railtype, p->attr & 1, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_SINGLE_RAIL);
01716 }
01717
01718 goto clear_town_stuff;
01719 } else {
01720
01721 break;
01722 }
01723
01724 p++;
01725 }
01726
01727 if (!(flag & DC_EXEC)) {
01728 if (t != NULL && rating > t->ratings[_current_player]) {
01729 return CMD_ERROR;
01730 }
01731 }
01732
01733 return total_cost;
01734 }
01735
01736
01737 static int AiBuildDefaultRailTrack(TileIndex tile, byte p0, byte p1, byte p2, byte p3, byte dir, byte cargo, RailType railtype, CommandCost* cost)
01738 {
01739 int i;
01740 const AiDefaultRailBlock *p;
01741
01742 for (i = 0; (p = _default_rail_track_data[i]) != NULL; i++) {
01743 if (p->p0 == p0 && p->p1 == p1 && p->p2 == p2 && p->p3 == p3 &&
01744 (p->dir == 0xFF || p->dir == dir || ((p->dir - 1) & 3) == dir)) {
01745 *cost = AiDoBuildDefaultRailTrack(tile, p->data, railtype, DC_NO_TOWN_RATING);
01746 if (CmdSucceeded(*cost) && AiCheckTrackResources(tile, p->data, cargo))
01747 return i;
01748 }
01749 }
01750
01751 return -1;
01752 }
01753
01754 static const byte _terraform_up_flags[] = {
01755 14, 13, 12, 11,
01756 10, 9, 8, 7,
01757 6, 5, 4, 3,
01758 2, 1, 0, 1,
01759 2, 1, 4, 1,
01760 2, 1, 8, 1,
01761 2, 1, 4, 2,
01762 2, 1
01763 };
01764
01765 static const byte _terraform_down_flags[] = {
01766 1, 2, 3, 4,
01767 5, 6, 1, 8,
01768 9, 10, 8, 12,
01769 4, 2, 0, 0,
01770 1, 2, 3, 4,
01771 5, 6, 2, 8,
01772 9, 10, 1, 12,
01773 8, 4
01774 };
01775
01776 static void AiDoTerraformLand(TileIndex tile, DiagDirection dir, int unk, int mode)
01777 {
01778 PlayerID old_player;
01779 uint32 r;
01780 Slope slope;
01781 uint h;
01782
01783 old_player = _current_player;
01784 _current_player = OWNER_NONE;
01785
01786 r = Random();
01787
01788 unk &= (int)r;
01789
01790 do {
01791 tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
01792
01793 r >>= 2;
01794 if (r & 2) {
01795 dir = ChangeDiagDir(dir, (r & 1) ? DIAGDIRDIFF_90LEFT : DIAGDIRDIFF_90RIGHT);
01796 }
01797 } while (--unk >= 0);
01798
01799 slope = GetTileSlope(tile, &h);
01800
01801 if (slope != SLOPE_FLAT) {
01802 if (mode > 0 || (mode == 0 && !(r & 0xC))) {
01803
01804 DoCommand(tile, _terraform_up_flags[slope - 1], 1,
01805 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
01806 } else if (h != 0) {
01807
01808 DoCommand(tile, _terraform_down_flags[slope - 1], 0,
01809 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
01810 }
01811 }
01812
01813 _current_player = old_player;
01814 }
01815
01816 static void AiStateBuildDefaultRailBlocks(Player *p)
01817 {
01818 uint i;
01819 int j;
01820 AiBuildRec *aib;
01821 int rule;
01822 CommandCost cost;
01823
01824
01825 if (++_players_ai[p->index].timeout_counter == 1388) {
01826 _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS;
01827 return;
01828 }
01829
01830
01831 for (i = 0; i < 8; i++) {
01832
01833 aib = &_players_ai[p->index].src;
01834 j = _players_ai[p->index].num_build_rec;
01835 do {
01836
01837 if (aib->cur_building_rule != 255) continue;
01838
01839
01840
01841 aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
01842
01843
01844 rule = AiBuildDefaultRailTrack(aib->use_tile,
01845 _players_ai[p->index].build_kind, _players_ai[p->index].num_wagons,
01846 aib->unk6, aib->unk7,
01847 aib->direction, aib->cargo,
01848 _players_ai[p->index].railtype_to_use,
01849 &cost
01850 );
01851
01852 if (rule == -1) {
01853
01854 if (_players_ai[p->index].state_counter >= 600) {
01855 AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode);
01856 }
01857
01858 if (++_players_ai[p->index].state_counter >= 1000) {
01859 _players_ai[p->index].state_counter = 0;
01860 _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode;
01861 }
01862 } else if (CheckPlayerHasMoney(cost)) {
01863
01864 aib->cur_building_rule = rule;
01865
01866 AiDoBuildDefaultRailTrack(
01867 aib->use_tile,
01868 _default_rail_track_data[rule]->data,
01869 _players_ai[p->index].railtype_to_use,
01870 DC_EXEC | DC_NO_TOWN_RATING
01871 );
01872 }
01873 } while (++aib, --j);
01874 }
01875
01876
01877 aib = &_players_ai[p->index].src;
01878 j = _players_ai[p->index].num_build_rec;
01879 do {
01880 if (aib->cur_building_rule == 255) return;
01881 } while (++aib, --j);
01882
01883
01884 _players_ai[p->index].state = AIS_BUILD_RAIL;
01885 _players_ai[p->index].state_mode = 255;
01886 }
01887
01888 static TileIndex AiGetEdgeOfDefaultRailBlock(byte rule, TileIndex tile, byte cmd, DiagDirection *dir)
01889 {
01890 const AiDefaultBlockData *p = _default_rail_track_data[rule]->data;
01891
01892 while (p->mode != 3 || !((--cmd) & 0x80)) p++;
01893
01894 return tile + ToTileIndexDiff(p->tileoffs) - TileOffsByDiagDir(*dir = p->attr);
01895 }
01896
01897 struct AiRailPathFindData {
01898 TileIndex tile;
01899 TileIndex tile2;
01900 int count;
01901 bool flag;
01902 };
01903
01904 static bool AiEnumFollowTrack(TileIndex tile, AiRailPathFindData *a, int track, uint length)
01905 {
01906 if (a->flag) return true;
01907
01908 if (length > 20 || tile == a->tile) {
01909 a->flag = true;
01910 return true;
01911 }
01912
01913 if (DistanceMax(tile, a->tile2) < 4) a->count++;
01914
01915 return false;
01916 }
01917
01918 static bool AiDoFollowTrack(const Player* p)
01919 {
01920 AiRailPathFindData arpfd;
01921
01922 arpfd.tile = _players_ai[p->index].start_tile_a;
01923 arpfd.tile2 = _players_ai[p->index].cur_tile_a;
01924 arpfd.flag = false;
01925 arpfd.count = 0;
01926 FollowTrack(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a), TRANSPORT_RAIL, 0, ReverseDiagDir(_players_ai[p->index].cur_dir_a),
01927 (TPFEnumProc*)AiEnumFollowTrack, NULL, &arpfd);
01928 return arpfd.count > 8;
01929 }
01930
01931 struct AiRailFinder {
01932 TileIndex final_tile;
01933 DiagDirection final_dir;
01934 byte depth;
01935 byte recursive_mode;
01936 DiagDirection cur_best_dir;
01937 DiagDirection best_dir;
01938 byte cur_best_depth;
01939 byte best_depth;
01940 uint cur_best_dist;
01941 const byte *best_ptr;
01942 uint best_dist;
01943 TileIndex cur_best_tile, best_tile;
01944 TileIndex bridge_end_tile;
01945 Player *player;
01946 };
01947
01948 static const byte _ai_table_15[4][8] = {
01949 {0, 0, 4, 3, 3, 1, 128 + 0, 64},
01950 {1, 1, 2, 0, 4, 2, 128 + 1, 65},
01951 {0, 2, 2, 3, 5, 1, 128 + 2, 66},
01952 {1, 3, 5, 0, 3, 2, 128 + 3, 67}
01953 };
01954
01955 static const byte _dir_table_1[] = { 3, 9, 12, 6};
01956 static const byte _dir_table_2[] = {12, 6, 3, 9};
01957
01958
01959 static bool AiIsTileBanned(const Player* p, TileIndex tile, byte val)
01960 {
01961 int i;
01962
01963 for (i = 0; i != _players_ai[p->index].banned_tile_count; i++) {
01964 if (_players_ai[p->index].banned_tiles[i] == tile && _players_ai[p->index].banned_val[i] == val) {
01965 return true;
01966 }
01967 }
01968 return false;
01969 }
01970
01971 static void AiBanTile(Player* p, TileIndex tile, byte val)
01972 {
01973 uint i;
01974
01975 for (i = lengthof(_players_ai[p->index].banned_tiles) - 1; i != 0; i--) {
01976 _players_ai[p->index].banned_tiles[i] = _players_ai[p->index].banned_tiles[i - 1];
01977 _players_ai[p->index].banned_val[i] = _players_ai[p->index].banned_val[i - 1];
01978 }
01979
01980 _players_ai[p->index].banned_tiles[0] = tile;
01981 _players_ai[p->index].banned_val[0] = val;
01982
01983 if (_players_ai[p->index].banned_tile_count != lengthof(_players_ai[p->index].banned_tiles)) {
01984 _players_ai[p->index].banned_tile_count++;
01985 }
01986 }
01987
01988 static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, DiagDirection dir);
01989
01990 static bool AiCheckRailPathBetter(AiRailFinder *arf, const byte *p)
01991 {
01992 bool better = false;
01993
01994 if (arf->recursive_mode < 1) {
01995
01996
01997 if (arf->cur_best_dist < arf->best_dist) {
01998 arf->best_dir = arf->cur_best_dir;
01999 arf->best_dist = arf->cur_best_dist;
02000 arf->best_ptr = p;
02001 arf->best_tile = arf->cur_best_tile;
02002 better = true;
02003 }
02004 } else if (arf->recursive_mode > 1) {
02005
02006 if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
02007 arf->best_depth = arf->cur_best_depth;
02008 arf->best_dist = 0;
02009 arf->best_ptr = p;
02010 arf->best_tile = 0;
02011 better = true;
02012 }
02013 }
02014 arf->recursive_mode = 0;
02015 arf->cur_best_dist = UINT_MAX;
02016 arf->cur_best_depth = 0xff;
02017
02018 return better;
02019 }
02020
02021 static inline void AiCheckBuildRailBridgeHere(AiRailFinder *arf, TileIndex tile, const byte *p)
02022 {
02023 Slope tileh;
02024 uint z;
02025 bool flag;
02026
02027 DiagDirection dir2 = (DiagDirection)(p[0] & 3);
02028
02029 tileh = GetTileSlope(tile, &z);
02030 if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
02031 TileIndex tile_new = tile;
02032
02033
02034 flag = z == 0;
02035 for (;;) {
02036 TileType type;
02037
02038 if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return;
02039 tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
02040 type = GetTileType(tile_new);
02041
02042 if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile_new, NULL) != SLOPE_FLAT) {
02043 if (!flag) return;
02044 break;
02045 }
02046 if (type != MP_WATER && type != MP_RAILWAY && type != MP_ROAD) return;
02047 flag = true;
02048 }
02049
02050
02051 if (CmdFailed(DoCommand(tile_new, tile, 0 | _players_ai[arf->player->index].railtype_to_use << 8, DC_AUTO, CMD_BUILD_BRIDGE))) {
02052 return;
02053 }
02054 AiBuildRailRecursive(arf, tile_new, dir2);
02055
02056
02057 if (arf->depth == 1) {
02058 if (AiCheckRailPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
02059 }
02060 }
02061 }
02062
02063 static inline void AiCheckBuildRailTunnelHere(AiRailFinder *arf, TileIndex tile, const byte *p)
02064 {
02065 uint z;
02066
02067 if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
02068 CommandCost cost = DoCommand(tile, _players_ai[arf->player->index].railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL);
02069
02070 if (CmdSucceeded(cost) && cost.GetCost() <= (arf->player->player_money >> 4)) {
02071 AiBuildRailRecursive(arf, _build_tunnel_endtile, (DiagDirection)(p[0] & 3));
02072 if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
02073 }
02074 }
02075 }
02076
02077
02078 static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, DiagDirection dir)
02079 {
02080 const byte *p;
02081
02082 tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
02083
02084
02085 if (tile == arf->final_tile) {
02086 if (arf->final_dir != ReverseDiagDir(dir)) {
02087 if (arf->recursive_mode != 2) arf->recursive_mode = 1;
02088 } else if (arf->recursive_mode != 2) {
02089 arf->recursive_mode = 2;
02090 arf->cur_best_depth = arf->depth;
02091 } else {
02092 if (arf->depth < arf->cur_best_depth) arf->cur_best_depth = arf->depth;
02093 }
02094 return;
02095 }
02096
02097
02098 if (arf->depth >= 4) {
02099 uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
02100
02101 if (dist < arf->cur_best_dist) {
02102
02103 arf->cur_best_depth = arf->depth;
02104 arf->cur_best_dist = dist;
02105 arf->cur_best_tile = tile;
02106 arf->cur_best_dir = dir;
02107 }
02108 return;
02109 }
02110
02111
02112 arf->depth++;
02113
02114
02115 p = _ai_table_15[dir];
02116
02117
02118 if (GetTileZ(tile) == 0) {
02119 p += 6;
02120 } else {
02121 do {
02122
02123 if (!AiIsTileBanned(arf->player, tile, p[0]) &&
02124 CmdSucceeded(DoCommand(tile, _players_ai[arf->player->index].railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) {
02125 AiBuildRailRecursive(arf, tile, (DiagDirection)p[1]);
02126 }
02127
02128
02129 if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
02130
02131 p += 2;
02132 } while (!(p[0] & 0x80));
02133 }
02134
02135 AiCheckBuildRailBridgeHere(arf, tile, p);
02136 AiCheckBuildRailTunnelHere(arf, tile, p + 1);
02137
02138 arf->depth--;
02139 }
02140
02141
02142 static const byte _dir_table_3[] = {0x25, 0x2A, 0x19, 0x16};
02143
02144 static void AiBuildRailConstruct(Player *p)
02145 {
02146 AiRailFinder arf;
02147 int i;
02148
02149
02150 if (AiDoFollowTrack(p)) {
02151 _players_ai[p->index].state_counter = (Random()&0xE)+6;
02152 _players_ai[p->index].state_mode = 1;
02153
02154
02155 AiBanTile(p, _players_ai[p->index].cur_tile_a, FindFirstBit(GetRailTrackStatus(_players_ai[p->index].cur_tile_a)));
02156 return;
02157 }
02158
02159
02160 arf.player = p;
02161 arf.final_tile = _players_ai[p->index].cur_tile_b;
02162 arf.final_dir = _players_ai[p->index].cur_dir_b;
02163 arf.depth = 0;
02164 arf.recursive_mode = 0;
02165 arf.best_ptr = NULL;
02166 arf.cur_best_dist = (uint)-1;
02167 arf.cur_best_depth = 0xff;
02168 arf.best_dist = (uint)-1;
02169 arf.best_depth = 0xff;
02170 arf.cur_best_tile = 0;
02171 arf.best_tile = 0;
02172 AiBuildRailRecursive(&arf, _players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a);
02173
02174
02175 if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
02176 _players_ai[p->index].state_mode = 255;
02177 return;
02178 }
02179
02180
02181 if (arf.best_ptr == NULL) {
02182
02183 for (i = 0; i != 5; i++) {
02184 AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0);
02185 }
02186
02187 if (++_players_ai[p->index].state_counter == 21) {
02188 _players_ai[p->index].state_counter = 40;
02189 _players_ai[p->index].state_mode = 1;
02190
02191
02192 AiBanTile(p, _players_ai[p->index].cur_tile_a, FindFirstBit(GetRailTrackStatus(_players_ai[p->index].cur_tile_a)));
02193 }
02194 return;
02195 }
02196
02197 _players_ai[p->index].cur_tile_a += TileOffsByDiagDir(_players_ai[p->index].cur_dir_a);
02198
02199 if (arf.best_ptr[0] & 0x80) {
02200 TileIndex t1 = _players_ai[p->index].cur_tile_a;
02201 TileIndex t2 = arf.bridge_end_tile;
02202
02203 int32 bridge_len = GetTunnelBridgeLength(t1, t2);
02204
02205 DiagDirection dir = (TileX(t1) == TileX(t2) ? DIAGDIR_SE : DIAGDIR_SW);
02206 Track track = AxisToTrack(DiagDirToAxis(dir));
02207
02208 if (t2 < t1) dir = ReverseDiagDir(dir);
02209
02210
02211 bool fail = false;
02212 CommandCost cost;
02213 TileIndex t = t1;
02214
02215
02216 do {
02217 cost = DoCommand(t, _players_ai[p->index].railtype_to_use, track, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
02218
02219 if (CmdFailed(cost) || IsTileType(t, MP_RAILWAY)) {
02220 fail = true;
02221 break;
02222 }
02223 t += TileOffsByDiagDir(dir);
02224 } while (t != t2);
02225
02226
02227 if (!fail) cost = DoCommand(t1, t2, _players_ai[p->index].railtype_to_use | (track << 4), DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_TRACK);
02228
02229 if (!fail && CmdSucceeded(cost) && cost.GetCost() <= p->player_money) {
02230 DoCommand(t1, t2, _players_ai[p->index].railtype_to_use | (track << 4), DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_BUILD_RAILROAD_TRACK);
02231 } else {
02232
02233
02234
02235
02236 int i;
02237 for (i = MAX_BRIDGES - 1; i != 0; i--) {
02238 if (CheckBridge_Stuff(i, bridge_len)) {
02239 CommandCost cost = DoCommand(t1, t2, i | (_players_ai[p->index].railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE);
02240 if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 1) && cost.GetCost() < ((p->player_money + _economy.max_loan - p->current_loan) >> 5)) break;
02241 }
02242 }
02243
02244
02245 DoCommand(t1, t2, i | (_players_ai[p->index].railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
02246 }
02247
02248 _players_ai[p->index].cur_tile_a = t2;
02249 _players_ai[p->index].state_counter = 0;
02250 } else if (arf.best_ptr[0] & 0x40) {
02251
02252 DoCommand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
02253 _players_ai[p->index].cur_tile_a = _build_tunnel_endtile;
02254 _players_ai[p->index].state_counter = 0;
02255 } else {
02256
02257 _players_ai[p->index].cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3);
02258 DoCommand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].railtype_to_use, arf.best_ptr[0],
02259 DC_EXEC | DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL);
02260 _players_ai[p->index].state_counter = 0;
02261 }
02262
02263 if (arf.best_tile != 0) {
02264 for (i = 0; i != 2; i++) {
02265 AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
02266 }
02267 }
02268 }
02269
02270 static bool AiRemoveTileAndGoForward(Player *p)
02271 {
02272 byte b;
02273 int bit;
02274 const byte *ptr;
02275 TileIndex tile = _players_ai[p->index].cur_tile_a;
02276 TileIndex tilenew;
02277
02278 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
02279 if (IsTunnel(tile)) {
02280
02281 if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
02282 return false;
02283 _players_ai[p->index].cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a));
02284 return true;
02285 } else {
02286
02287
02288 if (DiagDirToAxis(GetTunnelBridgeDirection(tile)) != (_players_ai[p->index].cur_dir_a & 1)) return false;
02289
02290 tile = GetOtherBridgeEnd(tile);
02291
02292 tilenew = TILE_MASK(tile - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a));
02293
02294 if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
02295 return false;
02296 _players_ai[p->index].cur_tile_a = tilenew;
02297 return true;
02298 }
02299 }
02300
02301
02302 b = GetRailTrackStatus(tile) & _dir_table_3[_players_ai[p->index].cur_dir_a];
02303 if (b == 0) return false;
02304
02305
02306 bit = FindFirstBit(b);
02307
02308
02309 if (IsTileType(tile, MP_RAILWAY) &&
02310 GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
02311 DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_SIGNALS);
02312 }
02313
02314
02315 if (CmdFailed(DoCommand(tile, 0, bit, DC_EXEC, CMD_REMOVE_SINGLE_RAIL)))
02316 return false;
02317
02318
02319 ptr = _ai_table_15[ReverseDiagDir(_players_ai[p->index].cur_dir_a)];
02320 while (ptr[0] != bit) ptr += 2;
02321 _players_ai[p->index].cur_dir_a = ReverseDiagDir((DiagDirection)ptr[1]);
02322
02323
02324 _players_ai[p->index].cur_tile_a = TILE_MASK(_players_ai[p->index].cur_tile_a - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a));
02325
02326 return true;
02327 }
02328
02329
02330 static void AiBuildRailDestruct(Player *p)
02331 {
02332
02333 if (!--_players_ai[p->index].state_counter) {
02334 _players_ai[p->index].state_mode = 2;
02335 _players_ai[p->index].state_counter = 0;
02336 }
02337
02338
02339 if (_players_ai[p->index].cur_tile_a == _players_ai[p->index].start_tile_a) return;
02340
02341 AiRemoveTileAndGoForward(p);
02342 }
02343
02344
02345 static void AiBuildRail(Player *p)
02346 {
02347 switch (_players_ai[p->index].state_mode) {
02348 case 0:
02349 AiBuildRailConstruct(p);
02350 break;
02351
02352 case 1:
02353 AiBuildRailDestruct(p);
02354 break;
02355
02356 case 2: {
02357 uint i;
02358
02359
02360 for (i = 0; i != 4; i++) {
02361 AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0);
02362 }
02363
02364 if (++_players_ai[p->index].state_counter == 4) {
02365 _players_ai[p->index].state_counter = 0;
02366 _players_ai[p->index].state_mode = 0;
02367 }
02368 }
02369
02370 default: break;
02371 }
02372 }
02373
02374 static void AiStateBuildRail(Player *p)
02375 {
02376 int num;
02377 AiBuildRec *aib;
02378 byte cmd;
02379 TileIndex tile;
02380 DiagDirection dir;
02381
02382
02383 if (++_players_ai[p->index].timeout_counter == 1388) {
02384 _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS;
02385 return;
02386 }
02387
02388
02389 if (_players_ai[p->index].state_mode != 255) {
02390 AiBuildRail(p);
02391
02392
02393 Swap(_players_ai[p->index].start_tile_a, _players_ai[p->index].start_tile_b);
02394 Swap(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_tile_b);
02395 Swap(_players_ai[p->index].start_dir_a, _players_ai[p->index].start_dir_b);
02396 Swap(_players_ai[p->index].cur_dir_a, _players_ai[p->index].cur_dir_b);
02397 return;
02398 }
02399
02400
02401 num = _players_ai[p->index].num_build_rec;
02402 aib = &_players_ai[p->index].src;
02403
02404 for (;;) {
02405 cmd = aib->buildcmd_a;
02406 aib->buildcmd_a = 255;
02407 if (cmd != 255) break;
02408
02409 cmd = aib->buildcmd_b;
02410 aib->buildcmd_b = 255;
02411 if (cmd != 255) break;
02412
02413 aib++;
02414 if (--num == 0) {
02415 _players_ai[p->index].state = AIS_BUILD_RAIL_VEH;
02416 _players_ai[p->index].state_counter = 0;
02417 return;
02418 }
02419 }
02420
02421
02422 tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, cmd & 3, &dir);
02423 _players_ai[p->index].start_tile_a = tile;
02424 _players_ai[p->index].cur_tile_a = tile;
02425 _players_ai[p->index].start_dir_a = dir;
02426 _players_ai[p->index].cur_dir_a = dir;
02427 DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir & 1) ? 1 : 0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
02428
02429 assert(TILE_MASK(tile) != 0xFF00);
02430
02431
02432 aib = (&_players_ai[p->index].src) + ((cmd >> 4) & 0xF);
02433 tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, (cmd >> 2) & 3, &dir);
02434 _players_ai[p->index].start_tile_b = tile;
02435 _players_ai[p->index].cur_tile_b = tile;
02436 _players_ai[p->index].start_dir_b = dir;
02437 _players_ai[p->index].cur_dir_b = dir;
02438 DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir & 1) ? 1 : 0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
02439
02440 assert(TILE_MASK(tile) != 0xFF00);
02441
02442
02443 _players_ai[p->index].state_mode = 2;
02444 _players_ai[p->index].state_counter = 0;
02445 _players_ai[p->index].banned_tile_count = 0;
02446 }
02447
02448 static StationID AiGetStationIdByDef(TileIndex tile, int id)
02449 {
02450 const AiDefaultBlockData *p = _default_rail_track_data[id]->data;
02451 while (p->mode != 1) p++;
02452 return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
02453 }
02454
02455 static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
02456 {
02457 EngineID best_veh_index = INVALID_ENGINE;
02458 EngineID i;
02459 uint16 best_capacity = 0;
02460 uint16 best_speed = 0;
02461 uint speed;
02462
02463 for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
02464 const RailVehicleInfo *rvi = RailVehInfo(i);
02465 const Engine* e = GetEngine(i);
02466
02467 if (!IsCompatibleRail(rvi->railtype, railtype) ||
02468 rvi->railveh_type != RAILVEH_WAGON ||
02469 !HasBit(e->player_avail, _current_player)) {
02470 continue;
02471 }
02472
02473 if (rvi->cargo_type != cargo) continue;
02474
02475
02476 speed = rvi->max_speed == 0 ? 0xFFFF : rvi->max_speed;
02477
02478 if (rvi->capacity >= best_capacity && speed >= best_speed) {
02479 best_capacity = rvi->capacity;
02480 best_speed = best_speed;
02481 best_veh_index = i;
02482 }
02483 }
02484
02485 return best_veh_index;
02486 }
02487
02488 static void AiStateBuildRailVeh(Player *p)
02489 {
02490 const AiDefaultBlockData *ptr;
02491 TileIndex tile;
02492 EngineID veh;
02493 int i;
02494 CargoID cargo;
02495 CommandCost cost;
02496 Vehicle *v;
02497 VehicleID loco_id;
02498
02499 ptr = _default_rail_track_data[_players_ai[p->index].src.cur_building_rule]->data;
02500 while (ptr->mode != 0) ptr++;
02501
02502 tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs));
02503
02504
02505 cargo = _players_ai[p->index].cargo_type;
02506 for (i = 0;;) {
02507 if (_players_ai[p->index].wagon_list[i] == INVALID_VEHICLE) {
02508 veh = AiFindBestWagon(cargo, _players_ai[p->index].railtype_to_use);
02509
02510
02511 if (veh == INVALID_ENGINE) goto handle_nocash;
02512 cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
02513 if (CmdFailed(cost)) goto handle_nocash;
02514 _players_ai[p->index].wagon_list[i] = _new_vehicle_id;
02515 _players_ai[p->index].wagon_list[i + 1] = INVALID_VEHICLE;
02516 return;
02517 }
02518 if (cargo == CT_MAIL) cargo = CT_PASSENGERS;
02519 if (++i == _players_ai[p->index].num_wagons * 2 - 1) break;
02520 }
02521
02522
02523 veh = AiChooseTrainToBuild(_players_ai[p->index].railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile);
02524 if (veh == INVALID_ENGINE) {
02525 handle_nocash:
02526
02527 if (++_players_ai[p->index].state_counter == 1000) {
02528 for (i = 0; _players_ai[p->index].wagon_list[i] != INVALID_VEHICLE; i++) {
02529 cost = DoCommand(tile, _players_ai[p->index].wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
02530 assert(CmdSucceeded(cost));
02531 }
02532 _players_ai[p->index].state = AIS_0;
02533 }
02534 return;
02535 }
02536
02537
02538 cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
02539 assert(CmdSucceeded(cost));
02540 loco_id = _new_vehicle_id;
02541
02542
02543 v = GetVehicle(loco_id);
02544 if (v->Next() != NULL) {
02545 i = _players_ai[p->index].wagon_list[_players_ai[p->index].num_wagons * 2 - 2];
02546 _players_ai[p->index].wagon_list[_players_ai[p->index].num_wagons * 2 - 2] = INVALID_VEHICLE;
02547 DoCommand(tile, i, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
02548 }
02549
02550
02551 for (i = 0; _players_ai[p->index].wagon_list[i] != INVALID_VEHICLE; i++) {
02552 DoCommand(tile, _players_ai[p->index].wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
02553 }
02554
02555 for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) {
02556 const AiBuildRec* aib = &_players_ai[p->index].src + _players_ai[p->index].order_list_blocks[i];
02557 bool is_pass = (
02558 _players_ai[p->index].cargo_type == CT_PASSENGERS ||
02559 _players_ai[p->index].cargo_type == CT_MAIL ||
02560 (_opt.landscape == LT_TEMPERATE && _players_ai[p->index].cargo_type == CT_VALUABLES)
02561 );
02562 Order order;
02563
02564 order.type = OT_GOTO_STATION;
02565 order.flags = 0;
02566 order.dest = AiGetStationIdByDef(aib->use_tile, aib->cur_building_rule);
02567
02568 if (!is_pass && i == 1) order.flags |= OFB_UNLOAD;
02569 if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0))
02570 order.flags |= OFB_FULL_LOAD;
02571
02572 DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
02573 }
02574
02575 DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_TRAIN);
02576
02577 DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
02578
02579 if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--;
02580
02581 if (--_players_ai[p->index].num_loco_to_build != 0) {
02582
02583 _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE;
02584 } else {
02585 _players_ai[p->index].state = AIS_0;
02586 }
02587 }
02588
02589 static void AiStateDeleteRailBlocks(Player *p)
02590 {
02591 const AiBuildRec* aib = &_players_ai[p->index].src;
02592 uint num = _players_ai[p->index].num_build_rec;
02593
02594 do {
02595 const AiDefaultBlockData* b;
02596
02597 if (aib->cur_building_rule == 255) continue;
02598 for (b = _default_rail_track_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
02599 DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
02600 }
02601 } while (++aib, --num);
02602
02603 _players_ai[p->index].state = AIS_0;
02604 }
02605
02606 static bool AiCheckRoadResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
02607 {
02608 uint values[NUM_CARGO];
02609 int rad;
02610
02611 if (_patches.modified_catchment) {
02612 rad = CA_TRUCK;
02613 } else {
02614 rad = 4;
02615 }
02616
02617 for (;; p++) {
02618 if (p->mode == 4) {
02619 return true;
02620 } else if (p->mode == 1) {
02621 TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
02622
02623 if (cargo & 0x80) {
02624 GetProductionAroundTiles(values, tile2, 1, 1, rad);
02625 return values[cargo & 0x7F] != 0;
02626 } else {
02627 GetAcceptanceAroundTiles(values, tile2, 1, 1, rad);
02628 return (values[cargo]&~7) != 0;
02629 }
02630 }
02631 }
02632 }
02633
02634 static bool _want_road_truck_station;
02635 static CommandCost AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag);
02636
02637
02638 static int AiFindBestDefaultRoadBlock(TileIndex tile, byte direction, byte cargo, CommandCost *cost)
02639 {
02640 int i;
02641 const AiDefaultRoadBlock *p;
02642
02643 _want_road_truck_station = (cargo & 0x7F) != CT_PASSENGERS;
02644
02645 for (i = 0; (p = _road_default_block_data[i]) != NULL; i++) {
02646 if (p->dir == direction) {
02647 *cost = AiDoBuildDefaultRoadBlock(tile, p->data, 0);
02648 if (CmdSucceeded(*cost) && AiCheckRoadResources(tile, p->data, cargo))
02649 return i;
02650 }
02651 }
02652
02653 return -1;
02654 }
02655
02656 static CommandCost AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
02657 {
02658 CommandCost ret;
02659 CommandCost total_cost(EXPENSES_CONSTRUCTION);
02660 Town *t = NULL;
02661 int rating = 0;
02662 int roadflag = 0;
02663
02664 for (;p->mode != 4;p++) {
02665 TileIndex c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
02666
02667 _cleared_town = NULL;
02668
02669 if (p->mode == 2) {
02670 if (IsNormalRoadTile(c) &&
02671 (GetRoadBits(c, ROADTYPE_ROAD) & p->attr) != 0) {
02672 roadflag |= 2;
02673
02674
02675 if ((GetRoadBits(c, ROADTYPE_ROAD) & p->attr) == p->attr) continue;
02676 }
02677
02678 ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
02679 if (CmdFailed(ret)) return CMD_ERROR;
02680 total_cost.AddCost(ret);
02681
02682 continue;
02683 }
02684
02685 if (p->mode == 0) {
02686
02687 ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_DEPOT);
02688 goto clear_town_stuff;
02689 } else if (p->mode == 1) {
02690 if (_want_road_truck_station) {
02691
02692 ret = DoCommand(c, p->attr, ROADTYPES_ROAD << 2 | RoadStop::TRUCK, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
02693 } else {
02694
02695 ret = DoCommand(c, p->attr, ROADTYPES_ROAD << 2 | RoadStop::BUS, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
02696 }
02697 clear_town_stuff:;
02698
02699 if (CmdFailed(ret)) return CMD_ERROR;
02700 total_cost.AddCost(ret);
02701
02702 if (_cleared_town != NULL) {
02703 if (t != NULL && t != _cleared_town) return CMD_ERROR;
02704 t = _cleared_town;
02705 rating += _cleared_town_rating;
02706 }
02707 } else if (p->mode == 3) {
02708 if (flag & DC_EXEC) continue;
02709
02710 if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
02711
02712 if (!IsNormalRoadTile(c)) {
02713 ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
02714 if (CmdFailed(ret)) return CMD_ERROR;
02715 }
02716
02717 }
02718 }
02719
02720 if (!_want_road_truck_station && !(roadflag & 2)) return CMD_ERROR;
02721
02722 if (!(flag & DC_EXEC)) {
02723 if (t != NULL && rating > t->ratings[_current_player]) return CMD_ERROR;
02724 }
02725 return total_cost;
02726 }
02727
02728
02729 static bool AiCheckBlockDistances(Player *p, TileIndex tile)
02730 {
02731 const AiBuildRec* aib = &_players_ai[p->index].src;
02732 uint num = _players_ai[p->index].num_build_rec;
02733
02734 do {
02735 if (aib->cur_building_rule != 255) {
02736 if (DistanceManhattan(aib->use_tile, tile) < 9) return false;
02737 }
02738 } while (++aib, --num);
02739
02740 return true;
02741 }
02742
02743
02744 static void AiStateBuildDefaultRoadBlocks(Player *p)
02745 {
02746 uint i;
02747 int j;
02748 AiBuildRec *aib;
02749 int rule;
02750 CommandCost cost;
02751
02752
02753 if (++_players_ai[p->index].timeout_counter == 1388) {
02754 _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS;
02755 return;
02756 }
02757
02758
02759 for (i = 0; i != 8; i++) {
02760
02761 aib = &_players_ai[p->index].src;
02762 j = _players_ai[p->index].num_build_rec;
02763 do {
02764
02765 if (aib->cur_building_rule != 255) continue;
02766
02767
02768
02769 aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
02770
02771
02772 rule = AiFindBestDefaultRoadBlock(
02773 aib->use_tile, aib->direction, aib->cargo, &cost
02774 );
02775
02776 if (rule == -1) {
02777
02778 if (_players_ai[p->index].state_counter >= 600) {
02779 AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode);
02780 }
02781
02782 if (++_players_ai[p->index].state_counter >= 1000) {
02783 _players_ai[p->index].state_counter = 0;
02784 _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode;
02785 }
02786 } else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) {
02787 CommandCost r;
02788
02789
02790 aib->cur_building_rule = rule;
02791
02792 r = AiDoBuildDefaultRoadBlock(
02793 aib->use_tile,
02794 _road_default_block_data[rule]->data,
02795 DC_EXEC | DC_NO_TOWN_RATING
02796 );
02797 assert(CmdSucceeded(r));
02798 }
02799 } while (++aib, --j);
02800 }
02801
02802
02803 aib = &_players_ai[p->index].src;
02804 j = _players_ai[p->index].num_build_rec;
02805 do {
02806 if (aib->cur_building_rule == 255) return;
02807 } while (++aib, --j);
02808
02809
02810 _players_ai[p->index].state = AIS_BUILD_ROAD;
02811 _players_ai[p->index].state_mode = 255;
02812 }
02813
02814 struct AiRoadFinder {
02815 TileIndex final_tile;
02816 DiagDirection final_dir;
02817 byte depth;
02818 byte recursive_mode;
02819 DiagDirection cur_best_dir;
02820 DiagDirection best_dir;
02821 byte cur_best_depth;
02822 byte best_depth;
02823 uint cur_best_dist;
02824 const byte *best_ptr;
02825 uint best_dist;
02826 TileIndex cur_best_tile, best_tile;
02827 TileIndex bridge_end_tile;
02828 Player *player;
02829 };
02830
02831 struct AiRoadEnum {
02832 TileIndex dest;
02833 TileIndex best_tile;
02834 int best_track;
02835 uint best_dist;
02836 };
02837
02838 static const DiagDirection _dir_by_track[] = {
02839 DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE,
02840 DIAGDIR_NE, DIAGDIR_NE,
02841 DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE,
02842 };
02843
02844 static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, DiagDirection dir);
02845
02846 static bool AiCheckRoadPathBetter(AiRoadFinder *arf, const byte *p)
02847 {
02848 bool better = false;
02849
02850 if (arf->recursive_mode < 1) {
02851
02852
02853 if (arf->cur_best_dist < arf->best_dist ||
02854 (arf->cur_best_dist == arf->best_dist && arf->cur_best_depth < arf->best_depth)) {
02855 arf->best_depth = arf->cur_best_depth;
02856 arf->best_dist = arf->cur_best_dist;
02857 arf->best_dir = arf->cur_best_dir;
02858 arf->best_ptr = p;
02859 arf->best_tile = arf->cur_best_tile;
02860 better = true;
02861 }
02862 } else if (arf->recursive_mode > 1) {
02863
02864 if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
02865 arf->best_depth = arf->cur_best_depth;
02866 arf->best_dist = 0;
02867 arf->best_ptr = p;
02868 arf->best_tile = 0;
02869 better = true;
02870 }
02871 }
02872 arf->recursive_mode = 0;
02873 arf->cur_best_dist = (uint)-1;
02874 arf->cur_best_depth = 0xff;
02875
02876 return better;
02877 }
02878
02879
02880 static bool AiEnumFollowRoad(TileIndex tile, AiRoadEnum *a, int track, uint length)
02881 {
02882 uint dist = DistanceManhattan(tile, a->dest);
02883
02884 if (dist <= a->best_dist) {
02885 TileIndex tile2 = TILE_MASK(tile + TileOffsByDiagDir(_dir_by_track[track]));
02886
02887 if (IsNormalRoadTile(tile2)) {
02888 a->best_dist = dist;
02889 a->best_tile = tile;
02890 a->best_track = track;
02891 }
02892 }
02893
02894 return false;
02895 }
02896
02897 static const uint16 _ai_road_table_and[4] = {
02898 0x1009,
02899 0x16,
02900 0x520,
02901 0x2A00,
02902 };
02903
02904 static bool AiCheckRoadFinished(Player *p)
02905 {
02906 AiRoadEnum are;
02907 TileIndex tile;
02908 DiagDirection dir = _players_ai[p->index].cur_dir_a;
02909 uint32 bits;
02910
02911 are.dest = _players_ai[p->index].cur_tile_b;
02912 tile = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(dir));
02913
02914 if (IsRoadStopTile(tile) || IsTileDepotType(tile, TRANSPORT_ROAD)) return false;
02915 bits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, ROADTYPES_ROAD)) & _ai_road_table_and[dir];
02916 if (bits == 0) return false;
02917
02918 are.best_dist = (uint)-1;
02919
02920 uint i;
02921 FOR_EACH_SET_BIT(i, bits) {
02922 FollowTrack(tile, 0x1000 | TRANSPORT_ROAD, ROADTYPES_ROAD, (DiagDirection)_dir_by_track[i], (TPFEnumProc*)AiEnumFollowRoad, NULL, &are);
02923 }
02924
02925 if (DistanceManhattan(tile, are.dest) <= are.best_dist) return false;
02926
02927 if (are.best_dist == 0) return true;
02928
02929 _players_ai[p->index].cur_tile_a = are.best_tile;
02930 _players_ai[p->index].cur_dir_a = _dir_by_track[are.best_track];
02931 return false;
02932 }
02933
02934
02935 static bool AiBuildRoadHelper(TileIndex tile, int flags, int type)
02936 {
02937 static const RoadBits _road_bits[] = {
02938 ROAD_X,
02939 ROAD_Y,
02940 ROAD_NW | ROAD_NE,
02941 ROAD_SW | ROAD_SE,
02942 ROAD_NW | ROAD_SW,
02943 ROAD_SE | ROAD_NE
02944 };
02945 return CmdSucceeded(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
02946 }
02947
02948 static inline void AiCheckBuildRoadBridgeHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
02949 {
02950 Slope tileh;
02951 uint z;
02952 bool flag;
02953
02954 DiagDirection dir2 = (DiagDirection)(p[0] & 3);
02955
02956 tileh = GetTileSlope(tile, &z);
02957 if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
02958 TileIndex tile_new = tile;
02959
02960
02961 flag = z == 0;
02962 for (;;) {
02963 TileType type;
02964
02965 if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return;
02966 tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
02967 type = GetTileType(tile_new);
02968
02969 if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile_new, NULL) != SLOPE_FLAT) {
02970
02971
02972 if (!flag) return;
02973 break;
02974 }
02975 if (type != MP_WATER && type != MP_RAILWAY && type != MP_ROAD) return;
02976 flag = true;
02977 }
02978
02979
02980 if (CmdFailed(DoCommand(tile_new, tile, ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE)))
02981 return;
02982 AiBuildRoadRecursive(arf, tile_new, dir2);
02983
02984
02985 if (arf->depth == 1) {
02986 if (AiCheckRoadPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
02987 }
02988 }
02989 }
02990
02991 static inline void AiCheckBuildRoadTunnelHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
02992 {
02993 uint z;
02994
02995 if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
02996 CommandCost cost = DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
02997
02998 if (CmdSucceeded(cost) && cost.GetCost() <= (arf->player->player_money >> 4)) {
02999 AiBuildRoadRecursive(arf, _build_tunnel_endtile, (DiagDirection)(p[0] & 3));
03000 if (arf->depth == 1) AiCheckRoadPathBetter(arf, p);
03001 }
03002 }
03003 }
03004
03005
03006
03007 static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, DiagDirection dir)
03008 {
03009 const byte *p;
03010
03011 tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
03012
03013
03014 if (tile == arf->final_tile) {
03015 if (ReverseDiagDir(arf->final_dir) == dir) {
03016 arf->recursive_mode = 2;
03017 arf->cur_best_depth = arf->depth;
03018 }
03019 return;
03020 }
03021
03022
03023 if (arf->depth >= 4) {
03024 uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
03025 if (dist < arf->cur_best_dist) {
03026
03027 arf->cur_best_dist = dist;
03028 arf->cur_best_tile = tile;
03029 arf->cur_best_dir = dir;
03030 arf->cur_best_depth = arf->depth;
03031 }
03032 return;
03033 }
03034
03035
03036 arf->depth++;
03037
03038
03039 p = _ai_table_15[dir];
03040
03041
03042 if (GetTileZ(tile) == 0) {
03043 p += 6;
03044 } else {
03045 do {
03046
03047 if (AiBuildRoadHelper(tile, DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, p[0])) {
03048 AiBuildRoadRecursive(arf, tile, (DiagDirection)p[1]);
03049 }
03050
03051
03052 if (arf->depth == 1) AiCheckRoadPathBetter(arf, p);
03053
03054 p += 2;
03055 } while (!(p[0] & 0x80));
03056 }
03057
03058 AiCheckBuildRoadBridgeHere(arf, tile, p);
03059 AiCheckBuildRoadTunnelHere(arf, tile, p + 1);
03060
03061 arf->depth--;
03062 }
03063
03064
03065 static void AiBuildRoadConstruct(Player *p)
03066 {
03067 AiRoadFinder arf;
03068 int i;
03069 TileIndex tile;
03070
03071
03072 if (AiCheckRoadFinished(p)) {
03073 _players_ai[p->index].state_mode = 255;
03074 return;
03075 }
03076
03077
03078 arf.player = p;
03079 arf.final_tile = _players_ai[p->index].cur_tile_b;
03080 arf.final_dir = _players_ai[p->index].cur_dir_b;
03081 arf.depth = 0;
03082 arf.recursive_mode = 0;
03083 arf.best_ptr = NULL;
03084 arf.cur_best_dist = (uint)-1;
03085 arf.cur_best_depth = 0xff;
03086 arf.best_dist = (uint)-1;
03087 arf.best_depth = 0xff;
03088 arf.cur_best_tile = 0;
03089 arf.best_tile = 0;
03090 AiBuildRoadRecursive(&arf, _players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a);
03091
03092
03093 if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
03094 _players_ai[p->index].state_mode = 255;
03095 return;
03096 }
03097
03098
03099 if (arf.best_ptr == NULL) {
03100
03101 do_some_terraform:
03102 for (i = 0; i != 5; i++)
03103 AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0);
03104
03105 if (++_players_ai[p->index].state_counter == 21) {
03106 _players_ai[p->index].state_mode = 1;
03107
03108 _players_ai[p->index].cur_tile_a = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a));
03109 _players_ai[p->index].cur_dir_a = ReverseDiagDir(_players_ai[p->index].cur_dir_a);
03110 _players_ai[p->index].state_counter = 0;
03111 }
03112 return;
03113 }
03114
03115 tile = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a));
03116
03117 if (arf.best_ptr[0] & 0x80) {
03118 TileIndex t1 = tile;
03119 TileIndex t2 = arf.bridge_end_tile;
03120
03121 int32 bridge_len = GetTunnelBridgeLength(t1, t2);
03122
03123 Axis axis = (TileX(t1) == TileX(t2) ? AXIS_Y : AXIS_X);
03124
03125
03126 CommandCost cost = DoCommand(t2, t1, (t2 < t1 ? 1 : 2) | (axis << 2) | (ROADTYPE_ROAD << 3), DC_AUTO | DC_NO_WATER, CMD_BUILD_LONG_ROAD);
03127
03128 if (CmdSucceeded(cost) && cost.GetCost() <= p->player_money) {
03129 DoCommand(t2, t1, (t2 < t1 ? 1 : 2) | (axis << 2) | (ROADTYPE_ROAD << 3), DC_AUTO | DC_EXEC | DC_NO_WATER, CMD_BUILD_LONG_ROAD);
03130 } else {
03131 int i;
03132
03133
03134
03135
03136 for (i = MAX_BRIDGES - 1; i != 0; i--) {
03137 if (CheckBridge_Stuff(i, bridge_len)) {
03138 CommandCost cost = DoCommand(t1, t2, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE);
03139 if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 1) && cost.GetCost() < ((p->player_money + _economy.max_loan - p->current_loan) >> 5)) break;
03140 }
03141 }
03142
03143
03144 DoCommand(t1, t2, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
03145 }
03146
03147 _players_ai[p->index].cur_tile_a = t2;
03148 _players_ai[p->index].state_counter = 0;
03149 } else if (arf.best_ptr[0] & 0x40) {
03150
03151 DoCommand(tile, 0x200, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
03152 _players_ai[p->index].cur_tile_a = _build_tunnel_endtile;
03153 _players_ai[p->index].state_counter = 0;
03154 } else {
03155
03156 if (!AiBuildRoadHelper(tile, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, arf.best_ptr[0]))
03157 goto do_some_terraform;
03158
03159 _players_ai[p->index].cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3);
03160 _players_ai[p->index].cur_tile_a = tile;
03161 _players_ai[p->index].state_counter = 0;
03162 }
03163
03164 if (arf.best_tile != 0) {
03165 for (i = 0; i != 2; i++)
03166 AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
03167 }
03168 }
03169
03170
03171 static void AiBuildRoad(Player *p)
03172 {
03173 if (_players_ai[p->index].state_mode < 1) {
03174
03175 AiBuildRoadConstruct(p);
03176 } else if (_players_ai[p->index].state_mode == 1) {
03177
03178 _players_ai[p->index].state_mode = 2;
03179 _players_ai[p->index].state_counter = 0;
03180 } else if (_players_ai[p->index].state_mode == 2) {
03181 uint i;
03182
03183
03184 for (i = 0; i != 4; i++) {
03185 AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0);
03186 }
03187
03188 if (++_players_ai[p->index].state_counter == 4) {
03189 _players_ai[p->index].state_counter = 0;
03190 _players_ai[p->index].state_mode = 0;
03191 }
03192 }
03193 }
03194
03195 static TileIndex AiGetRoadBlockEdge(byte rule, TileIndex tile, DiagDirection *dir)
03196 {
03197 const AiDefaultBlockData *p = _road_default_block_data[rule]->data;
03198 while (p->mode != 1) p++;
03199 *dir = p->attr;
03200 return TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
03201 }
03202
03203
03204 static void AiStateBuildRoad(Player *p)
03205 {
03206 int num;
03207 AiBuildRec *aib;
03208 byte cmd;
03209 TileIndex tile;
03210 DiagDirection dir;
03211
03212
03213 if (++_players_ai[p->index].timeout_counter == 1388) {
03214 _players_ai[p->index].state = AIS_DELETE_ROAD_BLOCKS;
03215 return;
03216 }
03217
03218
03219 if (_players_ai[p->index].state_mode != 255) {
03220 AiBuildRoad(p);
03221
03222
03223 Swap(_players_ai[p->index].start_tile_a, _players_ai[p->index].start_tile_b);
03224 Swap(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_tile_b);
03225 Swap(_players_ai[p->index].start_dir_a, _players_ai[p->index].start_dir_b);
03226 Swap(_players_ai[p->index].cur_dir_a, _players_ai[p->index].cur_dir_b);
03227
03228 return;
03229 }
03230
03231
03232 num = _players_ai[p->index].num_build_rec;
03233 aib = &_players_ai[p->index].src;
03234
03235 for (;;) {
03236 cmd = aib->buildcmd_a;
03237 aib->buildcmd_a = 255;
03238 if (cmd != 255) break;
03239
03240 aib++;
03241 if (--num == 0) {
03242 _players_ai[p->index].state = AIS_BUILD_ROAD_VEHICLES;
03243 return;
03244 }
03245 }
03246
03247
03248 tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
03249 _players_ai[p->index].start_tile_a = tile;
03250 _players_ai[p->index].cur_tile_a = tile;
03251 _players_ai[p->index].start_dir_a = dir;
03252 _players_ai[p->index].cur_dir_a = dir;
03253
03254
03255 aib = (&_players_ai[p->index].src) + (cmd & 0xF);
03256 tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
03257 _players_ai[p->index].start_tile_b = tile;
03258 _players_ai[p->index].cur_tile_b = tile;
03259 _players_ai[p->index].start_dir_b = dir;
03260 _players_ai[p->index].cur_dir_b = dir;
03261
03262
03263 _players_ai[p->index].state_mode = 2;
03264 _players_ai[p->index].state_counter = 0;
03265 _players_ai[p->index].banned_tile_count = 0;
03266 }
03267
03268 static StationID AiGetStationIdFromRoadBlock(TileIndex tile, int id)
03269 {
03270 const AiDefaultBlockData *p = _road_default_block_data[id]->data;
03271 while (p->mode != 1) p++;
03272 return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
03273 }
03274
03275 static void AiStateBuildRoadVehicles(Player *p)
03276 {
03277 const AiDefaultBlockData *ptr;
03278 TileIndex tile;
03279 VehicleID loco_id;
03280 EngineID veh;
03281 uint i;
03282
03283 ptr = _road_default_block_data[_players_ai[p->index].src.cur_building_rule]->data;
03284 for (; ptr->mode != 0; ptr++) {}
03285 tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs));
03286
03287 veh = AiChooseRoadVehToBuild(_players_ai[p->index].cargo_type, p->player_money, tile);
03288 if (veh == INVALID_ENGINE) {
03289 _players_ai[p->index].state = AIS_0;
03290 return;
03291 }
03292
03293 if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) return;
03294
03295 loco_id = _new_vehicle_id;
03296
03297 if (GetVehicle(loco_id)->cargo_type != _players_ai[p->index].cargo_type) {
03298
03299 if (CmdFailed(DoCommand(tile, loco_id, _players_ai[p->index].cargo_type, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
03300
03301 DoCommand(tile, loco_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
03302 return;
03303 }
03304 }
03305
03306 for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) {
03307 const AiBuildRec* aib = &_players_ai[p->index].src + _players_ai[p->index].order_list_blocks[i];
03308 bool is_pass = (
03309 _players_ai[p->index].cargo_type == CT_PASSENGERS ||
03310 _players_ai[p->index].cargo_type == CT_MAIL ||
03311 (_opt.landscape == LT_TEMPERATE && _players_ai[p->index].cargo_type == CT_VALUABLES)
03312 );
03313 Order order;
03314
03315 order.type = OT_GOTO_STATION;
03316 order.flags = 0;
03317 order.dest = AiGetStationIdFromRoadBlock(aib->use_tile, aib->cur_building_rule);
03318
03319 if (!is_pass && i == 1) order.flags |= OFB_UNLOAD;
03320 if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0))
03321 order.flags |= OFB_FULL_LOAD;
03322
03323 DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
03324 }
03325
03326 DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
03327 DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
03328
03329 if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--;
03330 if (--_players_ai[p->index].num_loco_to_build == 0) _players_ai[p->index].state = AIS_0;
03331 }
03332
03333 static void AiStateDeleteRoadBlocks(Player *p)
03334 {
03335 const AiBuildRec* aib = &_players_ai[p->index].src;
03336 uint num = _players_ai[p->index].num_build_rec;
03337
03338 do {
03339 const AiDefaultBlockData* b;
03340
03341 if (aib->cur_building_rule == 255) continue;
03342 for (b = _road_default_block_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
03343 if (b->mode > 1) continue;
03344 DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
03345 }
03346 } while (++aib, --num);
03347
03348 _players_ai[p->index].state = AIS_0;
03349 }
03350
03351
03352 static void AiStateAirportStuff(Player *p)
03353 {
03354 const Station* st;
03355 int i;
03356 AiBuildRec *aib;
03357 byte rule;
03358
03359
03360
03361
03362
03363
03364 i = 0;
03365 do {
03366
03367
03368
03369 aib = &_players_ai[p->index].src + i;
03370
03371 FOR_ALL_STATIONS(st) {
03372
03373 if (!(st->facilities & FACIL_AIRPORT)) continue;
03374
03375
03376 if (st->owner != OWNER_NONE && st->owner != _current_player) continue;
03377
03378 AirportFTAClass::Flags flags = st->Airport()->flags;
03379
03380
03381 if (!(flags & (_players_ai[p->index].build_kind == 1 ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES))) {
03382 continue;
03383 }
03384
03385
03386 if (DistanceMax(st->airport_tile, aib->spec_tile) > aib->rand_rng)
03387 continue;
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404 if (!(flags & AirportFTAClass::AIRPLANES)) {
03405
03406
03407
03408
03409
03410
03411 rule = 1;
03412 } else {
03413 rule = IsHangarTile(st->airport_tile);
03414 }
03415
03416 aib->cur_building_rule = rule;
03417 aib->use_tile = st->airport_tile;
03418 break;
03419 }
03420 } while (++i != _players_ai[p->index].num_build_rec);
03421
03422 _players_ai[p->index].state = AIS_BUILD_DEFAULT_AIRPORT_BLOCKS;
03423 _players_ai[p->index].state_mode = 255;
03424 _players_ai[p->index].state_counter = 0;
03425 }
03426
03427 static CommandCost AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
03428 {
03429 uint32 avail_airports = GetValidAirports();
03430 CommandCost ret,total_cost(EXPENSES_CONSTRUCTION);
03431
03432 for (; p->mode == 0; p++) {
03433 if (!HasBit(avail_airports, p->attr)) return CMD_ERROR;
03434 ret = DoCommand(TILE_MASK(tile + ToTileIndexDiff(p->tileoffs)), p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_AIRPORT);
03435 if (CmdFailed(ret)) return CMD_ERROR;
03436 total_cost.AddCost(ret);
03437 }
03438
03439 return total_cost;
03440 }
03441
03442 static bool AiCheckAirportResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
03443 {
03444 uint values[NUM_CARGO];
03445
03446 for (; p->mode == 0; p++) {
03447 TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
03448 const AirportFTAClass* airport = GetAirport(p->attr);
03449 uint w = airport->size_x;
03450 uint h = airport->size_y;
03451 uint rad = _patches.modified_catchment ? airport->catchment : (uint)CA_UNMODIFIED;
03452
03453 if (cargo & 0x80) {
03454 GetProductionAroundTiles(values, tile2, w, h, rad);
03455 return values[cargo & 0x7F] != 0;
03456 } else {
03457 GetAcceptanceAroundTiles(values, tile2, w, h, rad);
03458 return values[cargo] >= 8;
03459 }
03460 }
03461 return true;
03462 }
03463
03464 static int AiFindBestDefaultAirportBlock(TileIndex tile, byte cargo, byte heli, CommandCost *cost)
03465 {
03466 const AiDefaultBlockData *p;
03467
03468 bool no_small = false;
03469
03470 if (!heli) {
03471
03472 uint valid = GetValidAirports();
03473 for (uint i = 0; (p = _airport_default_block_data[i]) != NULL; i++) {
03474 uint flags = GetAirport(p->attr)->flags;
03475 if (HasBit(valid, p->attr) && (flags & AirportFTAClass::AIRPLANES) && !(flags & AirportFTAClass::SHORT_STRIP)) {
03476 no_small = true;
03477 break;
03478 }
03479 }
03480 }
03481
03482 for (uint i = 0; (p = _airport_default_block_data[i]) != NULL; i++) {
03483 uint flags = GetAirport(p->attr)->flags;
03484
03485 if (heli && !(flags & AirportFTAClass::HELICOPTERS)) continue;
03486
03487 if (!heli && !(flags & AirportFTAClass::AIRPLANES)) continue;
03488
03489 if (no_small && (flags & AirportFTAClass::SHORT_STRIP)) continue;
03490
03491 *cost = AiDoBuildDefaultAirportBlock(tile, p, 0);
03492 if (CmdSucceeded(*cost) && AiCheckAirportResources(tile, p, cargo))
03493 return i;
03494 }
03495 return -1;
03496 }
03497
03498 static void AiStateBuildDefaultAirportBlocks(Player *p)
03499 {
03500 int i, j;
03501 AiBuildRec *aib;
03502 int rule;
03503 CommandCost cost;
03504
03505
03506 if (++_players_ai[p->index].timeout_counter == 1388) {
03507 _players_ai[p->index].state = AIS_0;
03508 return;
03509 }
03510
03511
03512 i = 8;
03513 do {
03514
03515 aib = &_players_ai[p->index].src;
03516 j = _players_ai[p->index].num_build_rec;
03517 do {
03518
03519 if (aib->cur_building_rule != 255) continue;
03520
03521
03522
03523 aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
03524
03525
03526 rule = AiFindBestDefaultAirportBlock(aib->use_tile, aib->cargo, _players_ai[p->index].build_kind, &cost);
03527
03528
03529
03530 if (rule == -1) {
03531
03532 if (_players_ai[p->index].state_counter >= 600) {
03533 AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode);
03534 }
03535
03536 if (++_players_ai[p->index].state_counter >= 1000) {
03537 _players_ai[p->index].state_counter = 0;
03538 _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode;
03539 }
03540 } else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) {
03541
03542 CommandCost r;
03543
03544 aib->cur_building_rule = rule;
03545
03546 r = AiDoBuildDefaultAirportBlock(
03547 aib->use_tile,
03548 _airport_default_block_data[rule],
03549 DC_EXEC | DC_NO_TOWN_RATING
03550 );
03551 assert(CmdSucceeded(r));
03552 }
03553 } while (++aib, --j);
03554 } while (--i);
03555
03556
03557 aib = &_players_ai[p->index].src;
03558 j = _players_ai[p->index].num_build_rec;
03559 do {
03560 if (aib->cur_building_rule == 255) return;
03561 } while (++aib, --j);
03562
03563
03564 _players_ai[p->index].state = AIS_BUILD_AIRCRAFT_VEHICLES;
03565 }
03566
03567 static StationID AiGetStationIdFromAircraftBlock(TileIndex tile, int id)
03568 {
03569 const AiDefaultBlockData *p = _airport_default_block_data[id];
03570 while (p->mode != 1) p++;
03571 return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
03572 }
03573
03574 static void AiStateBuildAircraftVehicles(Player *p)
03575 {
03576 const AiDefaultBlockData *ptr;
03577 TileIndex tile;
03578 EngineID veh;
03579 int i;
03580 VehicleID loco_id;
03581
03582 ptr = _airport_default_block_data[_players_ai[p->index].src.cur_building_rule];
03583 for (; ptr->mode != 0; ptr++) {}
03584
03585 tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs));
03586
03587
03588 byte forbidden = 0;
03589 for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) {
03590 const AiBuildRec *aib = (&_players_ai[p->index].src) + _players_ai[p->index].order_list_blocks[i];
03591 const Station *st = GetStationByTile(aib->use_tile);
03592
03593 if (st == NULL || !(st->facilities & FACIL_AIRPORT)) continue;
03594
03595 AirportFTAClass::Flags flags = st->Airport()->flags;
03596 if (!(flags & AirportFTAClass::AIRPLANES)) forbidden |= AIR_CTOL | AIR_FAST;
03597 if (flags & AirportFTAClass::SHORT_STRIP) forbidden |= AIR_FAST;
03598 }
03599
03600 veh = AiChooseAircraftToBuild(p->player_money, forbidden);
03601 if (veh == INVALID_ENGINE) return;
03602 if (GetStationByTile(tile)->Airport()->nof_depots == 0) return;
03603
03604
03605
03606 tile += ToTileIndexDiff(GetStationByTile(tile)->Airport()->airport_depots[0]);
03607 if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) return;
03608 loco_id = _new_vehicle_id;
03609
03610 for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) {
03611 AiBuildRec *aib = (&_players_ai[p->index].src) + _players_ai[p->index].order_list_blocks[i];
03612 bool is_pass = (_players_ai[p->index].cargo_type == CT_PASSENGERS || _players_ai[p->index].cargo_type == CT_MAIL);
03613 Order order;
03614
03615 order.type = OT_GOTO_STATION;
03616 order.flags = 0;
03617 order.dest = AiGetStationIdFromAircraftBlock(aib->use_tile, aib->cur_building_rule);
03618
03619 if (!is_pass && i == 1) order.flags |= OFB_UNLOAD;
03620 if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0))
03621 order.flags |= OFB_FULL_LOAD;
03622
03623 DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
03624 }
03625
03626 DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
03627
03628 DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
03629
03630 if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--;
03631
03632 if (--_players_ai[p->index].num_loco_to_build == 0) _players_ai[p->index].state = AIS_0;
03633 }
03634
03635 static void AiStateCheckShipStuff(Player *p)
03636 {
03637
03638 }
03639
03640 static void AiStateBuildDefaultShipBlocks(Player *p)
03641 {
03642
03643 }
03644
03645 static void AiStateDoShipStuff(Player *p)
03646 {
03647
03648 }
03649
03650 static void AiStateSellVeh(Player *p)
03651 {
03652 Vehicle *v = _players_ai[p->index].cur_veh;
03653
03654 if (v->owner == _current_player) {
03655 if (v->type == VEH_TRAIN) {
03656
03657 if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
03658 if (v->current_order.type != OT_GOTO_DEPOT)
03659 DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_TRAIN_TO_DEPOT);
03660 goto going_to_depot;
03661 }
03662
03663
03664 DoCommand(v->tile, v->index, 1, DC_EXEC, CMD_SELL_RAIL_WAGON);
03665
03666 } else if (v->type == VEH_ROAD) {
03667 if (!v->IsStoppedInDepot()) {
03668 if (v->current_order.type != OT_GOTO_DEPOT)
03669 DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
03670 goto going_to_depot;
03671 }
03672
03673 DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
03674 } else if (v->type == VEH_AIRCRAFT) {
03675 if (!v->IsStoppedInDepot()) {
03676 if (v->current_order.type != OT_GOTO_DEPOT)
03677 DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
03678 goto going_to_depot;
03679 }
03680
03681 DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT);
03682 } else if (v->type == VEH_SHIP) {
03683
03684 }
03685 }
03686
03687 goto return_to_loop;
03688 going_to_depot:;
03689 if (++_players_ai[p->index].state_counter <= 832) return;
03690
03691 if (v->current_order.type == OT_GOTO_DEPOT) {
03692 v->current_order.type = OT_DUMMY;
03693 v->current_order.flags = 0;
03694 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
03695 }
03696 return_to_loop:;
03697 _players_ai[p->index].state = AIS_VEH_LOOP;
03698 }
03699
03700 static void AiStateRemoveStation(Player *p)
03701 {
03702
03703 const Order *ord;
03704 const Station *st;
03705 TileIndex tile;
03706
03707
03708 _players_ai[p->index].state = AIS_1;
03709
03710
03711 byte *in_use = MallocT<byte>(GetMaxStationIndex() + 1);
03712 memset(in_use, 0, GetMaxStationIndex() + 1);
03713 FOR_ALL_ORDERS(ord) {
03714 if (ord->type == OT_GOTO_STATION) in_use[ord->dest] = 1;
03715 }
03716
03717
03718 FOR_ALL_STATIONS(st) {
03719 if (st->owner == _current_player && !in_use[st->index] &&
03720 ( (st->bus_stops != NULL && (tile = st->bus_stops->xy) != 0) ||
03721 (st->truck_stops != NULL && (tile = st->truck_stops->xy)) != 0 ||
03722 (tile = st->train_tile) != 0 ||
03723 (tile = st->dock_tile) != 0 ||
03724 (tile = st->airport_tile) != 0)) {
03725 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
03726 }
03727 }
03728
03729 free(in_use);
03730 }
03731
03732 static void AiRemovePlayerRailOrRoad(Player *p, TileIndex tile)
03733 {
03734 TrackBits rails;
03735
03736 if (IsTileType(tile, MP_RAILWAY)) {
03737 if (!IsTileOwner(tile, _current_player)) return;
03738
03739 if (IsPlainRailTile(tile)) {
03740 is_rail_crossing:;
03741 rails = GetRailTrackStatus(tile);
03742
03743 if (rails == TRACK_BIT_HORZ || rails == TRACK_BIT_VERT) return;
03744
03745 if (rails & TRACK_BIT_3WAY_NE) {
03746 pos_0:
03747 if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(1, 0))) & TRACK_BIT_3WAY_SW) == 0) {
03748 _players_ai[p->index].cur_dir_a = DIAGDIR_NE;
03749 _players_ai[p->index].cur_tile_a = tile;
03750 _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
03751 return;
03752 }
03753 }
03754
03755 if (rails & TRACK_BIT_3WAY_SE) {
03756 pos_1:
03757 if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(0, 1))) & TRACK_BIT_3WAY_NW) == 0) {
03758 _players_ai[p->index].cur_dir_a = DIAGDIR_SE;
03759 _players_ai[p->index].cur_tile_a = tile;
03760 _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
03761 return;
03762 }
03763 }
03764
03765 if (rails & TRACK_BIT_3WAY_SW) {
03766 pos_2:
03767 if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(1, 0))) & TRACK_BIT_3WAY_NE) == 0) {
03768 _players_ai[p->index].cur_dir_a = DIAGDIR_SW;
03769 _players_ai[p->index].cur_tile_a = tile;
03770 _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
03771 return;
03772 }
03773 }
03774
03775 if (rails & TRACK_BIT_3WAY_NW) {
03776 pos_3:
03777 if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) {
03778 _players_ai[p->index].cur_dir_a = DIAGDIR_NW;
03779 _players_ai[p->index].cur_tile_a = tile;
03780 _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
03781 return;
03782 }
03783 }
03784 } else {
03785 static const byte _depot_bits[] = {0x19, 0x16, 0x25, 0x2A};
03786
03787 DiagDirection dir = GetRailDepotDirection(tile);
03788
03789 if (GetRailTrackStatus(tile + TileOffsByDiagDir(dir)) & _depot_bits[dir])
03790 return;
03791
03792 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
03793 }
03794 } else if (IsTileType(tile, MP_ROAD)) {
03795 if (!IsTileOwner(tile, _current_player)) return;
03796
03797 if (IsLevelCrossing(tile)) goto is_rail_crossing;
03798
03799 if (IsRoadDepot(tile)) {
03800 DiagDirection dir;
03801 TileIndex t;
03802
03803
03804 t = tile + TileDiffXY(-1, 0);
03805 if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
03806
03807 t = tile + TileDiffXY(1, 0);
03808 if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
03809
03810 t = tile + TileDiffXY(0, -1);
03811 if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
03812
03813 t = tile + TileDiffXY(0, 1);
03814 if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
03815
03816 dir = GetRoadDepotDirection(tile);
03817
03818 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
03819 DoCommand(
03820 TILE_MASK(tile + TileOffsByDiagDir(dir)),
03821 DiagDirToRoadBits(ReverseDiagDir(dir)),
03822 0,
03823 DC_EXEC,
03824 CMD_REMOVE_ROAD);
03825 }
03826 } else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
03827 if (!IsTileOwner(tile, _current_player) ||
03828 !IsBridge(tile) ||
03829 GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) {
03830 return;
03831 }
03832
03833 rails = TRACK_BIT_NONE;
03834
03835 switch (GetTunnelBridgeDirection(tile)) {
03836 default:
03837 case DIAGDIR_NE: goto pos_2;
03838 case DIAGDIR_SE: goto pos_3;
03839 case DIAGDIR_SW: goto pos_0;
03840 case DIAGDIR_NW: goto pos_1;
03841 }
03842 }
03843 }
03844
03845 static void AiStateRemoveTrack(Player *p)
03846 {
03847
03848 int num = MapSizeX() * 4;
03849
03850 do {
03851 TileIndex tile = ++_players_ai[p->index].state_counter;
03852
03853
03854 if (tile >= MapSize()) {
03855 _players_ai[p->index].state = AIS_REMOVE_STATION;
03856 return;
03857 }
03858
03859
03860 AiRemovePlayerRailOrRoad(p, tile);
03861 if (_players_ai[p->index].state != AIS_REMOVE_TRACK) return;
03862 } while (--num);
03863 }
03864
03865 static void AiStateRemoveSingleRailTile(Player *p)
03866 {
03867
03868 if (!AiRemoveTileAndGoForward(p)) _players_ai[p->index].state = AIS_REMOVE_TRACK;
03869 }
03870
03871 static AiStateAction * const _ai_actions[] = {
03872 AiCase0,
03873 AiCase1,
03874 AiStateVehLoop,
03875 AiStateCheckReplaceVehicle,
03876 AiStateDoReplaceVehicle,
03877 AiStateWantNewRoute,
03878
03879 AiStateBuildDefaultRailBlocks,
03880 AiStateBuildRail,
03881 AiStateBuildRailVeh,
03882 AiStateDeleteRailBlocks,
03883
03884 AiStateBuildDefaultRoadBlocks,
03885 AiStateBuildRoad,
03886 AiStateBuildRoadVehicles,
03887 AiStateDeleteRoadBlocks,
03888
03889 AiStateAirportStuff,
03890 AiStateBuildDefaultAirportBlocks,
03891 AiStateBuildAircraftVehicles,
03892
03893 AiStateCheckShipStuff,
03894 AiStateBuildDefaultShipBlocks,
03895 AiStateDoShipStuff,
03896
03897 AiStateSellVeh,
03898 AiStateRemoveStation,
03899 AiStateRemoveTrack,
03900
03901 AiStateRemoveSingleRailTile
03902 };
03903
03904 extern void ShowBuyCompanyDialog(uint player);
03905
03906 static void AiHandleTakeover(Player *p)
03907 {
03908 if (p->bankrupt_timeout != 0) {
03909 p->bankrupt_timeout -= 8;
03910 if (p->bankrupt_timeout > 0) return;
03911 p->bankrupt_timeout = 0;
03912 DeleteWindowById(WC_BUY_COMPANY, _current_player);
03913 if (IsLocalPlayer()) {
03914 AskExitToGameMenu();
03915 return;
03916 }
03917 if (IsHumanPlayer(_current_player)) return;
03918 }
03919
03920 if (p->bankrupt_asked == 255) return;
03921
03922 {
03923 uint asked = p->bankrupt_asked;
03924 Player *pp, *best_pl = NULL;
03925 int32 best_val = -1;
03926
03927
03928 FOR_ALL_PLAYERS(pp) {
03929 if (pp->is_active &&
03930 !(asked & 1) &&
03931 pp->bankrupt_asked == 0 &&
03932 best_val < pp->old_economy[1].performance_history) {
03933 best_val = pp->old_economy[1].performance_history;
03934 best_pl = pp;
03935 }
03936 asked >>= 1;
03937 }
03938
03939
03940 if (best_val == -1) {
03941 p->bankrupt_asked = 255;
03942 return;
03943 }
03944
03945 SetBit(p->bankrupt_asked, best_pl->index);
03946
03947 if (best_pl->index == _local_player) {
03948 p->bankrupt_timeout = 4440;
03949 ShowBuyCompanyDialog(_current_player);
03950 return;
03951 }
03952 if (IsHumanPlayer(best_pl->index)) return;
03953
03954
03955 if (best_pl->player_money >> 1 >= p->bankrupt_value) {
03956
03957 PlayerID old_p = _current_player;
03958 _current_player = best_pl->index;
03959 DoCommand(0, old_p, 0, DC_EXEC, CMD_BUY_COMPANY);
03960 _current_player = old_p;
03961 }
03962 }
03963 }
03964
03965 static void AiAdjustLoan(const Player* p)
03966 {
03967 Money base = AiGetBasePrice(p);
03968
03969 if (p->player_money > base * 1400) {
03970
03971 if (p->current_loan != 0) {
03972 DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN);
03973 }
03974 } else if (p->player_money < base * 500) {
03975
03976 if (p->current_loan < _economy.max_loan &&
03977 p->num_valid_stat_ent >= 2 &&
03978 -(p->old_economy[0].expenses + p->old_economy[1].expenses) < base * 60) {
03979 DoCommand(0, 0, 0, DC_EXEC, CMD_INCREASE_LOAN);
03980 }
03981 }
03982 }
03983
03984 static void AiBuildCompanyHQ(Player *p)
03985 {
03986 TileIndex tile;
03987
03988 if (p->location_of_house == 0 &&
03989 p->last_build_coordinate != 0) {
03990 tile = AdjustTileCoordRandomly(p->last_build_coordinate, 8);
03991 DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
03992 }
03993 }
03994
03995
03996 void AiDoGameLoop(Player *p)
03997 {
03998 if (p->bankrupt_asked != 0) {
03999 AiHandleTakeover(p);
04000 return;
04001 }
04002
04003
04004
04005
04006
04007 _ai_service_interval = _patches.servint_ispercent ? 80 : 180;
04008
04009 if (IsHumanPlayer(_current_player)) return;
04010
04011 AiAdjustLoan(p);
04012 AiBuildCompanyHQ(p);
04013
04014 #if 0
04015 {
04016 static byte old_state = 99;
04017 static bool hasdots = false;
04018 char *_ai_state_names[] = {
04019 "AiCase0",
04020 "AiCase1",
04021 "AiStateVehLoop",
04022 "AiStateCheckReplaceVehicle",
04023 "AiStateDoReplaceVehicle",
04024 "AiStateWantNewRoute",
04025 "AiStateBuildDefaultRailBlocks",
04026 "AiStateBuildRail",
04027 "AiStateBuildRailVeh",
04028 "AiStateDeleteRailBlocks",
04029 "AiStateBuildDefaultRoadBlocks",
04030 "AiStateBuildRoad",
04031 "AiStateBuildRoadVehicles",
04032 "AiStateDeleteRoadBlocks",
04033 "AiStateAirportStuff",
04034 "AiStateBuildDefaultAirportBlocks",
04035 "AiStateBuildAircraftVehicles",
04036 "AiStateCheckShipStuff",
04037 "AiStateBuildDefaultShipBlocks",
04038 "AiStateDoShipStuff",
04039 "AiStateSellVeh",
04040 "AiStateRemoveStation",
04041 "AiStateRemoveTrack",
04042 "AiStateRemoveSingleRailTile"
04043 };
04044
04045 if (_players_ai[p->index].state != old_state) {
04046 if (hasdots)
04047 printf("\n");
04048 hasdots=false;
04049 printf("AiState: %s\n", _ai_state_names[old_state=_players_ai[p->index].state]);
04050 } else {
04051 printf(".");
04052 hasdots=true;
04053 }
04054 }
04055 #endif
04056
04057 _ai_actions[_players_ai[p->index].state](p);
04058 }
04059
04060
04061 static const SaveLoad _player_ai_desc[] = {
04062 SLE_VAR(PlayerAI, state, SLE_UINT8),
04063 SLE_VAR(PlayerAI, tick, SLE_UINT8),
04064 SLE_CONDVAR(PlayerAI, state_counter, SLE_FILE_U16 | SLE_VAR_U32, 0, 12),
04065 SLE_CONDVAR(PlayerAI, state_counter, SLE_UINT32, 13, SL_MAX_VERSION),
04066 SLE_VAR(PlayerAI, timeout_counter, SLE_UINT16),
04067
04068 SLE_VAR(PlayerAI, state_mode, SLE_UINT8),
04069 SLE_VAR(PlayerAI, banned_tile_count, SLE_UINT8),
04070 SLE_VAR(PlayerAI, railtype_to_use, SLE_UINT8),
04071
04072 SLE_VAR(PlayerAI, cargo_type, SLE_UINT8),
04073 SLE_VAR(PlayerAI, num_wagons, SLE_UINT8),
04074 SLE_VAR(PlayerAI, build_kind, SLE_UINT8),
04075 SLE_VAR(PlayerAI, num_build_rec, SLE_UINT8),
04076 SLE_VAR(PlayerAI, num_loco_to_build, SLE_UINT8),
04077 SLE_VAR(PlayerAI, num_want_fullload, SLE_UINT8),
04078
04079 SLE_VAR(PlayerAI, route_type_mask, SLE_UINT8),
04080
04081 SLE_CONDVAR(PlayerAI, start_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04082 SLE_CONDVAR(PlayerAI, start_tile_a, SLE_UINT32, 6, SL_MAX_VERSION),
04083 SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04084 SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_UINT32, 6, SL_MAX_VERSION),
04085 SLE_VAR(PlayerAI, start_dir_a, SLE_UINT8),
04086 SLE_VAR(PlayerAI, cur_dir_a, SLE_UINT8),
04087
04088 SLE_CONDVAR(PlayerAI, start_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04089 SLE_CONDVAR(PlayerAI, start_tile_b, SLE_UINT32, 6, SL_MAX_VERSION),
04090 SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04091 SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_UINT32, 6, SL_MAX_VERSION),
04092 SLE_VAR(PlayerAI, start_dir_b, SLE_UINT8),
04093 SLE_VAR(PlayerAI, cur_dir_b, SLE_UINT8),
04094
04095 SLE_REF(PlayerAI, cur_veh, REF_VEHICLE),
04096
04097 SLE_ARR(PlayerAI, wagon_list, SLE_UINT16, 9),
04098 SLE_ARR(PlayerAI, order_list_blocks, SLE_UINT8, 20),
04099 SLE_ARR(PlayerAI, banned_tiles, SLE_UINT16, 16),
04100
04101 SLE_CONDNULL(64, 2, SL_MAX_VERSION),
04102 SLE_END()
04103 };
04104
04105 static const SaveLoad _player_ai_build_rec_desc[] = {
04106 SLE_CONDVAR(AiBuildRec, spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04107 SLE_CONDVAR(AiBuildRec, spec_tile, SLE_UINT32, 6, SL_MAX_VERSION),
04108 SLE_CONDVAR(AiBuildRec, use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
04109 SLE_CONDVAR(AiBuildRec, use_tile, SLE_UINT32, 6, SL_MAX_VERSION),
04110 SLE_VAR(AiBuildRec, rand_rng, SLE_UINT8),
04111 SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8),
04112 SLE_VAR(AiBuildRec, unk6, SLE_UINT8),
04113 SLE_VAR(AiBuildRec, unk7, SLE_UINT8),
04114 SLE_VAR(AiBuildRec, buildcmd_a, SLE_UINT8),
04115 SLE_VAR(AiBuildRec, buildcmd_b, SLE_UINT8),
04116 SLE_VAR(AiBuildRec, direction, SLE_UINT8),
04117 SLE_VAR(AiBuildRec, cargo, SLE_UINT8),
04118 SLE_END()
04119 };
04120
04121
04122 void SaveLoad_AI(PlayerID id)
04123 {
04124 PlayerAI *pai = &_players_ai[id];
04125 SlObject(pai, _player_ai_desc);
04126 for (int i = 0; i != pai->num_build_rec; i++) {
04127 SlObject(&pai->src + i, _player_ai_build_rec_desc);
04128 }
04129 }