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