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