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