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