tron@2186: /* $Id$ */ tron@2186: truelight@2381: #include "../../stdafx.h" truelight@2381: #include "../../openttd.h" truelight@2381: #include "../../debug.h" tron@3157: #include "../../road_map.h" tron@3946: #include "../../vehicle.h" rubidium@8612: #include "../../command_func.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@110: truelight@110: // Build HQ truelight@110: // Params: truelight@110: // tile : tile where HQ is going to be build tron@1977: bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile) tron@1977: { truelight@2682: if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ))) truelight@110: return false; truelight@2682: AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ); truelight@110: return true; truelight@110: } truelight@110: tron@2366: truelight@110: // Build station truelight@110: // Params: truelight@110: // type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station truelight@110: // tile : tile where station is going to be build truelight@110: // length : in case of AI_TRAIN: length of station truelight@110: // numtracks : in case of AI_TRAIN: tracks of station truelight@110: // direction : the direction of the station truelight@110: // flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it) rubidium@7439: CommandCost AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag) tron@1977: { truelight@110: 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); Darkvater@1713: Darkvater@1713: if (type == AI_BUS) rubidium@7177: return AI_DoCommand(tile, direction, ROADTYPES_ROAD << 2 | RoadStop::BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP); Darkvater@1713: rubidium@7177: return AI_DoCommand(tile, direction, ROADTYPES_ROAD << 2 | RoadStop::TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP); truelight@110: } truelight@110: tron@2366: truelight@110: // Builds a brdige. The second best out of the ones available for this player truelight@110: // Params: truelight@110: // tile_a : starting point truelight@110: // tile_b : end point truelight@110: // flag : flag passed to DoCommand rubidium@7439: CommandCost AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag) tron@1977: { truelight@110: int bridge_type, bridge_len, type, type2; truelight@110: truelight@110: // Find a good bridgetype (the best money can buy) truelight@110: bridge_len = GetBridgeLength(tile_a, tile_b); truelight@110: type = type2 = 0; truelight@110: for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) { truelight@110: if (CheckBridge_Stuff(bridge_type, bridge_len)) { truelight@110: type2 = type; truelight@110: type = bridge_type; truelight@110: // We found two bridges, exit tron@2366: if (type2 != 0) break; truelight@110: } truelight@110: } tron@4000: // There is only one bridge that can be built truelight@110: if (type2 == 0 && type != 0) type2 = type; truelight@110: truelight@110: // Now, simply, build the bridge! tron@4000: if (p->ainew.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@7177: return AI_DoCommand(tile_a, tile_b, ((0x80 | ROADTYPES_ROAD) << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); tron@4000: } truelight@110: } truelight@110: truelight@110: truelight@110: // Build the route part by part truelight@110: // Basicly what this function do, is build that amount of parts of the route truelight@110: // that go in the same direction. It sets 'part' to the last part of the route builded. truelight@110: // The return value is the cost for the builded parts truelight@110: // truelight@110: // Params: truelight@110: // PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder truelight@110: // part : Which part we need to build truelight@110: // truelight@110: // TODO: skip already builded road-pieces (e.g.: cityroad) rubidium@7439: CommandCost AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag) tron@2366: { tron@2366: int part = PathFinderInfo->position; truelight@110: byte *route_extra = PathFinderInfo->route_extra; truelight@110: TileIndex *route = PathFinderInfo->route; truelight@110: int dir; truelight@110: int old_dir = -1; rubidium@7446: CommandCost cost; rubidium@7439: CommandCost res; truelight@110: // We need to calculate the direction with the parent of the parent.. so we skip truelight@110: // the first pieces and the last piece truelight@110: if (part < 1) part = 1; truelight@110: // When we are done, stop it tron@4000: if (part >= PathFinderInfo->route_length - 1) { tron@4000: PathFinderInfo->position = -2; rubidium@7446: return CommandCost(); tron@4000: } truelight@193: truelight@193: truelight@110: if (PathFinderInfo->rail_or_road) { truelight@110: // Tunnel code tron@2366: if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) { rubidium@7446: cost.AddCost(AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL)); tron@2366: PathFinderInfo->position++; tron@2366: // TODO: problems! tron@2366: if (CmdFailed(cost)) { Darkvater@5568: DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]); rubidium@7446: return CommandCost(); tron@2366: } tron@2366: return cost; tron@2366: } tron@2366: // Bridge code tron@2366: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { rubidium@7446: cost.AddCost(AiNew_Build_Bridge(p, route[part], route[part - 1], flag)); tron@2366: PathFinderInfo->position++; tron@2366: // TODO: problems! tron@2366: if (CmdFailed(cost)) { Darkvater@5568: DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part - 1]); rubidium@7446: return CommandCost(); tron@2366: } tron@2366: return cost; tron@2366: } truelight@110: tron@2366: // Build normal rail tron@2366: // Keep it doing till we go an other way tron@4000: if (route_extra[part - 1] == 0 && route_extra[part] == 0) { tron@2366: while (route_extra[part] == 0) { tron@2366: // Get the current direction tron@2366: dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]); tron@2366: // Is it the same as the last one? tron@2366: if (old_dir != -1 && old_dir != dir) break; tron@2366: old_dir = dir; tron@2366: // Build the tile truelight@2682: res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL); tron@2366: if (CmdFailed(res)) { tron@2366: // Problem.. let's just abort it all! tron@2366: p->ainew.state = AI_STATE_NOTHING; rubidium@7446: return CommandCost(); tron@2366: } rubidium@7446: cost.AddCost(res); tron@2366: // Go to the next tile tron@2366: part++; tron@2366: // Check if it is still in range.. tron@2366: if (part >= PathFinderInfo->route_length - 1) break; tron@2366: } tron@2366: part--; tron@2366: } tron@2366: // We want to return the last position, so we go back one tron@2366: PathFinderInfo->position = part; tron@2366: } else { truelight@110: // Tunnel code tron@2366: if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) { rubidium@7446: cost.AddCost(AI_DoCommand(route[part], 0x200 | ROADTYPES_ROAD, 0, flag, CMD_BUILD_TUNNEL)); tron@2366: PathFinderInfo->position++; tron@2366: // TODO: problems! tron@2366: if (CmdFailed(cost)) { Darkvater@5568: DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]); rubidium@7446: return CommandCost(); tron@2366: } tron@2366: return cost; tron@2366: } tron@2366: // Bridge code tron@2366: if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) { rubidium@7446: cost.AddCost(AiNew_Build_Bridge(p, route[part], route[part + 1], flag)); tron@2366: PathFinderInfo->position++; tron@2366: // TODO: problems! tron@2366: if (CmdFailed(cost)) { Darkvater@5568: DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part + 1]); rubidium@7446: return CommandCost(); tron@2366: } tron@2366: return cost; tron@2366: } truelight@110: tron@2366: // Build normal road tron@2366: // Keep it doing till we go an other way rubidium@8254: // EnsureNoVehicleOnGround makes sure we don't build on a tile where a vehicle is. This way tron@2366: // it will wait till the vehicle is gone.. rubidium@8254: if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicleOnGround(route[part]))) { rubidium@8254: while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicleOnGround(route[part]))) { tron@2366: // Get the current direction tron@2366: dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]); tron@2366: // Is it the same as the last one? tron@2366: if (old_dir != -1 && old_dir != dir) break; tron@2366: old_dir = dir; tron@2366: // There is already some road, and it is a bridge.. don't build!!! tron@2366: if (!IsTileType(route[part], MP_TUNNELBRIDGE)) { tron@2366: // Build the tile truelight@2682: res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD); tron@2366: // Currently, we ignore CMD_ERRORs! rubidium@8254: if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_ROAD) && !EnsureNoVehicleOnGround(route[part])) { tron@2366: // Problem.. let's just abort it all! Darkvater@5568: DEBUG(ai, 0, "[BuidPath] route building failed at tile 0x%X, aborting", route[part]); tron@2366: p->ainew.state = AI_STATE_NOTHING; rubidium@7446: return CommandCost(); tron@2366: } Darkvater@1713: rubidium@7446: if (CmdSucceeded(res)) cost.AddCost(res); tron@2366: } tron@2366: // Go to the next tile tron@2366: part++; tron@2366: // Check if it is still in range.. tron@2366: if (part >= PathFinderInfo->route_length - 1) break; tron@2366: } tron@2366: part--; tron@2366: // We want to return the last position, so we go back one tron@2366: } rubidium@8254: if (!EnsureNoVehicleOnGround(route[part]) && flag == DC_EXEC) part--; tron@2366: PathFinderInfo->position = part; tron@2366: } truelight@193: tron@2366: return cost; truelight@110: } truelight@110: tron@2366: truelight@110: // 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) tron@2366: { tron@2366: if (p->ainew.tbt == AI_TRAIN) { tron@2366: // Not supported yet tron@3885: return INVALID_ENGINE; tron@2366: } else { peter1138@5029: EngineID best_veh_index = INVALID_ENGINE; peter1138@5029: int32 best_veh_rating = 0; peter1138@5016: EngineID start = ROAD_ENGINES_INDEX; peter1138@5016: EngineID end = ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; tron@3885: EngineID i; truelight@110: peter1138@5030: /* Loop through all road vehicles */ peter1138@5030: for (i = start; i != end; i++) { peter1138@5029: const RoadVehicleInfo *rvi = RoadVehInfo(i); tron@3887: const Engine* e = GetEngine(i); peter1138@5029: int32 rating; rubidium@7439: CommandCost ret; tron@3885: peter1138@5016: /* Skip vehicles which can't take our cargo type */ peter1138@5031: if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue; peter1138@5016: tron@2366: // Is it availiable? tron@2366: // Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY skidd13@8424: 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@5029: rating = rvi->max_speed * rvi->capacity; peter1138@5029: if (rating <= best_veh_rating) continue; peter1138@5029: tron@2366: // Can we build it? truelight@2682: 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; tron@2366: } peter1138@5029: peter1138@5029: return best_veh_index; tron@2366: } truelight@110: } truelight@110: tron@2366: 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; peter1138@5031: peter1138@5031: if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) { peter1138@5031: /* Cargo type doesn't match, so refit it */ peter1138@5031: if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) { peter1138@5031: /* Refit failed, so sell the vehicle */ peter1138@5031: DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH); peter1138@5031: p->ainew.state = AI_STATE_NOTHING; peter1138@5031: } peter1138@5031: } 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@110: // Builds the best vehicle possible rubidium@7439: CommandCost AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag) tron@1977: { tron@3885: EngineID i = AiNew_PickVehicle(p); truelight@193: tron@3885: if (i == INVALID_ENGINE) return CMD_ERROR; tron@2639: if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR; Darkvater@1713: 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@110: } truelight@110: rubidium@7439: CommandCost AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag) Darkvater@1713: { rubidium@7439: CommandCost ret, ret2; tron@4077: if (p->ainew.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@7446: 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@7446: ret.AddCost(ret2); rubidium@7446: return ret; tron@4077: } truelight@110: }