# ai_tunnel.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_tunnel.cpp 16247 2009-05-06 22:37:19Z rubidium $ */
    00002
    00005 #include "ai_tunnel.hpp"
    00006 #include "ai_rail.hpp"
    00007 #include "../ai_instance.hpp"
    00008 #include "../../tunnel_map.h"
    00009 #include "../../command_func.h"
    00010 #include "../../tunnelbridge.h"
    00011 #include "../../road_func.h"
    00012
    00013 /* static */ bool AITunnel::IsTunnelTile(TileIndex tile)
    00014 {
    00015   if (!::IsValidTile(tile)) return false;
    00016   return ::IsTunnelTile(tile);
    00017 }
    00018
    00019 /* static */ TileIndex AITunnel::GetOtherTunnelEnd(TileIndex tile)
    00020 {
    00021   if (!::IsValidTile(tile)) return INVALID_TILE;
    00022
    00023   /* If it's a tunnel alread, take the easy way out! */
    00024   if (IsTunnelTile(tile)) return ::GetOtherTunnelEnd(tile);
    00025
    00026   uint start_z;
    00027   Slope start_tileh = ::GetTileSlope(tile, &start_z);
    00028   DiagDirection direction = ::GetInclinedSlopeDirection(start_tileh);
    00029   if (direction == INVALID_DIAGDIR) return INVALID_TILE;
    00030
    00031   TileIndexDiff delta = ::TileOffsByDiagDir(direction);
    00032   uint end_z;
    00033   do {
    00034     tile += delta;
    00035     if (!::IsValidTile(tile)) return INVALID_TILE;
    00036
    00037 		::GetTileSlope(tile, &end_z);
    00038   } while (start_z != end_z);
    00039
    00040   return tile;
    00041 }
    00042
    00043 static void _DoCommandReturnBuildTunnel2(class AIInstance *instance)
    00044 {
    00045   if (!AITunnel::_BuildTunnelRoad2()) {
    00046     AIInstance::DoCommandReturn(instance);
    00047     return;
    00048   }
    00049
    00050   /* This can never happen, as in test-mode this callback is never executed,
    00051    *  and in execute-mode, the other callback is called. */
    00052   NOT_REACHED();
    00053 }
    00054
    00055 static void _DoCommandReturnBuildTunnel1(class AIInstance *instance)
    00056 {
    00057   if (!AITunnel::_BuildTunnelRoad1()) {
    00058     AIInstance::DoCommandReturn(instance);
    00059     return;
    00060   }
    00061
    00062   /* This can never happen, as in test-mode this callback is never executed,
    00063    *  and in execute-mode, the other callback is called. */
    00064   NOT_REACHED();
    00065 }
    00066
    00067 /* static */ bool AITunnel::BuildTunnel(AIVehicle::VehicleType vehicle_type, TileIndex start)
    00068 {
    00069   EnforcePrecondition(false, ::IsValidTile(start));
    00070   EnforcePrecondition(false, vehicle_type == AIVehicle::VT_RAIL || vehicle_type == AIVehicle::VT_ROAD);
    00071   EnforcePrecondition(false, vehicle_type != AIVehicle::VT_RAIL || AIRail::IsRailTypeAvailable(AIRail::GetCurrentRailType()));
    00072
    00073   uint type = 0;
    00074   if (vehicle_type == AIVehicle::VT_ROAD) {
    00075     type |= (TRANSPORT_ROAD << 9);
    00076     type |= ::RoadTypeToRoadTypes((::RoadType)AIObject::GetRoadType());
    00077   } else {
    00078     type |= (TRANSPORT_RAIL << 9);
    00079     type |= AIRail::GetCurrentRailType();
    00080   }
    00081
    00082   /* For rail we do nothing special */
    00083   if (vehicle_type == AIVehicle::VT_RAIL) {
    00084     return AIObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL);
    00085   }
    00086
    00087   AIObject::SetCallbackVariable(0, start);
    00088   return AIObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, NULL, &_DoCommandReturnBuildTunnel1);
    00089 }
    00090
    00091 /* static */ bool AITunnel::_BuildTunnelRoad1()
    00092 {
    00093   /* Build the piece of road on the 'start' side of the tunnel */
    00094   TileIndex end = AIObject::GetCallbackVariable(0);
    00095   TileIndex start = AITunnel::GetOtherTunnelEnd(end);
    00096
    00097   DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW));
    00098   DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
    00099
    00100   return AIObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &_DoCommandReturnBuildTunnel2);
    00101 }
    00102
    00103 /* static */ bool AITunnel::_BuildTunnelRoad2()
    00104 {
    00105   /* Build the piece of road on the 'end' side of the tunnel */
    00106   TileIndex end = AIObject::GetCallbackVariable(0);
    00107   TileIndex start = AITunnel::GetOtherTunnelEnd(end);
    00108
    00109   DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW));
    00110   DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
    00111
    00112   return AIObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD);
    00113 }
    00114
    00115 /* static */ bool AITunnel::RemoveTunnel(TileIndex tile)
    00116 {
    00117   EnforcePrecondition(false, IsTunnelTile(tile));
    00118
    00119   return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
    00120 }