1
0
Fork 0

(svn r146) -Fix [AI]: Tunnel/bridge bug

-Fix [AI]: Minor problems
-Add [AI]: Profit check (if not making enough money, vehicles are sold)
release/0.4.5
truelight 2004-08-31 16:12:52 +00:00
parent a7dd461672
commit 5eba928cb8
6 changed files with 250 additions and 103 deletions

32
ai.h
View File

@ -10,7 +10,7 @@
* This can also alter the AI in a negative way. I will never claim these settings * This can also alter the AI in a negative way. I will never claim these settings
* are perfect, but don't change them if you don't know what the effect is. * are perfect, but don't change them if you don't know what the effect is.
*/ */
// How many times it the H multiplied. The higher, the more it will go straight to the // How many times it the H multiplied. The higher, the more it will go straight to the
// end point. The lower, how more it will find the route with the lowest cost. // end point. The lower, how more it will find the route with the lowest cost.
// also: the lower, the longer it takes before route is calculated.. // also: the lower, the longer it takes before route is calculated..
@ -136,11 +136,29 @@
// How many thick between building 2 vehicles // How many thick between building 2 vehicles
#define AI_BUILD_VEHICLE_TIME_BETWEEN 74 #define AI_BUILD_VEHICLE_TIME_BETWEEN 74
// How many days must there between vehicle checks
// The more often, the less non-money-making lines there will be
// but the unfair it may seem to a human player
#define AI_DAYS_BETWEEN_VEHICLE_CHECKS 30
// How money profit does a vehicle needs to make to stay in order
// This is the profit of this year + profit of last year
// But also for vehicles that are just one year old. In other words:
// Vehicles of 2 years do easier meet this setting then vehicles
// of one year. This is a very good thing. New vehicles are filtered,
// while old vehicles stay longer, because we do get less in return.
#define AI_MINIMUM_ROUTE_PROFIT 1000
// A vehicle is considered lost when he his cargo is more then 180 days old
#define AI_VEHICLE_LOST_DAYS 180
// How many times may the AI try to find a route before it gives up
#define AI_MAX_TRIES_FOR_SAME_ROUTE 8
/* /*
* End of defines * End of defines
*/ */
// This stops 90degrees curves // This stops 90degrees curves
static const byte _illegal_curves[6] = { static const byte _illegal_curves[6] = {
255, 255, // Horz and vert, don't have the effect 255, 255, // Horz and vert, don't have the effect
@ -174,6 +192,7 @@ enum {
AI_STATE_GIVE_ORDERS, AI_STATE_GIVE_ORDERS,
AI_STATE_START_VEHICLE, AI_STATE_START_VEHICLE,
AI_STATE_REPAY_MONEY, AI_STATE_REPAY_MONEY,
AI_STATE_CHECK_ALL_VEHICLES,
AI_STATE_ACTION_DONE, AI_STATE_ACTION_DONE,
AI_STATE_STOP, // Temporary function to stop the AI AI_STATE_STOP, // Temporary function to stop the AI
}; };
@ -190,6 +209,7 @@ enum {
AI_ACTION_BUS_ROUTE, AI_ACTION_BUS_ROUTE,
AI_ACTION_TRUCK_ROUTE, AI_ACTION_TRUCK_ROUTE,
AI_ACTION_REPAY_LOAN, AI_ACTION_REPAY_LOAN,
AI_ACTION_CHECK_ALL_VEHICLES,
}; };
// Used for from_type/to_type // Used for from_type/to_type
@ -199,6 +219,12 @@ enum {
AI_INDUSTRY, AI_INDUSTRY,
}; };
// Flags for in the vehicle
enum {
AI_VEHICLEFLAG_SELL = 1,
// Remember, flags must be in power of 2
};
#define AI_NO_CARGO 0xFF // Means that there is no cargo defined yet (used for industry) #define AI_NO_CARGO 0xFF // Means that there is no cargo defined yet (used for industry)
#define AI_NEED_CARGO 0xFE // Used when the AI needs to find out a cargo for the route #define AI_NEED_CARGO 0xFE // Used when the AI needs to find out a cargo for the route
#define AI_STATION_RANGE TILE_XY(TILE_X_MAX, TILE_Y_MAX) #define AI_STATION_RANGE TILE_XY(TILE_X_MAX, TILE_Y_MAX)
@ -229,6 +255,8 @@ void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo
int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c); int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c);
int AiNew_GetRoadDirection(uint tile_a, uint tile_b, uint tile_c); int AiNew_GetRoadDirection(uint tile_a, uint tile_b, uint tile_c);
int AiNew_GetDirection(uint tile_a, uint tile_b); int AiNew_GetDirection(uint tile_a, uint tile_b);
bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag);
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v);
// ai_build.c // ai_build.c
bool AiNew_Build_CompanyHQ(Player *p, uint tile); bool AiNew_Build_CompanyHQ(Player *p, uint tile);

View File

@ -177,7 +177,7 @@ int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte fla
// Build the tile // Build the tile
res = DoCommandByTile(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD); res = DoCommandByTile(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
// Currently, we ignore CMD_ERRORs! // Currently, we ignore CMD_ERRORs!
if (res == CMD_ERROR && !IS_TILETYPE(route[part], MP_STREET) && (flag == DC_EXEC && !EnsureNoVehicle(route[part]))) { if (res == CMD_ERROR && flag == DC_EXEC && !IS_TILETYPE(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
// Problem.. let's just abort it all! // Problem.. let's just abort it all!
DEBUG(ai,0)("Darn, the route could not be builded.. aborting!"); DEBUG(ai,0)("Darn, the route could not be builded.. aborting!");
p->ainew.state = AI_STATE_NOTHING; p->ainew.state = AI_STATE_NOTHING;

224
ai_new.c
View File

@ -31,7 +31,7 @@ static void AiNew_State_FirstTime(Player *p) {
// With this assert, that problem can never happen. // With this assert, that problem can never happen.
assert(p->ainew.state == AI_STATE_FIRST_TIME); assert(p->ainew.state == AI_STATE_FIRST_TIME);
// We first have to init some things // We first have to init some things
if (_current_player == 1) { if (_current_player == 1) {
ShowErrorMessage(-1, TEMP_AI_IN_PROGRESS, 0, 0); ShowErrorMessage(-1, TEMP_AI_IN_PROGRESS, 0, 0);
} }
@ -44,8 +44,9 @@ static void AiNew_State_FirstTime(Player *p) {
p->ainew.path_info.end_tile_tl = 0; p->ainew.path_info.end_tile_tl = 0;
p->ainew.path_info.end_tile_br = 0; p->ainew.path_info.end_tile_br = 0;
p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info); p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info);
p->ainew.idle = 0; p->ainew.idle = 0;
p->ainew.last_vehiclecheck_date = _date;
// We ALWAYS start with a bus route.. just some basic money ;) // We ALWAYS start with a bus route.. just some basic money ;)
p->ainew.action = AI_ACTION_BUS_ROUTE; p->ainew.action = AI_ACTION_BUS_ROUTE;
@ -92,19 +93,23 @@ static void AiNew_State_WakeUp(Player *p) {
// so we do not change any status // so we do not change any status
return; return;
} }
money = p->player_money - AI_MINIMUM_MONEY; money = p->player_money - AI_MINIMUM_MONEY;
// Let's pick an action! // Let's pick an action!
if (p->ainew.action == AI_ACTION_NONE) { if (p->ainew.action == AI_ACTION_NONE) {
c = Random() & 0xFF; c = Random() & 0xFF;
if (p->current_loan > 0 && p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN && if (p->current_loan > 0 && p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN &&
c < 10) { c < 10) {
p->ainew.action = AI_ACTION_REPAY_LOAN; p->ainew.action = AI_ACTION_REPAY_LOAN;
} else if (p->ainew.last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) {
// Check all vehicles once in a while
p->ainew.action = AI_ACTION_CHECK_ALL_VEHICLES;
p->ainew.last_vehiclecheck_date = _date;
} else if (c < 100 && !_patches.ai_disable_veh_roadveh) { } else if (c < 100 && !_patches.ai_disable_veh_roadveh) {
// Do we have any spots for road-vehicles left open? // Do we have any spots for road-vehicles left open?
if (GetFreeUnitNumber(VEH_Road) <= _patches.max_roadveh) { if (GetFreeUnitNumber(VEH_Road) <= _patches.max_roadveh) {
if (c < 65) p->ainew.action = AI_ACTION_TRUCK_ROUTE; if (c < 85) p->ainew.action = AI_ACTION_TRUCK_ROUTE;
else p->ainew.action = AI_ACTION_BUS_ROUTE; else p->ainew.action = AI_ACTION_BUS_ROUTE;
} }
}/* else if (c < 200 && !_patches.ai_disable_veh_train) { }/* else if (c < 200 && !_patches.ai_disable_veh_train) {
@ -112,14 +117,21 @@ static void AiNew_State_WakeUp(Player *p) {
p->ainew.action = AI_ACTION_TRAIN_ROUTE; p->ainew.action = AI_ACTION_TRAIN_ROUTE;
} }
}*/ }*/
p->ainew.counter = 0;
} }
if (p->ainew.counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) {
p->ainew.action = AI_ACTION_NONE;
return;
}
if (_patches.ai_disable_veh_roadveh && ( if (_patches.ai_disable_veh_roadveh && (
p->ainew.action == AI_ACTION_BUS_ROUTE || p->ainew.action == AI_ACTION_TRUCK_ROUTE)) { p->ainew.action == AI_ACTION_BUS_ROUTE || p->ainew.action == AI_ACTION_TRUCK_ROUTE)) {
p->ainew.action = AI_ACTION_NONE; p->ainew.action = AI_ACTION_NONE;
return; return;
} }
if (_patches.ai_disable_veh_roadveh && ( if (_patches.ai_disable_veh_roadveh && (
p->ainew.action == AI_ACTION_BUS_ROUTE || p->ainew.action == AI_ACTION_TRUCK_ROUTE)) { p->ainew.action == AI_ACTION_BUS_ROUTE || p->ainew.action == AI_ACTION_TRUCK_ROUTE)) {
p->ainew.action = AI_ACTION_NONE; p->ainew.action = AI_ACTION_NONE;
@ -131,7 +143,12 @@ static void AiNew_State_WakeUp(Player *p) {
p->ainew.state = AI_STATE_REPAY_MONEY; p->ainew.state = AI_STATE_REPAY_MONEY;
return; return;
} }
if (p->ainew.action == AI_ACTION_CHECK_ALL_VEHICLES) {
p->ainew.state = AI_STATE_CHECK_ALL_VEHICLES;
return;
}
// It is useless to start finding a route if we don't have enough money // It is useless to start finding a route if we don't have enough money
// to build the route anyway.. // to build the route anyway..
if (p->ainew.action == AI_ACTION_BUS_ROUTE && money > AI_MINIMUM_BUS_ROUTE_MONEY) { if (p->ainew.action == AI_ACTION_BUS_ROUTE && money > AI_MINIMUM_BUS_ROUTE_MONEY) {
@ -155,7 +172,7 @@ static void AiNew_State_WakeUp(Player *p) {
p->ainew.tbt = AI_TRUCK; p->ainew.tbt = AI_TRUCK;
return; return;
} }
p->ainew.state = AI_STATE_NOTHING; p->ainew.state = AI_STATE_NOTHING;
} }
@ -171,16 +188,16 @@ static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type) {
Station *st; Station *st;
int count = 0; int count = 0;
int j = 0; int j = 0;
// We don't like roadconstructions, don't even true such a city // We don't like roadconstructions, don't even true such a city
if (t->road_build_months != 0) return false; if (t->road_build_months != 0) return false;
// Check if the rating in a city is high enough // Check if the rating in a city is high enough
// If not, take a chance if we want to continue // If not, take a chance if we want to continue
if (t->ratings[_current_player] < 0 && CHANCE16(1,4)) return false; if (t->ratings[_current_player] < 0 && CHANCE16(1,4)) return false;
if (t->max_pass - t->act_pass < AI_CHECKCITY_NEEDED_CARGO && !CHANCE16(1,AI_CHECKCITY_CITY_CHANCE)) return false; if (t->max_pass - t->act_pass < AI_CHECKCITY_NEEDED_CARGO && !CHANCE16(1,AI_CHECKCITY_CITY_CHANCE)) return false;
// Check if we have build a station in this town the last 6 months // Check if we have build a station in this town the last 6 months
// else we don't do it. This is done, because stat updates can be slow // else we don't do it. This is done, because stat updates can be slow
// and sometimes it takes up to 4 months before the stats are corectly. // and sometimes it takes up to 4 months before the stats are corectly.
@ -219,12 +236,12 @@ static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type) {
return false; return false;
} }
} }
// We are about to add one... // We are about to add one...
count++; count++;
// Check if we the city can provide enough cargo for this amount of stations.. // Check if we the city can provide enough cargo for this amount of stations..
if (count * AI_CHECKCITY_CARGO_PER_STATION > t->max_pass) return false; if (count * AI_CHECKCITY_CARGO_PER_STATION > t->max_pass) return false;
// All check are okay, so we can build here! // All check are okay, so we can build here!
return true; return true;
} }
@ -233,15 +250,15 @@ static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type) {
Station *st; Station *st;
int count = 0; int count = 0;
int j = 0; int j = 0;
if (i->town != NULL && i->town->ratings[_current_player] < 0 && CHANCE16(1,4)) return false; if (i->town != NULL && i->town->ratings[_current_player] < 0 && CHANCE16(1,4)) return false;
// No limits on delevering stations! // No limits on delevering stations!
// Or for industry that does not give anything yet // Or for industry that does not give anything yet
if (i->produced_cargo[0] == 0xFF || i->total_production[0] == 0) return true; if (i->produced_cargo[0] == 0xFF || i->total_production[0] == 0) return true;
if (i->total_production[0] - i->total_transported[0] < AI_CHECKCITY_NEEDED_CARGO) return false; if (i->total_production[0] - i->total_transported[0] < AI_CHECKCITY_NEEDED_CARGO) return false;
// Check if we have build a station in this town the last 6 months // Check if we have build a station in this town the last 6 months
// else we don't do it. This is done, because stat updates can be slow // else we don't do it. This is done, because stat updates can be slow
// and sometimes it takes up to 4 months before the stats are corectly. // and sometimes it takes up to 4 months before the stats are corectly.
@ -288,7 +305,7 @@ static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type) {
// All check are okay, so we can build here! // All check are okay, so we can build here!
return true; return true;
} }
return true; return true;
} }
@ -296,14 +313,14 @@ static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type) {
static void AiNew_State_LocateRoute(Player *p) { static void AiNew_State_LocateRoute(Player *p) {
assert(p->ainew.state == AI_STATE_LOCATE_ROUTE); assert(p->ainew.state == AI_STATE_LOCATE_ROUTE);
// For now, we only support PASSENGERS, CITY and BUSSES // For now, we only support PASSENGERS, CITY and BUSSES
// We don't have a route yet // We don't have a route yet
if (p->ainew.cargo == AI_NEED_CARGO) { if (p->ainew.cargo == AI_NEED_CARGO) {
p->ainew.new_cost = 0; // No cost yet p->ainew.new_cost = 0; // No cost yet
p->ainew.temp = -1; p->ainew.temp = -1;
// Reset the counter // Reset the counter
p->ainew.counter = 0; p->ainew.counter = 0;
p->ainew.from_ic = -1; p->ainew.from_ic = -1;
p->ainew.to_ic = -1; p->ainew.to_ic = -1;
if (p->ainew.tbt == AI_BUS) { if (p->ainew.tbt == AI_BUS) {
@ -323,7 +340,7 @@ static void AiNew_State_LocateRoute(Player *p) {
// Now we are doing initing, we wait one tick // Now we are doing initing, we wait one tick
return; return;
} }
// Increase the counter and abort if it is taking too long! // Increase the counter and abort if it is taking too long!
p->ainew.counter++; p->ainew.counter++;
if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) { if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) {
@ -331,7 +348,7 @@ static void AiNew_State_LocateRoute(Player *p) {
p->ainew.state = AI_STATE_NOTHING; p->ainew.state = AI_STATE_NOTHING;
return; return;
} }
// We are going to locate a city from where we are going to connect // We are going to locate a city from where we are going to connect
if (p->ainew.from_ic == -1) { if (p->ainew.from_ic == -1) {
if (p->ainew.temp == -1) { if (p->ainew.temp == -1) {
@ -341,7 +358,7 @@ static void AiNew_State_LocateRoute(Player *p) {
else else
p->ainew.temp = RandomRange(_total_industries); p->ainew.temp = RandomRange(_total_industries);
} }
if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) { if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) {
// It was not a valid city // It was not a valid city
// increase the temp with one, and return. We will come back later here // increase the temp with one, and return. We will come back later here
@ -352,22 +369,22 @@ static void AiNew_State_LocateRoute(Player *p) {
} else { } else {
if (p->ainew.temp >= _total_industries) p->ainew.temp = 0; if (p->ainew.temp >= _total_industries) p->ainew.temp = 0;
} }
// Don't do an attempt if we are trying the same id as the last time... // Don't do an attempt if we are trying the same id as the last time...
if (p->ainew.last_id == p->ainew.temp) return; if (p->ainew.last_id == p->ainew.temp) return;
p->ainew.last_id = p->ainew.temp; p->ainew.last_id = p->ainew.temp;
return; return;
} }
// We found a good city/industry, save the data of it // We found a good city/industry, save the data of it
p->ainew.from_ic = p->ainew.temp; p->ainew.from_ic = p->ainew.temp;
// Start the next tick with finding a to-city // Start the next tick with finding a to-city
p->ainew.temp = -1; p->ainew.temp = -1;
return; return;
} }
// Find a to-city // Find a to-city
if (p->ainew.temp == -1) { if (p->ainew.temp == -1) {
// First, we pick a random spot to search to // First, we pick a random spot to search to
@ -376,16 +393,16 @@ static void AiNew_State_LocateRoute(Player *p) {
else else
p->ainew.temp = RandomRange(_total_industries); p->ainew.temp = RandomRange(_total_industries);
} }
// The same city is not allowed // The same city is not allowed
// Also check if the city is valid // Also check if the city is valid
if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) { if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) {
// Maybe it is valid.. // Maybe it is valid..
// We need to know if they are not to far apart from eachother.. // We need to know if they are not to far apart from eachother..
// We do that by checking how much cargo we have to move and how long the route // We do that by checking how much cargo we have to move and how long the route
// is. // is.
if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) { if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) {
int max_cargo = DEREF_TOWN(p->ainew.from_ic)->max_pass + DEREF_TOWN(p->ainew.temp)->max_pass; int max_cargo = DEREF_TOWN(p->ainew.from_ic)->max_pass + DEREF_TOWN(p->ainew.temp)->max_pass;
max_cargo -= DEREF_TOWN(p->ainew.from_ic)->act_pass + DEREF_TOWN(p->ainew.temp)->act_pass; max_cargo -= DEREF_TOWN(p->ainew.from_ic)->act_pass + DEREF_TOWN(p->ainew.temp)->act_pass;
@ -400,7 +417,7 @@ static void AiNew_State_LocateRoute(Player *p) {
p->ainew.from_tile = 0; p->ainew.from_tile = 0;
p->ainew.to_tile = 0; p->ainew.to_tile = 0;
return; return;
} }
} else if (p->ainew.tbt == AI_TRUCK) { } else if (p->ainew.tbt == AI_TRUCK) {
@ -469,7 +486,7 @@ static void AiNew_State_LocateRoute(Player *p) {
} else { } else {
if (p->ainew.temp >= _total_industries) p->ainew.temp = 0; if (p->ainew.temp >= _total_industries) p->ainew.temp = 0;
} }
// Don't do an attempt if we are trying the same id as the last time... // Don't do an attempt if we are trying the same id as the last time...
if (p->ainew.last_id == p->ainew.temp) return; if (p->ainew.last_id == p->ainew.temp) return;
p->ainew.last_id = p->ainew.temp; p->ainew.last_id = p->ainew.temp;
@ -513,7 +530,7 @@ static void AiNew_State_FindStation(Player *p) {
Town *town = NULL; Town *town = NULL;
Industry *industry = NULL; Industry *industry = NULL;
assert(p->ainew.state == AI_STATE_FIND_STATION); assert(p->ainew.state == AI_STATE_FIND_STATION);
if (p->ainew.from_tile == 0) { if (p->ainew.from_tile == 0) {
// First we scan for a station in the from-city // First we scan for a station in the from-city
if (p->ainew.from_type == AI_CITY) { if (p->ainew.from_type == AI_CITY) {
@ -626,11 +643,11 @@ static void AiNew_State_FindStation(Player *p) {
best = found_best[x]; best = found_best[x];
} }
} }
// See how much it is going to cost us... // See how much it is going to cost us...
r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST); r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
p->ainew.new_cost += r; p->ainew.new_cost += r;
direction = AI_PATHFINDER_NO_DIRECTION; direction = AI_PATHFINDER_NO_DIRECTION;
} else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) { } else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) {
// Truck station locater works differently.. a station can be on any place // Truck station locater works differently.. a station can be on any place
@ -659,7 +676,7 @@ static void AiNew_State_FindStation(Player *p) {
static void AiNew_State_FindPath(Player *p) { static void AiNew_State_FindPath(Player *p) {
int r; int r;
assert(p->ainew.state == AI_STATE_FIND_PATH); assert(p->ainew.state == AI_STATE_FIND_PATH);
// First time, init some data // First time, init some data
if (p->ainew.temp == -1) { if (p->ainew.temp == -1) {
// Init path_info // Init path_info
@ -683,18 +700,18 @@ static void AiNew_State_FindPath(Player *p) {
p->ainew.path_info.end_tile_br = p->ainew.to_tile; p->ainew.path_info.end_tile_br = p->ainew.to_tile;
p->ainew.path_info.end_direction = p->ainew.to_direction; p->ainew.path_info.end_direction = p->ainew.to_direction;
} }
if (p->ainew.tbt == AI_TRAIN) if (p->ainew.tbt == AI_TRAIN)
p->ainew.path_info.rail_or_road = true; p->ainew.path_info.rail_or_road = true;
else else
p->ainew.path_info.rail_or_road = false; p->ainew.path_info.rail_or_road = false;
// First, clean the pathfinder with our new begin and endpoints // First, clean the pathfinder with our new begin and endpoints
clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info); clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info);
p->ainew.temp = 0; p->ainew.temp = 0;
} }
// Start the pathfinder // Start the pathfinder
r = p->ainew.pathfinder->main(p->ainew.pathfinder); r = p->ainew.pathfinder->main(p->ainew.pathfinder);
// If it return: no match, stop it... // If it return: no match, stop it...
@ -725,7 +742,7 @@ static void AiNew_State_FindDepot(Player *p) {
assert(p->ainew.state == AI_STATE_FIND_DEPOT); assert(p->ainew.state == AI_STATE_FIND_DEPOT);
p->ainew.depot_tile = 0; p->ainew.depot_tile = 0;
for (i=2;i<p->ainew.path_info.route_length-2;i++) { for (i=2;i<p->ainew.path_info.route_length-2;i++) {
tile = p->ainew.path_info.route[i]; tile = p->ainew.path_info.route[i];
for (j=0;j<lengthof(_tileoffs_by_dir);j++) { for (j=0;j<lengthof(_tileoffs_by_dir);j++) {
@ -747,7 +764,7 @@ static void AiNew_State_FindDepot(Player *p) {
} }
} }
} }
// This routine let depot finding start in the middle, and work his way to the stations // This routine let depot finding start in the middle, and work his way to the stations
// It makes depot placing nicer :) // It makes depot placing nicer :)
i = p->ainew.path_info.route_length / 2; i = p->ainew.path_info.route_length / 2;
@ -761,7 +778,7 @@ static void AiNew_State_FindDepot(Player *p) {
// Bridge or tunnel.. we can't place a depot there // Bridge or tunnel.. we can't place a depot there
continue; continue;
} }
tile = p->ainew.path_info.route[i]; tile = p->ainew.path_info.route[i];
for (j=0;j<lengthof(_tileoffs_by_dir);j++) { for (j=0;j<lengthof(_tileoffs_by_dir);j++) {
@ -835,7 +852,7 @@ static int AiNew_HowManyVehicles(Player *p) {
max_cargo = DEREF_INDUSTRY(p->ainew.from_ic)->total_production[0]; max_cargo = DEREF_INDUSTRY(p->ainew.from_ic)->total_production[0];
else else
max_cargo = DEREF_INDUSTRY(p->ainew.to_ic)->total_production[0]; max_cargo = DEREF_INDUSTRY(p->ainew.to_ic)->total_production[0];
// This is because moving 60% is more then we can dream of! // This is because moving 60% is more then we can dream of!
max_cargo *= 0.6; max_cargo *= 0.6;
// We want all the cargo to be gone in a month.. so, we know the cargo it delivers // We want all the cargo to be gone in a month.. so, we know the cargo it delivers
@ -858,16 +875,16 @@ static int AiNew_HowManyVehicles(Player *p) {
static void AiNew_State_VerifyRoute(Player *p) { static void AiNew_State_VerifyRoute(Player *p) {
int res, i; int res, i;
assert(p->ainew.state == AI_STATE_VERIFY_ROUTE); assert(p->ainew.state == AI_STATE_VERIFY_ROUTE);
// Let's calculate the cost of the path.. // Let's calculate the cost of the path..
// new_cost already contains the cost of the stations // new_cost already contains the cost of the stations
p->ainew.path_info.position = -1; p->ainew.path_info.position = -1;
do { do {
p->ainew.path_info.position++; p->ainew.path_info.position++;
p->ainew.new_cost += AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_QUERY_COST); p->ainew.new_cost += AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_QUERY_COST);
} while (p->ainew.path_info.position != -2); } while (p->ainew.path_info.position != -2);
// Now we know the price of build station + path. Now check how many vehicles // Now we know the price of build station + path. Now check how many vehicles
// we need and what the price for that will be // we need and what the price for that will be
res = AiNew_HowManyVehicles(p); res = AiNew_HowManyVehicles(p);
@ -878,12 +895,12 @@ static void AiNew_State_VerifyRoute(Player *p) {
} }
p->ainew.amount_veh = res; p->ainew.amount_veh = res;
p->ainew.cur_veh = 0; p->ainew.cur_veh = 0;
// Check how much it it going to cost us.. // Check how much it it going to cost us..
for (i=0;i<res;i++) { for (i=0;i<res;i++) {
p->ainew.new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST); p->ainew.new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST);
} }
// Now we know how much the route is going to cost us // Now we know how much the route is going to cost us
// Check if we have enough money for it! // Check if we have enough money for it!
if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) { if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) {
@ -892,7 +909,7 @@ static void AiNew_State_VerifyRoute(Player *p) {
p->ainew.state = AI_STATE_NOTHING; p->ainew.state = AI_STATE_NOTHING;
return; return;
} }
// Now we can build the route, check the direction of the stations! // Now we can build the route, check the direction of the stations!
if (p->ainew.from_direction == AI_PATHFINDER_NO_DIRECTION) { if (p->ainew.from_direction == AI_PATHFINDER_NO_DIRECTION) {
p->ainew.from_direction = AiNew_GetDirection(p->ainew.path_info.route[p->ainew.path_info.route_length-1], p->ainew.path_info.route[p->ainew.path_info.route_length-2]); p->ainew.from_direction = AiNew_GetDirection(p->ainew.path_info.route[p->ainew.path_info.route_length-1], p->ainew.path_info.route[p->ainew.path_info.route_length-2]);
@ -904,10 +921,10 @@ static void AiNew_State_VerifyRoute(Player *p) {
p->ainew.from_tile = p->ainew.path_info.route[p->ainew.path_info.route_length-1]; p->ainew.from_tile = p->ainew.path_info.route[p->ainew.path_info.route_length-1];
if (p->ainew.to_tile == AI_STATION_RANGE) if (p->ainew.to_tile == AI_STATION_RANGE)
p->ainew.to_tile = p->ainew.path_info.route[0]; p->ainew.to_tile = p->ainew.path_info.route[0];
p->ainew.state = AI_STATE_BUILD_STATION; p->ainew.state = AI_STATE_BUILD_STATION;
p->ainew.temp = 0; p->ainew.temp = 0;
DEBUG(ai,1)("[AiNew] The route is set and buildable.. going to build it!"); DEBUG(ai,1)("[AiNew] The route is set and buildable.. going to build it!");
} }
@ -952,7 +969,7 @@ static void AiNew_State_BuildPath(Player *p) {
// By let the counter count from AI_BUILDPATH_PAUSE to 0, we have a nice way :) // By let the counter count from AI_BUILDPATH_PAUSE to 0, we have a nice way :)
if (--p->ainew.counter != 0) return; if (--p->ainew.counter != 0) return;
p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1; p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1;
// Increase the building position // Increase the building position
p->ainew.path_info.position++; p->ainew.path_info.position++;
// Build route // Build route
@ -964,7 +981,7 @@ static void AiNew_State_BuildPath(Player *p) {
static const byte _roadbits_by_dir[4] = {2,1,8,4}; static const byte _roadbits_by_dir[4] = {2,1,8,4};
// If they not queue, they have to go up and down to try again at a station... // If they not queue, they have to go up and down to try again at a station...
// We don't want that, so try building some road left or right of the station // We don't want that, so try building some road left or right of the station
short dir1, dir2, dir3; int dir1, dir2, dir3;
TileIndex tile; TileIndex tile;
int i, r; int i, r;
for (i=0;i<2;i++) { for (i=0;i<2;i++) {
@ -983,11 +1000,11 @@ static void AiNew_State_BuildPath(Player *p) {
if (dir2 > 3) dir2 = 0; if (dir2 > 3) dir2 = 0;
dir3 = p->ainew.to_direction; dir3 = p->ainew.to_direction;
} }
DoCommandByTile(tile, _roadbits_by_dir[dir1], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); DoCommandByTile(tile, _roadbits_by_dir[dir1], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
DoCommandByTile(tile, _roadbits_by_dir[dir2], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); DoCommandByTile(tile, _roadbits_by_dir[dir2], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
DoCommandByTile(tile, _roadbits_by_dir[dir3^2], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); DoCommandByTile(tile, _roadbits_by_dir[dir3^2], 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
dir1 = _tileoffs_by_dir[dir1]; dir1 = _tileoffs_by_dir[dir1];
dir2 = _tileoffs_by_dir[dir2]; dir2 = _tileoffs_by_dir[dir2];
dir3 = _tileoffs_by_dir[dir3]; dir3 = _tileoffs_by_dir[dir3];
@ -1000,21 +1017,21 @@ static void AiNew_State_BuildPath(Player *p) {
r = CMD_ERROR; r = CMD_ERROR;
if (IS_TILETYPE(tile+dir2, MP_CLEAR) || IS_TILETYPE(tile+dir2, MP_TREES)) if (IS_TILETYPE(tile+dir2, MP_CLEAR) || IS_TILETYPE(tile+dir2, MP_TREES))
DoCommandByTile(tile+dir2, AiNew_GetRoadDirection(tile, tile+dir2, tile+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); r = DoCommandByTile(tile+dir2, AiNew_GetRoadDirection(tile, tile+dir2, tile+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
if (r != CMD_ERROR) if (r != CMD_ERROR)
if (IS_TILETYPE(tile+dir2+dir2, MP_CLEAR) || IS_TILETYPE(tile+dir2+dir2, MP_TREES)) if (IS_TILETYPE(tile+dir2+dir2, MP_CLEAR) || IS_TILETYPE(tile+dir2+dir2, MP_TREES))
DoCommandByTile(tile+dir2+dir2, AiNew_GetRoadDirection(tile+dir2, tile+dir2+dir2, tile+dir2+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); DoCommandByTile(tile+dir2+dir2, AiNew_GetRoadDirection(tile+dir2, tile+dir2+dir2, tile+dir2+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
r = CMD_ERROR; r = CMD_ERROR;
if (IS_TILETYPE(tile+dir3, MP_CLEAR) || IS_TILETYPE(tile+dir3, MP_TREES)) if (IS_TILETYPE(tile+dir3, MP_CLEAR) || IS_TILETYPE(tile+dir3, MP_TREES))
DoCommandByTile(tile+dir3, AiNew_GetRoadDirection(tile, tile+dir3, tile+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); r = DoCommandByTile(tile+dir3, AiNew_GetRoadDirection(tile, tile+dir3, tile+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
if (r != CMD_ERROR) if (r != CMD_ERROR)
if (IS_TILETYPE(tile+dir3+dir3, MP_CLEAR) || IS_TILETYPE(tile+dir3+dir3, MP_TREES)) if (IS_TILETYPE(tile+dir3+dir3, MP_CLEAR) || IS_TILETYPE(tile+dir3+dir3, MP_TREES))
DoCommandByTile(tile+dir3+dir3, AiNew_GetRoadDirection(tile+dir3, tile+dir3+dir3, tile+dir3+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); DoCommandByTile(tile+dir3+dir3, AiNew_GetRoadDirection(tile+dir3, tile+dir3+dir3, tile+dir3+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
} }
} }
DEBUG(ai,1)("[AiNew] Done building the path (cost: %d)", p->ainew.new_cost); DEBUG(ai,1)("[AiNew] Done building the path (cost: %d)", p->ainew.new_cost);
p->ainew.state = AI_STATE_BUILD_DEPOT; p->ainew.state = AI_STATE_BUILD_DEPOT;
} }
@ -1024,7 +1041,7 @@ static void AiNew_State_BuildPath(Player *p) {
static void AiNew_State_BuildDepot(Player *p) { static void AiNew_State_BuildDepot(Player *p) {
int res = 0; int res = 0;
assert(p->ainew.state == AI_STATE_BUILD_DEPOT); assert(p->ainew.state == AI_STATE_BUILD_DEPOT);
if (IS_TILETYPE(p->ainew.depot_tile, MP_STREET) && _map5[p->ainew.depot_tile] & 0x20) { if (IS_TILETYPE(p->ainew.depot_tile, MP_STREET) && _map5[p->ainew.depot_tile] & 0x20) {
if (_map_owner[p->ainew.depot_tile] == _current_player) { if (_map_owner[p->ainew.depot_tile] == _current_player) {
// The depot is already builded! // The depot is already builded!
@ -1036,18 +1053,18 @@ static void AiNew_State_BuildDepot(Player *p) {
return; return;
} }
} }
// There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p) // There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p)
if (!EnsureNoVehicle(p->ainew.depot_tile + _tileoffs_by_dir[p->ainew.depot_direction])) if (!EnsureNoVehicle(p->ainew.depot_tile + _tileoffs_by_dir[p->ainew.depot_direction]))
return; return;
res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC); res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC);
if (res == CMD_ERROR) { if (res == CMD_ERROR) {
DEBUG(ai,0)("[AiNew - BuildDepot] Strange but true... depot can not be build!"); DEBUG(ai,0)("[AiNew - BuildDepot] Strange but true... depot can not be build!");
p->ainew.state = AI_STATE_NOTHING; p->ainew.state = AI_STATE_NOTHING;
return; return;
} }
p->ainew.state = AI_STATE_BUILD_VEHICLE; p->ainew.state = AI_STATE_BUILD_VEHICLE;
p->ainew.idle = 1; p->ainew.idle = 1;
p->ainew.veh_main_id = (VehicleID)-1; p->ainew.veh_main_id = (VehicleID)-1;
@ -1057,7 +1074,7 @@ static void AiNew_State_BuildDepot(Player *p) {
static void AiNew_State_BuildVehicle(Player *p) { static void AiNew_State_BuildVehicle(Player *p) {
int res; int res;
assert(p->ainew.state == AI_STATE_BUILD_VEHICLE); assert(p->ainew.state == AI_STATE_BUILD_VEHICLE);
// Check if we need to build a vehicle // Check if we need to build a vehicle
if (p->ainew.amount_veh == 0) { if (p->ainew.amount_veh == 0) {
// Nope, we are done! // Nope, we are done!
@ -1070,7 +1087,7 @@ static void AiNew_State_BuildVehicle(Player *p) {
// It is realistic that the AI can only build 1 vehicle a day.. // It is realistic that the AI can only build 1 vehicle a day..
// This makes sure of that! // This makes sure of that!
p->ainew.idle = AI_BUILD_VEHICLE_TIME_BETWEEN; p->ainew.idle = AI_BUILD_VEHICLE_TIME_BETWEEN;
// Build the vehicle // Build the vehicle
res = AiNew_Build_Vehicle(p, p->ainew.depot_tile, DC_EXEC); res = AiNew_Build_Vehicle(p, p->ainew.depot_tile, DC_EXEC);
if (res == CMD_ERROR) { if (res == CMD_ERROR) {
@ -1095,10 +1112,10 @@ static void AiNew_State_BuildVehicle(Player *p) {
static void AiNew_State_GiveOrders(Player *p) { static void AiNew_State_GiveOrders(Player *p) {
int order, flags; int order, flags;
assert(p->ainew.state == AI_STATE_GIVE_ORDERS); assert(p->ainew.state == AI_STATE_GIVE_ORDERS);
if (p->ainew.veh_main_id != (VehicleID)-1) { if (p->ainew.veh_main_id != (VehicleID)-1) {
DoCommandByTile(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER); DoCommandByTile(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER);
// Skip the first order if it is a second vehicle // Skip the first order if it is a second vehicle
// This to make vehicles go different ways.. // This to make vehicles go different ways..
if (p->ainew.veh_id & 1) if (p->ainew.veh_id & 1)
@ -1108,7 +1125,7 @@ static void AiNew_State_GiveOrders(Player *p) {
} else { } else {
p->ainew.veh_main_id = p->ainew.veh_id; p->ainew.veh_main_id = p->ainew.veh_id;
} }
// When more then 1 vehicle, we send them to different directions // When more then 1 vehicle, we send them to different directions
order = 0; order = 0;
flags = (_map2[p->ainew.from_tile] << 8) | OT_GOTO_STATION; flags = (_map2[p->ainew.from_tile] << 8) | OT_GOTO_STATION;
@ -1136,7 +1153,7 @@ static void AiNew_State_GiveOrders(Player *p) {
// Start the vehicle // Start the vehicle
static void AiNew_State_StartVehicle(Player *p) { static void AiNew_State_StartVehicle(Player *p) {
assert(p->ainew.state == AI_STATE_START_VEHICLE); assert(p->ainew.state == AI_STATE_START_VEHICLE);
// 3, 2, 1... go! (give START_STOP command ;)) // 3, 2, 1... go! (give START_STOP command ;))
DoCommandByTile(0, p->ainew.veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH); DoCommandByTile(0, p->ainew.veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
// Try to build an other vehicle (that function will stop building when needed) // Try to build an other vehicle (that function will stop building when needed)
@ -1151,6 +1168,62 @@ static void AiNew_State_RepayMoney(Player *p) {
p->ainew.state = AI_STATE_ACTION_DONE; p->ainew.state = AI_STATE_ACTION_DONE;
} }
static void AiNew_CheckVehicle(Player *p, Vehicle *v) {
// When a vehicle is under the 6 months, we don't check for anything
if (v->age < 180) return;
// When a vehicle is older then 1 year, it should make money...
if (v->age > 360) {
// If both years together are not more then AI_MINIMUM_ROUTE_PROFIT,
// it is not worth the line I guess...
if (v->profit_last_year + v->profit_this_year < AI_MINIMUM_ROUTE_PROFIT ||
(v->reliability * 100 >> 16) < 40) {
// There is a possibility that the route is fucked up...
if (v->cargo_days > AI_VEHICLE_LOST_DAYS) {
// The vehicle is lost.. check the route, or else, get the vehicle
// back to a depot
// TODO: make this piece of code
}
// We are already sending him back
if (AiNew_GetSpecialVehicleFlag(p, v) & AI_VEHICLEFLAG_SELL) {
if (v->type == VEH_Road && IsRoadDepotTile(v->tile) &&
(v->vehstatus&VS_STOPPED)) {
// We are at the depot, sell the vehicle
DoCommandByTile(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
}
return;
}
if (!AiNew_SetSpecialVehicleFlag(p, v, AI_VEHICLEFLAG_SELL)) return;
{
int res = 0;
if (v->type == VEH_Road)
res = DoCommandByTile(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
// This means we can not find a depot :s
// if (res == CMD_ERROR)
}
}
}
}
// Checks all vehicles if they are still valid and make money and stuff
static void AiNew_State_CheckAllVehicles(Player *p) {
Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->type == 0) continue;
if (v->owner != p->index) continue;
// Currently, we only know how to handle road-vehicles
if (v->type != VEH_Road) continue;
AiNew_CheckVehicle(p, v);
}
p->ainew.state = AI_STATE_ACTION_DONE;
}
// Using the technique simular to the original AI // Using the technique simular to the original AI
// Keeps things logical // Keeps things logical
// It really should be in the same order as the AI_STATE's are! // It really should be in the same order as the AI_STATE's are!
@ -1171,6 +1244,7 @@ static AiNew_StateFunction* const _ainew_state[] = {
AiNew_State_GiveOrders, AiNew_State_GiveOrders,
AiNew_State_StartVehicle, AiNew_State_StartVehicle,
AiNew_State_RepayMoney, AiNew_State_RepayMoney,
AiNew_State_CheckAllVehicles,
AiNew_State_ActionDone, AiNew_State_ActionDone,
NULL, NULL,
}; };
@ -1184,7 +1258,7 @@ void AiNewDoGameLoop(Player *p) {
// If it is a human player, it is not an AI, so bubye! // If it is a human player, it is not an AI, so bubye!
if (IS_HUMAN_PLAYER(_current_player)) if (IS_HUMAN_PLAYER(_current_player))
return; return;
if (p->ainew.state == AI_STATE_STARTUP) { if (p->ainew.state == AI_STATE_STARTUP) {
// The AI just got alive! // The AI just got alive!
p->ainew.state = AI_STATE_FIRST_TIME; p->ainew.state = AI_STATE_FIRST_TIME;
@ -1193,10 +1267,10 @@ void AiNewDoGameLoop(Player *p) {
// Only startup the AI // Only startup the AI
return; return;
} }
// We keep a ticker. We use it for competitor_speed // We keep a ticker. We use it for competitor_speed
p->ainew.tick++; p->ainew.tick++;
// See what the speed is // See what the speed is
switch (_opt.diff.competitor_speed) { switch (_opt.diff.competitor_speed) {
case 0: // Very slow case 0: // Very slow

View File

@ -187,7 +187,7 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
// This problem only is valid for tunnels: // This problem only is valid for tunnels:
// When the last tile was not yet a tunnel, check if we enter from the right side.. // When the last tile was not yet a tunnel, check if we enter from the right side..
if (!IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE) && (_map5[current->path.node.tile + _tiles_around[i]] & 0x80) == 0) { if (!IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE) && (_map5[current->path.node.tile + _tiles_around[i]] & 0x80) == 0) {
if ((i^2) != (_map5[current->path.node.tile + _tiles_around[i]] & 3)) continue; if (i != (_map5[current->path.node.tile + _tiles_around[i]] & 3)) continue;
} }
} }
} }

View File

@ -1,7 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "ttd.h" #include "ttd.h"
#include "player.h"
#include "ai.h" #include "ai.h"
#include "vehicle.h"
int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c) { int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c) {
// 0 = vert // 0 = vert
@ -79,4 +79,39 @@ int AiNew_GetDirection(uint tile_a, uint tile_b) {
if (GET_TILE_X(tile_a) < GET_TILE_X(tile_b)) return 2; if (GET_TILE_X(tile_a) < GET_TILE_X(tile_b)) return 2;
return 0; return 0;
} }
// This functions looks up if this vehicle is special for this AI
// and returns his flag
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v) {
int i;
for (i=0;i<AI_MAX_SPECIAL_VEHICLES;i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
return p->ainew.special_vehicles[i].flag;
}
}
// Not found :(
return 0;
}
bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag) {
int i, new_id = -1;
for (i=0;i<AI_MAX_SPECIAL_VEHICLES;i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
p->ainew.special_vehicles[i].flag |= flag;
return true;
}
if (new_id == -1 && p->ainew.special_vehicles[i].veh_id == 0 &&
p->ainew.special_vehicles[i].flag == 0)
new_id = i;
}
// Out of special_vehicle spots :s
if (new_id == -1) {
DEBUG(ai, 1)("special_vehicles list is too small :(");
return false;
}
p->ainew.special_vehicles[new_id].veh_id = v->index;
p->ainew.special_vehicles[new_id].flag = flag;
return true;
}

View File

@ -47,19 +47,19 @@ typedef struct PlayerAI {
TileIndex cur_tile_a; TileIndex cur_tile_a;
byte cur_dir_a; byte cur_dir_a;
byte start_dir_a; byte start_dir_a;
TileIndex start_tile_b; TileIndex start_tile_b;
TileIndex cur_tile_b; TileIndex cur_tile_b;
byte cur_dir_b; byte cur_dir_b;
byte start_dir_b; byte start_dir_b;
Vehicle *cur_veh; /* only used by some states */ Vehicle *cur_veh; /* only used by some states */
AiBuildRec src, dst, mid1, mid2; AiBuildRec src, dst, mid1, mid2;
VehicleID wagon_list[9]; VehicleID wagon_list[9];
byte order_list_blocks[20]; byte order_list_blocks[20];
TileIndex banned_tiles[16]; TileIndex banned_tiles[16];
byte banned_val[16]; byte banned_val[16];
} PlayerAI; } PlayerAI;
@ -76,58 +76,68 @@ typedef struct Ai_PathFinderInfo {
byte route_extra[500]; // Some extra information about the route like bridge/tunnel byte route_extra[500]; // Some extra information about the route like bridge/tunnel
int route_length; int route_length;
int position; // Current position in the build-path, needed to build the path int position; // Current position in the build-path, needed to build the path
bool rail_or_road; // true = rail, false = road bool rail_or_road; // true = rail, false = road
} Ai_PathFinderInfo; } Ai_PathFinderInfo;
// The amount of memory reserved for the AI-special-vehicles
#define AI_MAX_SPECIAL_VEHICLES 100
typedef struct Ai_SpecialVehicle {
VehicleID veh_id;
uint32 flag;
} Ai_SpecialVehicle;
typedef struct PlayerAiNew { typedef struct PlayerAiNew {
uint8 state; uint8 state;
uint tick; uint tick;
uint idle; uint idle;
int temp; // A value used in more then one function, but it just temporary int temp; // A value used in more then one function, but it just temporary
// The use is pretty simple: with this we can 'think' about stuff // The use is pretty simple: with this we can 'think' about stuff
// in more then one tick, and more then one AI. A static will not // in more then one tick, and more then one AI. A static will not
// do, because they are not saved. This way, the AI is almost human ;) // do, because they are not saved. This way, the AI is almost human ;)
int counter; // For the same reason as temp, we have counter. It can count how int counter; // For the same reason as temp, we have counter. It can count how
// long we are trying something, and just abort if it takes too long // long we are trying something, and just abort if it takes too long
// Pathfinder stuff // Pathfinder stuff
Ai_PathFinderInfo path_info; Ai_PathFinderInfo path_info;
AyStar *pathfinder; AyStar *pathfinder;
// Route stuff // Route stuff
byte cargo; byte cargo;
byte tbt; // train/bus/truck 0/1/2 AI_TRAIN/AI_BUS/AI_TRUCK byte tbt; // train/bus/truck 0/1/2 AI_TRAIN/AI_BUS/AI_TRUCK
int new_cost; int new_cost;
byte action; byte action;
uint last_id; // here is stored the last id of the searched city/industry uint last_id; // here is stored the last id of the searched city/industry
uint last_vehiclecheck_date; // Used in CheckVehicle
Ai_SpecialVehicle special_vehicles[AI_MAX_SPECIAL_VEHICLES]; // Some vehicles have some special flags
TileIndex from_tile; TileIndex from_tile;
TileIndex to_tile; TileIndex to_tile;
byte from_direction; byte from_direction;
byte to_direction; byte to_direction;
bool from_deliver; // True if this is the station that GIVES cargo bool from_deliver; // True if this is the station that GIVES cargo
bool to_deliver; bool to_deliver;
TileIndex depot_tile; TileIndex depot_tile;
byte depot_direction; byte depot_direction;
byte amount_veh; // How many vehicles we are going to build in this route byte amount_veh; // How many vehicles we are going to build in this route
byte cur_veh; // How many vehicles did we bought? byte cur_veh; // How many vehicles did we bought?
VehicleID veh_id; // Used when bought a vehicle VehicleID veh_id; // Used when bought a vehicle
VehicleID veh_main_id; // The ID of the first vehicle, for shared copy VehicleID veh_main_id; // The ID of the first vehicle, for shared copy
int from_ic; // ic = industry/city. This is the ID of them int from_ic; // ic = industry/city. This is the ID of them
byte from_type; // AI_NO_TYPE/AI_CITY/AI_INDUSTRY byte from_type; // AI_NO_TYPE/AI_CITY/AI_INDUSTRY
int to_ic; int to_ic;
byte to_type; byte to_type;
} PlayerAiNew; } PlayerAiNew;
@ -155,12 +165,12 @@ typedef struct Player {
TileIndex location_of_house; TileIndex location_of_house;
TileIndex last_build_coordinate; TileIndex last_build_coordinate;
byte share_owners[4]; byte share_owners[4];
byte inaugurated_year; byte inaugurated_year;
byte num_valid_stat_ent; byte num_valid_stat_ent;
byte quarters_of_bankrupcy; byte quarters_of_bankrupcy;
byte bankrupt_asked; // which players were asked about buying it? byte bankrupt_asked; // which players were asked about buying it?
int16 bankrupt_timeout; int16 bankrupt_timeout;
@ -170,7 +180,7 @@ typedef struct Player {
byte is_ai; byte is_ai;
PlayerAI ai; PlayerAI ai;
PlayerAiNew ainew; PlayerAiNew ainew;
int64 yearly_expenses[3][13]; int64 yearly_expenses[3][13];
PlayerEconomyEntry cur_economy; PlayerEconomyEntry cur_economy;
PlayerEconomyEntry old_economy[24]; PlayerEconomyEntry old_economy[24];