ai_tunnel.cpp

Go to the documentation of this file.
00001 /* $Id: ai_tunnel.cpp 21888 2011-01-22 10:33:16Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "ai_tunnel.hpp"
00014 #include "ai_rail.hpp"
00015 #include "../ai_instance.hpp"
00016 #include "../../tunnel_map.h"
00017 #include "../../command_func.h"
00018 
00019 /* static */ bool AITunnel::IsTunnelTile(TileIndex tile)
00020 {
00021   if (!::IsValidTile(tile)) return false;
00022   return ::IsTunnelTile(tile);
00023 }
00024 
00025 /* static */ TileIndex AITunnel::GetOtherTunnelEnd(TileIndex tile)
00026 {
00027   if (!::IsValidTile(tile)) return INVALID_TILE;
00028 
00029   /* If it's a tunnel already, take the easy way out! */
00030   if (IsTunnelTile(tile)) return ::GetOtherTunnelEnd(tile);
00031 
00032   uint start_z;
00033   Slope start_tileh = ::GetTileSlope(tile, &start_z);
00034   DiagDirection direction = ::GetInclinedSlopeDirection(start_tileh);
00035   if (direction == INVALID_DIAGDIR) return INVALID_TILE;
00036 
00037   TileIndexDiff delta = ::TileOffsByDiagDir(direction);
00038   uint end_z;
00039   do {
00040     tile += delta;
00041     if (!::IsValidTile(tile)) return INVALID_TILE;
00042 
00043 		::GetTileSlope(tile, &end_z);
00044   } while (start_z != end_z);
00045 
00046   return tile;
00047 }
00048 
00049 static void _DoCommandReturnBuildTunnel2(class AIInstance *instance)
00050 {
00051   if (!AITunnel::_BuildTunnelRoad2()) {
00052     AIInstance::DoCommandReturn(instance);
00053     return;
00054   }
00055 
00056   /* This can never happen, as in test-mode this callback is never executed,
00057    *  and in execute-mode, the other callback is called. */
00058   NOT_REACHED();
00059 }
00060 
00061 static void _DoCommandReturnBuildTunnel1(class AIInstance *instance)
00062 {
00063   if (!AITunnel::_BuildTunnelRoad1()) {
00064     AIInstance::DoCommandReturn(instance);
00065     return;
00066   }
00067 
00068   /* This can never happen, as in test-mode this callback is never executed,
00069    *  and in execute-mode, the other callback is called. */
00070   NOT_REACHED();
00071 }
00072 
00073 /* static */ bool AITunnel::BuildTunnel(AIVehicle::VehicleType vehicle_type, TileIndex start)
00074 {
00075   EnforcePrecondition(false, ::IsValidTile(start));
00076   EnforcePrecondition(false, vehicle_type == AIVehicle::VT_RAIL || vehicle_type == AIVehicle::VT_ROAD);
00077   EnforcePrecondition(false, vehicle_type != AIVehicle::VT_RAIL || AIRail::IsRailTypeAvailable(AIRail::GetCurrentRailType()));
00078 
00079   uint type = 0;
00080   if (vehicle_type == AIVehicle::VT_ROAD) {
00081     type |= (TRANSPORT_ROAD << 8);
00082     type |= ::RoadTypeToRoadTypes((::RoadType)AIObject::GetRoadType());
00083   } else {
00084     type |= (TRANSPORT_RAIL << 8);
00085     type |= AIRail::GetCurrentRailType();
00086   }
00087 
00088   /* For rail we do nothing special */
00089   if (vehicle_type == AIVehicle::VT_RAIL) {
00090     return AIObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL);
00091   }
00092 
00093   AIObject::SetCallbackVariable(0, start);
00094   return AIObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, NULL, &_DoCommandReturnBuildTunnel1);
00095 }
00096 
00097 /* static */ bool AITunnel::_BuildTunnelRoad1()
00098 {
00099   /* Build the piece of road on the 'start' side of the tunnel */
00100   TileIndex end = AIObject::GetCallbackVariable(0);
00101   TileIndex start = AITunnel::GetOtherTunnelEnd(end);
00102 
00103   DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start);
00104   DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
00105 
00106   return AIObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &_DoCommandReturnBuildTunnel2);
00107 }
00108 
00109 /* static */ bool AITunnel::_BuildTunnelRoad2()
00110 {
00111   /* Build the piece of road on the 'end' side of the tunnel */
00112   TileIndex end = AIObject::GetCallbackVariable(0);
00113   TileIndex start = AITunnel::GetOtherTunnelEnd(end);
00114 
00115   DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start);
00116   DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
00117 
00118   return AIObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD);
00119 }
00120 
00121 /* static */ bool AITunnel::RemoveTunnel(TileIndex tile)
00122 {
00123   EnforcePrecondition(false, IsTunnelTile(tile));
00124 
00125   return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
00126 }