(svn r10611) [NoAI] -Fix: improved FindBestXXX, it now finds the fastest, biggest vehicle available
[NoAI] -Change [API]: FindBestXXX now takes max_cost as 3rd param, to find a vehicle below a given treshhold
/* $Id$ */
/** @file ai_vehicle.cpp handles the functions of the AIVehicle class */
#include "ai_vehicle.hpp"
#include "ai_cargo.hpp"
#include "../../command.h"
#include "../../vehicle.h"
#include "../../depot.h"
#include "../../engine.h"
#include "../../player.h"
#include "../../aircraft.h"
/* static */ bool AIVehicle::IsValidEngine(EngineID engine_id)
{
return ::IsEngineIndex(engine_id); // TODO: implement 'can I build this engine check'
}
/* static */ bool AIVehicle::IsValidVehicle(VehicleID vehicle_id)
{
return ::IsValidVehicleID(vehicle_id) && ::GetVehicle(vehicle_id)->owner == _current_player;
}
EngineID AIVehicle::FindBestVehicle(CargoID cargo, uint8 min_reliability, VehicleType veh_type, uint max_cost)
{
if (!AICargo::IsValidCargo(cargo) || min_reliability > 100) return INVALID_ENGINE;
EngineID best_engine = INVALID_ENGINE;
EngineID engine_id;
uint best_cargo = 0;
uint best_speed = 0;
FOR_ALL_ENGINEIDS_OF_TYPE(engine_id, veh_type) {
/* Is the vehicle available for this player */
if (IsEngineBuildable(engine_id, veh_type, _current_player) &&
GetEngine(engine_id)->reliability * 100 >= min_reliability << 16) {
uint cspeed, ccargo;
/* Can this vehicle handle the cargo requested? */
switch (veh_type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = RoadVehInfo(engine_id);
if (vi->cargo_type != cargo && !CanRefitTo(engine_id, cargo)) continue;
if ((_price.roadveh_base >> 3) * vi->base_cost >> 5 > max_cost) continue;
ccargo = vi->capacity;
cspeed = vi->max_speed;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = RailVehInfo(engine_id);
if (vi->cargo_type != cargo && !CanRefitTo(engine_id, cargo)) continue;
if ((_price.build_railvehicle >> 3) * vi->base_cost >> 5 > max_cost) continue;
ccargo = vi->capacity;
cspeed = vi->max_speed;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ShipVehInfo(engine_id);
if (vi->cargo_type != cargo && !CanRefitTo(engine_id, cargo)) continue;
if ((_price.ship_base >> 3) * vi->base_cost >> 5 > max_cost) continue;
ccargo = vi->capacity;
cspeed = vi->max_speed;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = AircraftVehInfo(engine_id);
if (CT_PASSENGERS != cargo && CT_MAIL != cargo && !CanRefitTo(engine_id, cargo)) continue;
if ((_price.aircraft_base >> 3) * vi->base_cost >> 5 > max_cost) continue;
ccargo = vi->passenger_capacity;
cspeed = vi->max_speed;
} break;
default: NOT_REACHED();
}
/* Sort on speed, than on cargo, than on order of engine-array */
if (best_speed > cspeed) continue;
if (best_cargo > ccargo) continue;
best_engine = engine_id;
best_speed = cspeed;
best_cargo = ccargo;
}
}
return best_engine;
}
EngineID AIVehicle::FindBestRoadVehicle(CargoID cargo, uint8 min_reliability, uint max_cost)
{
return this->FindBestVehicle(cargo, min_reliability, VEH_ROAD, max_cost);
}
EngineID AIVehicle::FindBestAircraftVehicle(CargoID cargo, uint8 min_reliability, uint max_cost)
{
return this->FindBestVehicle(cargo, min_reliability, VEH_AIRCRAFT, max_cost);
}
VehicleID AIVehicle::BuildVehicle(TileIndex depot, EngineID engine_id)
{
if (!this->IsValidEngine(engine_id)) return false;
/* Reset the internal NewVehicleID in case we are in TestMode */
AIObject::SetNewVehicleID(0);
bool ret;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: ret = this->DoCommand(depot, engine_id, 0, CMD_BUILD_ROAD_VEH); break;
case VEH_TRAIN: ret = this->DoCommand(depot, engine_id, 0, CMD_BUILD_RAIL_VEHICLE); break;
case VEH_SHIP: ret = this->DoCommand(depot, engine_id, 0, CMD_BUILD_SHIP); break;
case VEH_AIRCRAFT: ret = this->DoCommand(depot, engine_id, 0, CMD_BUILD_AIRCRAFT); break;
default: NOT_REACHED(); return INVALID_VEHICLE;
}
return ret ? AIObject::GetNewVehicleID() : INVALID_VEHICLE;
}
VehicleID AIVehicle::CloneVehicle(TileIndex depot, VehicleID vehicle_id, bool share_orders)
{
if (!this->IsValidVehicle(vehicle_id)) return false;
/* Reset the internal NewVehicleID in case we are in TestMode */
AIObject::SetNewVehicleID(0);
bool ret = this->DoCommand(depot, vehicle_id, share_orders, CMD_CLONE_VEHICLE);
return ret ? AIObject::GetNewVehicleID() : INVALID_VEHICLE;
}
bool AIVehicle::RefitVehicle(VehicleID vehicle_id, CargoID cargo)
{
if (!this->IsValidVehicle(vehicle_id) || !AICargo::IsValidCargo(cargo)) return false;
switch (::GetVehicle(vehicle_id)->type) {
case VEH_ROAD: return this->DoCommand(0, vehicle_id, cargo, CMD_REFIT_ROAD_VEH);
case VEH_TRAIN: return this->DoCommand(0, vehicle_id, cargo, CMD_REFIT_RAIL_VEHICLE);
case VEH_SHIP: return this->DoCommand(0, vehicle_id, cargo, CMD_REFIT_SHIP);
case VEH_AIRCRAFT: return this->DoCommand(0, vehicle_id, cargo, CMD_REFIT_AIRCRAFT);
default: return false;
}
}
bool AIVehicle::SellVehicle(VehicleID vehicle_id)
{
if (!this->IsValidVehicle(vehicle_id)) return false;
switch (::GetVehicle(vehicle_id)->type) {
case VEH_ROAD: return this->DoCommand(0, vehicle_id, 0, CMD_SELL_ROAD_VEH);
case VEH_TRAIN: return this->DoCommand(0, vehicle_id, 0, CMD_SELL_RAIL_WAGON);
case VEH_SHIP: return this->DoCommand(0, vehicle_id, 0, CMD_SELL_SHIP);
case VEH_AIRCRAFT: return this->DoCommand(0, vehicle_id, 0, CMD_SELL_AIRCRAFT);
default: return false;
}
}
bool AIVehicle::SendVehicleToDepot(VehicleID vehicle_id)
{
if (!this->IsValidVehicle(vehicle_id)) return false;
switch (::GetVehicle(vehicle_id)->type) {
case VEH_ROAD: return this->DoCommand(0, vehicle_id, 0, CMD_SEND_ROADVEH_TO_DEPOT);
case VEH_TRAIN: return this->DoCommand(0, vehicle_id, 0, CMD_SEND_TRAIN_TO_DEPOT);
case VEH_SHIP: return this->DoCommand(0, vehicle_id, 0, CMD_SEND_SHIP_TO_DEPOT);
case VEH_AIRCRAFT: return this->DoCommand(0, vehicle_id, 0, CMD_SEND_AIRCRAFT_TO_HANGAR);
default: return false;
}
}
bool AIVehicle::StartStopVehicle(VehicleID vehicle_id)
{
if (!this->IsValidVehicle(vehicle_id)) return false;
switch (::GetVehicle(vehicle_id)->type) {
case VEH_ROAD: return this->DoCommand(0, vehicle_id, 0, CMD_START_STOP_ROADVEH);
case VEH_TRAIN: return this->DoCommand(0, vehicle_id, 0, CMD_START_STOP_TRAIN);
case VEH_SHIP: return this->DoCommand(0, vehicle_id, 0, CMD_START_STOP_SHIP);
case VEH_AIRCRAFT: return this->DoCommand(0, vehicle_id, 0, CMD_START_STOP_AIRCRAFT);
default: return false;
}
}
bool AIVehicle::SkipVehicleOrder(VehicleID vehicle_id)
{
if (!this->IsValidVehicle(vehicle_id)) return false;
return this->DoCommand(0, vehicle_id, 0, CMD_SKIP_TO_ORDER);
}
/* static */ TileIndex AIVehicle::GetLocation(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return INVALID_TILE;
return ::GetVehicle(vehicle_id)->tile;
}
/* static */ EngineID AIVehicle::GetEngineType(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
return ::GetVehicle(vehicle_id)->engine_type;
}
/* static */ int32 AIVehicle::GetUnitNumber(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->unitnumber;
}
/* static */ int32 AIVehicle::GetAge(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->age;
}
/* static */ int32 AIVehicle::GetMaxAge(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->max_age;
}
/* static */ int32 AIVehicle::GetAgeLeft(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->max_age - ::GetVehicle(vehicle_id)->age;
}
/* static */ int32 AIVehicle::GetProfitThisYear(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->profit_this_year;
}
/* static */ int32 AIVehicle::GetProfitLastYear(VehicleID vehicle_id)
{
if (!AIVehicle::IsValidVehicle(vehicle_id)) return -1;
return ::GetVehicle(vehicle_id)->profit_last_year;
}