00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "ai_map.hpp"
00013 #include "ai_station.hpp"
00014 #include "ai_cargo.hpp"
00015 #include "../../station_base.h"
00016 #include "../../company_func.h"
00017 #include "../../script/squirrel_helper_type.hpp"
00018
00019 AIRoad::RoadVehicleType AIRoad::GetRoadVehicleTypeForCargo(CargoID cargo_type)
00020 {
00021 return AICargo::HasCargoClass(cargo_type, AICargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK;
00022 }
00023
00024 bool AIRoad::IsRoadTile(TileIndex tile)
00025 {
00026 if (!::IsValidTile(tile)) return false;
00027
00028 return (::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) != ROAD_TILE_DEPOT) ||
00029 IsDriveThroughRoadStationTile(tile);
00030 }
00031
00032 bool AIRoad::IsRoadDepotTile(TileIndex tile)
00033 {
00034 if (!::IsValidTile(tile)) return false;
00035
00036 return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT &&
00037 (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00038 }
00039
00040 bool AIRoad::IsRoadStationTile(TileIndex tile)
00041 {
00042 if (!::IsValidTile(tile)) return false;
00043
00044 return ::IsRoadStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00045 }
00046
00047 bool AIRoad::IsDriveThroughRoadStationTile(TileIndex tile)
00048 {
00049 if (!::IsValidTile(tile)) return false;
00050
00051 return ::IsDriveThroughStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00052 }
00053
00054 bool AIRoad::IsRoadTypeAvailable(RoadType road_type)
00055 {
00056 return ::HasRoadTypesAvail(_current_company, ::RoadTypeToRoadTypes((::RoadType)road_type));
00057 }
00058
00059 AIRoad::RoadType AIRoad::GetCurrentRoadType()
00060 {
00061 return (RoadType)AIObject::GetRoadType();
00062 }
00063
00064 void AIRoad::SetCurrentRoadType(RoadType road_type)
00065 {
00066 if (!IsRoadTypeAvailable(road_type)) return;
00067
00068 AIObject::SetRoadType((::RoadType)road_type);
00069 }
00070
00071 bool AIRoad::HasRoadType(TileIndex tile, RoadType road_type)
00072 {
00073 if (!AIMap::IsValidTile(tile)) return false;
00074 if (!IsRoadTypeAvailable(road_type)) return false;
00075 return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE;
00076 }
00077
00078 bool AIRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2)
00079 {
00080 if (!::IsValidTile(t1)) return false;
00081 if (!::IsValidTile(t2)) return false;
00082 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
00083
00084
00085 if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false;
00086
00087 RoadBits r1 = ::GetAnyRoadBits(t1, AIObject::GetRoadType());
00088 RoadBits r2 = ::GetAnyRoadBits(t2, AIObject::GetRoadType());
00089
00090 uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3);
00091 uint dir_2 = 2 ^ dir_1;
00092
00093 DisallowedRoadDirections drd2 = IsNormalRoadTile(t2) ? GetDisallowedRoadDirections(t2) : DRD_NONE;
00094
00095 return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND);
00096 }
00097
00098
00099
00114 static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end)
00115 {
00116 return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end);
00117 }
00118
00129 static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end)
00130 {
00131 switch (slope) {
00132
00133 case SLOPE_FLAT:
00134 return 1;
00135
00136
00137
00138
00139
00140 case SLOPE_NE: case SLOPE_SW:
00141 return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0;
00142 case SLOPE_SE: case SLOPE_NW:
00143 return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0;
00144
00145
00146 default:
00147 return 0;
00148 }
00149 }
00150
00156 static int32 RotateNeighbour(int32 neighbour)
00157 {
00158 switch (neighbour) {
00159 case -2: return -1;
00160 case -1: return 2;
00161 case 1: return -2;
00162 case 2: return 1;
00163 default: NOT_REACHED();
00164 }
00165 }
00166
00172 static RoadBits NeighbourToRoadBits(int32 neighbour)
00173 {
00174 switch (neighbour) {
00175 case -2: return ROAD_NW;
00176 case -1: return ROAD_NE;
00177 case 2: return ROAD_SE;
00178 case 1: return ROAD_SW;
00179 default: NOT_REACHED();
00180 }
00181 }
00182
00193 static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end)
00194 {
00195 if (::IsSteepSlope(slope)) {
00196 switch (slope) {
00197
00198
00199
00200 case SLOPE_STEEP_S:
00201 case SLOPE_STEEP_W:
00202 case SLOPE_STEEP_N:
00203 case SLOPE_STEEP_E:
00204 return CheckAutoExpandedRoadBits(existing, start, end) ? (existing->size == 0 ? 2 : 1) : 0;
00205
00206
00207 default:
00208 return -1;
00209 }
00210 }
00211
00212
00213
00214
00215
00216 static const ::Slope base_slopes[] = {
00217 SLOPE_FLAT, SLOPE_W, SLOPE_W, SLOPE_SW,
00218 SLOPE_W, SLOPE_EW, SLOPE_SW, SLOPE_WSE,
00219 SLOPE_W, SLOPE_SW, SLOPE_EW, SLOPE_WSE,
00220 SLOPE_SW, SLOPE_WSE, SLOPE_WSE};
00221 static const byte base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1};
00222
00223 if (slope >= (::Slope)lengthof(base_slopes)) {
00224
00225 return -1;
00226 }
00227 byte base_rotate = base_rotates[slope];
00228 slope = base_slopes[slope];
00229
00230
00231
00232 switch (slope) {
00233 case SLOPE_FLAT:
00234
00235 return 1;
00236
00237 case SLOPE_EW:
00238 case SLOPE_WSE:
00239
00240
00241 return 1;
00242
00243 case SLOPE_W:
00244 case SLOPE_SW:
00245
00246 break;
00247
00248 default:
00249
00250 return -1;
00251 }
00252
00253
00254 for (int j = 0; j < base_rotate; j++) {
00255 for (int i = 0; i < existing->size; i++) {
00256 existing->array[i] = RotateNeighbour(existing->array[i]);
00257 }
00258 start = RotateNeighbour(start);
00259 end = RotateNeighbour(end);
00260 }
00261
00262
00263 RoadBits start_roadbits = NeighbourToRoadBits(start);
00264 RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end);
00265 RoadBits existing_roadbits = ROAD_NONE;
00266 for (int i = 0; i < existing->size; i++) {
00267 existing_roadbits |= NeighbourToRoadBits(existing->array[i]);
00268 }
00269
00270 switch (slope) {
00271 case SLOPE_W:
00272
00273 switch (new_roadbits) {
00274 case ROAD_N:
00275 case ROAD_E:
00276 case ROAD_S:
00277
00278 return 0;
00279
00280 case ROAD_X:
00281 case ROAD_Y:
00282
00283 if ((existing_roadbits | new_roadbits) != new_roadbits) {
00284
00285
00286 return 0;
00287 }
00288
00289
00290 return ((start_roadbits & ROAD_E) && !(existing_roadbits & ROAD_W)) ? 2 : 1;
00291
00292 default:
00293
00294
00295
00296 if ((existing_roadbits | new_roadbits) == new_roadbits) return 1;
00297 return (existing_roadbits & ROAD_E) ? 0 : 1;
00298 }
00299
00300 case SLOPE_SW:
00301
00302 switch (new_roadbits) {
00303 case ROAD_N:
00304 case ROAD_E:
00305
00306 return 0;
00307
00308 case ROAD_X:
00309
00310 if ((existing_roadbits | new_roadbits) != new_roadbits) {
00311
00312
00313 return 0;
00314 }
00315
00316
00317 return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1;
00318
00319 default:
00320
00321
00322
00323 return (existing_roadbits & ROAD_NE) ? 0 : 1;
00324 }
00325
00326 default:
00327 NOT_REACHED();
00328 }
00329 }
00330
00341 static bool NormaliseTileOffset(int32 *tile)
00342 {
00343 if (*tile == 1 || *tile == -1) return true;
00344 if (*tile == ::TileDiffXY(0, -1)) {
00345 *tile = -2;
00346 return true;
00347 }
00348 if (*tile == ::TileDiffXY(0, 1)) {
00349 *tile = 2;
00350 return true;
00351 }
00352 return false;
00353 }
00354
00355 int32 AIRoad::CanBuildConnectedRoadParts(AITile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_)
00356 {
00357 ::Slope slope = (::Slope)slope_;
00358 int32 start = start_;
00359 int32 end = end_;
00360
00361
00362 if (start == end) return -1;
00363
00364 for (int i = 0; i < existing->size; i++) {
00365 if (!NormaliseTileOffset(&existing->array[i])) return -1;
00366 }
00367
00368 if (!NormaliseTileOffset(&start)) return -1;
00369 if (!NormaliseTileOffset(&end)) return -1;
00370
00371
00372
00373 return _settings_game.construction.build_on_slopes ? LookupWithBuildOnSlopes(slope, existing, start, end) : LookupWithoutBuildOnSlopes(slope, existing, start, end);
00374 }
00375
00376 int32 AIRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end)
00377 {
00378 if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1;
00379 if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1;
00380
00381
00382 static const TileIndex neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)};
00383 Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32));
00384 existing->size = 0;
00385
00386 ::RoadBits rb = ::ROAD_NONE;
00387 if (::IsNormalRoadTile(tile)) {
00388 rb = ::GetAllRoadBits(tile);
00389 } else {
00390 for (::RoadType rt = ::ROADTYPE_BEGIN; rt < ::ROADTYPE_END; rt++) rb |= ::GetAnyRoadBits(tile, rt);
00391 }
00392 for (uint i = 0; i < lengthof(neighbours); i++) {
00393 if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i];
00394 }
00395
00396 return AIRoad::CanBuildConnectedRoadParts(AITile::GetSlope(tile), existing, start - tile, end - tile);
00397 }
00398
00407 static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, DiagDirection neighbour)
00408 {
00409 TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour);
00410 if ((rts & ::GetRoadTypes(neighbour_tile)) == 0) return false;
00411
00412 switch (::GetTileType(neighbour_tile)) {
00413 case MP_ROAD:
00414 return (::GetRoadTileType(neighbour_tile) != ROAD_TILE_DEPOT);
00415
00416 case MP_STATION:
00417 if (::IsDriveThroughStopTile(neighbour_tile)) {
00418 return (::DiagDirToAxis(neighbour) == ::DiagDirToAxis(::GetRoadStopDir(neighbour_tile)));
00419 }
00420 return false;
00421
00422 default:
00423 return false;
00424 }
00425 }
00426
00427 int32 AIRoad::GetNeighbourRoadCount(TileIndex tile)
00428 {
00429 if (!::IsValidTile(tile)) return false;
00430 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
00431
00432 ::RoadTypes rts = ::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType());
00433 int32 neighbour = 0;
00434
00435 if (TileX(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NE)) neighbour++;
00436 if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SE)) neighbour++;
00437 if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SW)) neighbour++;
00438 if (TileY(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NW)) neighbour++;
00439
00440 return neighbour;
00441 }
00442
00443 TileIndex AIRoad::GetRoadDepotFrontTile(TileIndex depot)
00444 {
00445 if (!IsRoadDepotTile(depot)) return INVALID_TILE;
00446
00447 return depot + ::TileOffsByDiagDir(::GetRoadDepotDirection(depot));
00448 }
00449
00450 TileIndex AIRoad::GetRoadStationFrontTile(TileIndex station)
00451 {
00452 if (!IsRoadStationTile(station)) return INVALID_TILE;
00453
00454 return station + ::TileOffsByDiagDir(::GetRoadStopDir(station));
00455 }
00456
00457 TileIndex AIRoad::GetDriveThroughBackTile(TileIndex station)
00458 {
00459 if (!IsDriveThroughRoadStationTile(station)) return INVALID_TILE;
00460
00461 return station + ::TileOffsByDiagDir(::ReverseDiagDir(::GetRoadStopDir(station)));
00462 }
00463
00464 bool AIRoad::_BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full)
00465 {
00466 EnforcePrecondition(false, start != end);
00467 EnforcePrecondition(false, ::IsValidTile(start));
00468 EnforcePrecondition(false, ::IsValidTile(end));
00469 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00470 EnforcePrecondition(false, !one_way || AIObject::GetRoadType() == ::ROADTYPE_ROAD);
00471 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00472
00473 return AIObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (AIObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 5) | 1 << 6, CMD_BUILD_LONG_ROAD);
00474 }
00475
00476 bool AIRoad::BuildRoad(TileIndex start, TileIndex end)
00477 {
00478 return _BuildRoadInternal(start, end, false, false);
00479 }
00480
00481 bool AIRoad::BuildOneWayRoad(TileIndex start, TileIndex end)
00482 {
00483 return _BuildRoadInternal(start, end, true, false);
00484 }
00485
00486 bool AIRoad::BuildRoadFull(TileIndex start, TileIndex end)
00487 {
00488 return _BuildRoadInternal(start, end, false, true);
00489 }
00490
00491 bool AIRoad::BuildOneWayRoadFull(TileIndex start, TileIndex end)
00492 {
00493 return _BuildRoadInternal(start, end, true, true);
00494 }
00495
00496 bool AIRoad::BuildRoadDepot(TileIndex tile, TileIndex front)
00497 {
00498 EnforcePrecondition(false, tile != front);
00499 EnforcePrecondition(false, ::IsValidTile(tile));
00500 EnforcePrecondition(false, ::IsValidTile(front));
00501 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
00502 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00503
00504 uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
00505
00506 return AIObject::DoCommand(tile, entrance_dir | (AIObject::GetRoadType() << 2), 0, CMD_BUILD_ROAD_DEPOT);
00507 }
00508
00509 bool AIRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
00510 {
00511 EnforcePrecondition(false, tile != front);
00512 EnforcePrecondition(false, ::IsValidTile(tile));
00513 EnforcePrecondition(false, ::IsValidTile(front));
00514 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
00515 EnforcePrecondition(false, station_id == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id));
00516 EnforcePrecondition(false, road_veh_type == ROADVEHTYPE_BUS || road_veh_type == ROADVEHTYPE_TRUCK);
00517 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00518
00519 uint entrance_dir;
00520 if (drive_through) {
00521 entrance_dir = ::TileY(tile) != ::TileY(front);
00522 } else {
00523 entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
00524 }
00525
00526 uint p2 = station_id == AIStation::STATION_JOIN_ADJACENT ? 0 : 32;
00527 p2 |= drive_through ? 2 : 0;
00528 p2 |= road_veh_type == ROADVEHTYPE_TRUCK ? 1 : 0;
00529 p2 |= ::RoadTypeToRoadTypes(AIObject::GetRoadType()) << 2;
00530 p2 |= entrance_dir << 6;
00531 p2 |= (AIStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16;
00532 return AIObject::DoCommand(tile, 1 | 1 << 8, p2, CMD_BUILD_ROAD_STOP);
00533 }
00534
00535 bool AIRoad::BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
00536 {
00537 return _BuildRoadStationInternal(tile, front, road_veh_type, false, station_id);
00538 }
00539
00540 bool AIRoad::BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
00541 {
00542 return _BuildRoadStationInternal(tile, front, road_veh_type, true, station_id);
00543 }
00544
00545 bool AIRoad::RemoveRoad(TileIndex start, TileIndex end)
00546 {
00547 EnforcePrecondition(false, ::IsValidTile(start));
00548 EnforcePrecondition(false, ::IsValidTile(end));
00549 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00550 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00551
00552 return AIObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 1 : 2) | (AIObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD);
00553 }
00554
00555 bool AIRoad::RemoveRoadFull(TileIndex start, TileIndex end)
00556 {
00557 EnforcePrecondition(false, ::IsValidTile(start));
00558 EnforcePrecondition(false, ::IsValidTile(end));
00559 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00560 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00561
00562 return AIObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 2 : 1) | (AIObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD);
00563 }
00564
00565 bool AIRoad::RemoveRoadDepot(TileIndex tile)
00566 {
00567 EnforcePrecondition(false, ::IsValidTile(tile));
00568 EnforcePrecondition(false, IsTileType(tile, MP_ROAD))
00569 EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT);
00570
00571 return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
00572 }
00573
00574 bool AIRoad::RemoveRoadStation(TileIndex tile)
00575 {
00576 EnforcePrecondition(false, ::IsValidTile(tile));
00577 EnforcePrecondition(false, IsTileType(tile, MP_STATION));
00578 EnforcePrecondition(false, IsRoadStop(tile));
00579
00580 return AIObject::DoCommand(tile, 1 | 1 << 8, GetRoadStopType(tile), CMD_REMOVE_ROAD_STOP);
00581 }
00582
00583 Money AIRoad::GetBuildCost(RoadType roadtype, BuildType build_type)
00584 {
00585 if (!AIRoad::IsRoadTypeAvailable(roadtype)) return -1;
00586
00587 switch (build_type) {
00588 case BT_ROAD: return ::GetPrice(PR_BUILD_ROAD, 1, NULL);
00589 case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, NULL);
00590 case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, NULL);
00591 case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, NULL);
00592 default: return -1;
00593 }
00594 }