truelight@2381: /* $Id$ */ truelight@2381: truelight@2381: #include "../../stdafx.h" truelight@2381: #include "../../openttd.h" truelight@2381: #include "../../debug.h" truelight@2381: #include "../../functions.h" truelight@2381: #include "../../map.h" tron@3157: #include "../../road_map.h" truelight@2381: #include "../../tile.h" tron@3946: #include "../../vehicle.h" truelight@2381: #include "../../command.h" truelight@2381: #include "trolly.h" truelight@2381: #include "../../engine.h" truelight@2381: #include "../../station.h" truelight@2381: #include "../../variables.h" celestar@3359: #include "../../bridge.h" truelight@2682: #include "../ai.h" truelight@2381: truelight@2381: // Build HQ truelight@2381: // Params: truelight@2381: // tile : tile where HQ is going to be build truelight@2381: bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile) truelight@2381: { truelight@2682: if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ))) truelight@2381: return false; truelight@2682: AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ); truelight@2381: return true; truelight@2381: } truelight@2381: truelight@2381: truelight@2381: // Build station truelight@2381: // Params: truelight@2381: // type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station truelight@2381: // tile : tile where station is going to be build truelight@2381: // length : in case of AI_TRAIN: length of station truelight@2381: // numtracks : in case of AI_TRAIN: tracks of station truelight@2381: // direction : the direction of the station truelight@2381: // flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it) truelight@2381: int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag) truelight@2381: { truelight@2381: if (type == AI_TRAIN) truelight@2682: return AI_DoCommand(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION); truelight@2381: truelight@2381: if (type == AI_BUS) truelight@2682: return AI_DoCommand(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP); truelight@2381: truelight@2682: return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP); truelight@2381: } truelight@2381: truelight@2381: truelight@2381: // Builds a brdige. The second best out of the ones available for this player truelight@2381: // Params: truelight@2381: // tile_a : starting point truelight@2381: // tile_b : end point truelight@2381: // flag : flag passed to DoCommand truelight@2381: int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag) truelight@2381: { truelight@2381: int bridge_type, bridge_len, type, type2; truelight@2381: truelight@2381: // Find a good bridgetype (the best money can buy) truelight@2381: bridge_len = GetBridgeLength(tile_a, tile_b); truelight@2381: type = type2 = 0; truelight@2381: for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) { truelight@2381: if (CheckBridge_Stuff(bridge_type, bridge_len)) { truelight@2381: type2 = type; truelight@2381: type = bridge_type; truelight@2381: // We found two bridges, exit truelight@2381: if (type2 != 0) break; truelight@2381: } truelight@2381: } truelight@2381: // There is only one bridge that can be build.. truelight@2381: if (type2 == 0 && type != 0) type2 = type; truelight@2381: truelight@2381: // Now, simply, build the bridge! truelight@2381: if (p->ainew.tbt == AI_TRAIN) truelight@2682: return AI_DoCommand(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); truelight@2381: truelight@2682: return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); truelight@2381: } truelight@2381: truelight@2381: truelight@2381: // Build the route part by part truelight@2381: // Basicly what this function do, is build that amount of parts of the route truelight@2381: // that go in the same direction. It sets 'part' to the last part of the route builded. truelight@2381: // The return value is the cost for the builded parts truelight@2381: // truelight@2381: // Params: truelight@2381: // PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder truelight@2381: // part : Which part we need to build truelight@2381: // truelight@2381: // TODO: skip already builded road-pieces (e.g.: cityroad) truelight@2381: int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag) truelight@2381: { truelight@2381: int part = PathFinderInfo->position; truelight@2381: byte *route_extra = PathFinderInfo->route_extra; truelight@2381: TileIndex *route = PathFinderInfo->route; truelight@2381: int dir; truelight@2381: int old_dir = -1; truelight@2381: int cost = 0; truelight@2381: int res; truelight@2381: // We need to calculate the direction with the parent of the parent.. so we skip truelight@2381: // the first pieces and the last piece truelight@2381: if (part < 1) part = 1; truelight@2381: // When we are done, stop it truelight@2381: if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; } truelight@2381: truelight@2381: truelight@2381: if (PathFinderInfo->rail_or_road) { truelight@2381: // Tunnel code truelight@2381: if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) { truelight@2682: cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { truelight@2381: DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!"); truelight@2381: return 0; truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: // Bridge code truelight@2381: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { truelight@2381: cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { truelight@2381: DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!"); truelight@2381: return 0; truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: truelight@2381: // Build normal rail truelight@2381: // Keep it doing till we go an other way truelight@2381: if (route_extra[part-1] == 0 && route_extra[part] == 0) { truelight@2381: while (route_extra[part] == 0) { truelight@2381: // Get the current direction truelight@2381: dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]); truelight@2381: // Is it the same as the last one? truelight@2381: if (old_dir != -1 && old_dir != dir) break; truelight@2381: old_dir = dir; truelight@2381: // Build the tile truelight@2682: res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL); truelight@2381: if (CmdFailed(res)) { truelight@2381: // Problem.. let's just abort it all! truelight@2381: p->ainew.state = AI_STATE_NOTHING; truelight@2381: return 0; truelight@2381: } truelight@2381: cost += res; truelight@2381: // Go to the next tile truelight@2381: part++; truelight@2381: // Check if it is still in range.. truelight@2381: if (part >= PathFinderInfo->route_length - 1) break; truelight@2381: } truelight@2381: part--; truelight@2381: } truelight@2381: // We want to return the last position, so we go back one truelight@2381: PathFinderInfo->position = part; truelight@2381: } else { truelight@2381: // Tunnel code truelight@2381: if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) { truelight@2682: cost += AI_DoCommand(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { truelight@2381: DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!"); truelight@2381: return 0; truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: // Bridge code truelight@2381: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { truelight@2381: cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { truelight@2381: DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!"); truelight@2381: return 0; truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: truelight@2381: // Build normal road truelight@2381: // Keep it doing till we go an other way truelight@2381: // EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way truelight@2381: // it will wait till the vehicle is gone.. truelight@2381: if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) { truelight@2381: while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) { truelight@2381: // Get the current direction truelight@2381: dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]); truelight@2381: // Is it the same as the last one? truelight@2381: if (old_dir != -1 && old_dir != dir) break; truelight@2381: old_dir = dir; truelight@2381: // There is already some road, and it is a bridge.. don't build!!! truelight@2381: if (!IsTileType(route[part], MP_TUNNELBRIDGE)) { truelight@2381: // Build the tile truelight@2682: res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD); truelight@2381: // Currently, we ignore CMD_ERRORs! truelight@2381: if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) { truelight@2381: // Problem.. let's just abort it all! truelight@2381: DEBUG(ai,0)("Darn, the route could not be builded.. aborting!"); truelight@2381: p->ainew.state = AI_STATE_NOTHING; truelight@2381: return 0; truelight@2381: } truelight@2381: truelight@2381: if (!CmdFailed(res)) cost += res; truelight@2381: } truelight@2381: // Go to the next tile truelight@2381: part++; truelight@2381: // Check if it is still in range.. truelight@2381: if (part >= PathFinderInfo->route_length - 1) break; truelight@2381: } truelight@2381: part--; truelight@2381: // We want to return the last position, so we go back one truelight@2381: } truelight@2381: if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--; truelight@2381: PathFinderInfo->position = part; truelight@2381: } truelight@2381: truelight@2381: return cost; truelight@2381: } truelight@2381: truelight@2381: truelight@2381: // This functions tries to find the best vehicle for this type of cargo tron@3885: // It returns INVALID_ENGINE if not suitable engine is found tron@3885: EngineID AiNew_PickVehicle(Player *p) truelight@2381: { truelight@2381: if (p->ainew.tbt == AI_TRAIN) { truelight@2381: // Not supported yet tron@3885: return INVALID_ENGINE; truelight@2381: } else { tron@3885: EngineID start = _cargoc.ai_roadveh_start[p->ainew.cargo]; tron@3885: EngineID end = start + _cargoc.ai_roadveh_count[p->ainew.cargo]; tron@3885: EngineID i; truelight@2381: truelight@2381: // Let's check it backwards.. we simply want to best engine available.. tron@3885: for (i = end - 1; i >= start; i--) { tron@3887: const Engine* e = GetEngine(i); tron@3885: int32 ret; tron@3885: truelight@2381: // Is it availiable? truelight@2381: // Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY tron@3887: if (!HASBIT(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue; truelight@2381: // Can we build it? truelight@2682: ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH); tron@3885: if (!CmdFailed(ret)) return i; truelight@2381: } truelight@2381: // We did not find a vehicle :( tron@3885: return INVALID_ENGINE; truelight@2381: } truelight@2381: } truelight@2381: truelight@2381: tron@3946: void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2) tron@3946: { tron@3946: Player* p = GetPlayer(_current_player); tron@3946: tron@3946: if (success) { tron@3946: p->ainew.state = AI_STATE_GIVE_ORDERS; tron@3946: p->ainew.veh_id = _new_vehicle_id; tron@3946: } else { tron@3946: /* XXX this should be handled more gracefully */ tron@3946: p->ainew.state = AI_STATE_NOTHING; tron@3946: } tron@3946: } tron@3946: tron@3946: truelight@2381: // Builds the best vehicle possible truelight@2381: int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag) truelight@2381: { tron@3885: EngineID i = AiNew_PickVehicle(p); truelight@2381: tron@3885: if (i == INVALID_ENGINE) return CMD_ERROR; tron@2639: if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR; truelight@2381: tron@3946: if (flag & DC_EXEC) { tron@3946: return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI); tron@3946: } else { tron@3946: return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH); tron@3946: } truelight@2381: } truelight@2381: tron@3157: int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag) truelight@2381: { truelight@2381: int ret, ret2; truelight@2381: if (p->ainew.tbt == AI_TRAIN) truelight@2682: return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT); truelight@2381: truelight@2682: ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT); truelight@2381: if (CmdFailed(ret)) return ret; truelight@2381: // Try to build the road from the depot tron@3157: ret2 = AI_DoCommand(tile + TileOffsByDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD); truelight@2381: // If it fails, ignore it.. truelight@2381: if (CmdFailed(ret2)) return ret; truelight@2381: return ret + ret2; truelight@2381: }