truelight@2381: /* $Id$ */ truelight@2381: truelight@2381: #include "../../stdafx.h" truelight@2381: #include "../../openttd.h" truelight@2381: #include "../../debug.h" tron@3157: #include "../../road_map.h" rubidium@8116: #include "../../command_func.h" truelight@2381: #include "trolly.h" rubidium@8786: #include "../../engine_func.h" peter1138@9070: #include "../../engine_base.h" truelight@2381: #include "../../variables.h" celestar@3359: #include "../../bridge.h" rubidium@8144: #include "../../vehicle_func.h" rubidium@8144: #include "../../vehicle_base.h" rubidium@8254: #include "../../player_base.h" rubidium@8254: #include "../../player_func.h" truelight@2682: #include "../ai.h" smatz@8398: #include "../../tunnelbridge.h" smatz@8398: 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) rubidium@6943: CommandCost 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) rubidium@8785: return AI_DoCommand(tile, direction, ROADTYPES_ROAD << 2 | ROADSTOP_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP); truelight@2381: rubidium@8785: return AI_DoCommand(tile, direction, ROADTYPES_ROAD << 2 | ROADSTOP_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 rubidium@6943: CommandCost 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) smatz@8398: bridge_len = GetTunnelBridgeLength(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: } tron@4000: // There is only one bridge that can be built truelight@2381: if (type2 == 0 && type != 0) type2 = type; truelight@2381: truelight@2381: // Now, simply, build the bridge! rubidium@8229: if (_players_ainew[p->index].tbt == AI_TRAIN) { tron@4000: return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); tron@4000: } else { rubidium@6681: return AI_DoCommand(tile_a, tile_b, ((0x80 | ROADTYPES_ROAD) << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); tron@4000: } 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) rubidium@6943: CommandCost 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; rubidium@6950: CommandCost cost; rubidium@6943: CommandCost 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 tron@4000: if (part >= PathFinderInfo->route_length - 1) { tron@4000: PathFinderInfo->position = -2; rubidium@6950: return CommandCost(); tron@4000: } 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) { rubidium@6950: cost.AddCost(AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL)); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { Darkvater@5380: DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]); rubidium@6950: return CommandCost(); truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: // Bridge code truelight@2381: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { rubidium@6950: cost.AddCost(AiNew_Build_Bridge(p, route[part], route[part - 1], flag)); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { Darkvater@5380: DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part - 1]); rubidium@6950: return CommandCost(); 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 tron@4000: 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! rubidium@8229: _players_ainew[p->index].state = AI_STATE_NOTHING; rubidium@6950: return CommandCost(); truelight@2381: } rubidium@6950: cost.AddCost(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) { rubidium@6950: cost.AddCost(AI_DoCommand(route[part], 0x200 | ROADTYPES_ROAD, 0, flag, CMD_BUILD_TUNNEL)); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { Darkvater@5380: DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]); rubidium@6950: return CommandCost(); truelight@2381: } truelight@2381: return cost; truelight@2381: } truelight@2381: // Bridge code truelight@2381: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { rubidium@6950: cost.AddCost(AiNew_Build_Bridge(p, route[part], route[part + 1], flag)); truelight@2381: PathFinderInfo->position++; truelight@2381: // TODO: problems! truelight@2381: if (CmdFailed(cost)) { Darkvater@5380: DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part + 1]); rubidium@6950: return CommandCost(); 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 rubidium@7758: // EnsureNoVehicleOnGround 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.. rubidium@7758: if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicleOnGround(route[part]))) { rubidium@7758: while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicleOnGround(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! rubidium@7758: if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_ROAD) && !EnsureNoVehicleOnGround(route[part])) { truelight@2381: // Problem.. let's just abort it all! Darkvater@5380: DEBUG(ai, 0, "[BuidPath] route building failed at tile 0x%X, aborting", route[part]); rubidium@8229: _players_ainew[p->index].state = AI_STATE_NOTHING; rubidium@6950: return CommandCost(); truelight@2381: } truelight@2381: rubidium@6950: if (CmdSucceeded(res)) cost.AddCost(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: } rubidium@7758: if (!EnsureNoVehicleOnGround(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: { rubidium@8229: if (_players_ainew[p->index].tbt == AI_TRAIN) { truelight@2381: // Not supported yet tron@3885: return INVALID_ENGINE; truelight@2381: } else { peter1138@5029: EngineID best_veh_index = INVALID_ENGINE; peter1138@5029: int32 best_veh_rating = 0; peter1138@9070: const Engine *e; truelight@2381: peter1138@5030: /* Loop through all road vehicles */ peter1138@9070: FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { peter1138@9070: EngineID i = e->index; peter1138@9070: const RoadVehicleInfo *rvi = &e->u.road; tron@3885: peter1138@5016: /* Skip vehicles which can't take our cargo type */ rubidium@8229: if (rvi->cargo_type != _players_ainew[p->index].cargo && !CanRefitTo(i, _players_ainew[p->index].cargo)) continue; peter1138@5016: smatz@8388: /* Skip trams */ smatz@8388: if (HasBit(EngInfo(i)->misc_flags, EF_ROAD_TRAM)) continue; smatz@8388: truelight@2381: // Is it availiable? truelight@2381: // Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY skidd13@7928: if (!HasBit(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue; peter1138@5029: peter1138@5029: /* Rate and compare the engine by speed & capacity */ peter1138@8389: int rating = rvi->max_speed * rvi->capacity; peter1138@5029: if (rating <= best_veh_rating) continue; peter1138@5029: truelight@2381: // Can we build it? peter1138@8389: CommandCost ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH); peter1138@5029: if (CmdFailed(ret)) continue; peter1138@5029: peter1138@5029: best_veh_rating = rating; peter1138@5029: best_veh_index = i; truelight@2381: } peter1138@5029: peter1138@5029: return best_veh_index; 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) { rubidium@8229: _players_ainew[p->index].state = AI_STATE_GIVE_ORDERS; rubidium@8229: _players_ainew[p->index].veh_id = _new_vehicle_id; peter1138@5031: rubidium@8229: if (GetVehicle(_players_ainew[p->index].veh_id)->cargo_type != _players_ainew[p->index].cargo) { peter1138@5031: /* Cargo type doesn't match, so refit it */ rubidium@8229: if (CmdFailed(DoCommand(tile, _players_ainew[p->index].veh_id, _players_ainew[p->index].cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) { peter1138@5031: /* Refit failed, so sell the vehicle */ rubidium@8229: DoCommand(tile, _players_ainew[p->index].veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH); rubidium@8229: _players_ainew[p->index].state = AI_STATE_NOTHING; peter1138@5031: } peter1138@5031: } tron@3946: } else { tron@3946: /* XXX this should be handled more gracefully */ rubidium@8229: _players_ainew[p->index].state = AI_STATE_NOTHING; tron@3946: } tron@3946: } tron@3946: tron@3946: truelight@2381: // Builds the best vehicle possible rubidium@6943: CommandCost 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; rubidium@8229: if (_players_ainew[p->index].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: rubidium@6943: CommandCost AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag) truelight@2381: { rubidium@6943: CommandCost ret, ret2; rubidium@8229: if (_players_ainew[p->index].tbt == AI_TRAIN) { truelight@2682: return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT); tron@4077: } else { tron@4077: ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT); rubidium@6950: if (CmdFailed(ret2)) return ret; tron@4077: // Try to build the road from the depot Darkvater@4559: ret2 = AI_DoCommand(tile + TileOffsByDiagDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD); tron@4077: // If it fails, ignore it.. tron@4077: if (CmdFailed(ret2)) return ret; rubidium@6950: ret.AddCost(ret2); rubidium@6950: return ret; tron@4077: } truelight@2381: }