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

30
ai.h
View File

@ -136,11 +136,29 @@
// How many thick between building 2 vehicles
#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
*/
// This stops 90degrees curves
static const byte _illegal_curves[6] = {
255, 255, // Horz and vert, don't have the effect
@ -174,6 +192,7 @@ enum {
AI_STATE_GIVE_ORDERS,
AI_STATE_START_VEHICLE,
AI_STATE_REPAY_MONEY,
AI_STATE_CHECK_ALL_VEHICLES,
AI_STATE_ACTION_DONE,
AI_STATE_STOP, // Temporary function to stop the AI
};
@ -190,6 +209,7 @@ enum {
AI_ACTION_BUS_ROUTE,
AI_ACTION_TRUCK_ROUTE,
AI_ACTION_REPAY_LOAN,
AI_ACTION_CHECK_ALL_VEHICLES,
};
// Used for from_type/to_type
@ -199,6 +219,12 @@ enum {
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_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)
@ -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_GetRoadDirection(uint tile_a, uint tile_b, uint tile_c);
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
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
res = DoCommandByTile(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
// 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!
DEBUG(ai,0)("Darn, the route could not be builded.. aborting!");
p->ainew.state = AI_STATE_NOTHING;

View File

@ -46,6 +46,7 @@ static void AiNew_State_FirstTime(Player *p) {
p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info);
p->ainew.idle = 0;
p->ainew.last_vehiclecheck_date = _date;
// We ALWAYS start with a bus route.. just some basic money ;)
p->ainew.action = AI_ACTION_BUS_ROUTE;
@ -101,10 +102,14 @@ static void AiNew_State_WakeUp(Player *p) {
if (p->current_loan > 0 && p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN &&
c < 10) {
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) {
// Do we have any spots for road-vehicles left open?
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 if (c < 200 && !_patches.ai_disable_veh_train) {
@ -112,6 +117,13 @@ static void AiNew_State_WakeUp(Player *p) {
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 && (
@ -132,6 +144,11 @@ static void AiNew_State_WakeUp(Player *p) {
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
// to build the route anyway..
if (p->ainew.action == AI_ACTION_BUS_ROUTE && money > AI_MINIMUM_BUS_ROUTE_MONEY) {
@ -964,7 +981,7 @@ static void AiNew_State_BuildPath(Player *p) {
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...
// 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;
int i, r;
for (i=0;i<2;i++) {
@ -1000,14 +1017,14 @@ static void AiNew_State_BuildPath(Player *p) {
r = CMD_ERROR;
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 (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);
r = CMD_ERROR;
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 (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);
@ -1151,6 +1168,62 @@ static void AiNew_State_RepayMoney(Player *p) {
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
// Keeps things logical
// 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_StartVehicle,
AiNew_State_RepayMoney,
AiNew_State_CheckAllVehicles,
AiNew_State_ActionDone,
NULL,
};

View File

@ -187,7 +187,7 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
// This problem only is valid for tunnels:
// 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 ((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 "ttd.h"
#include "player.h"
#include "ai.h"
#include "vehicle.h"
int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c) {
// 0 = vert
@ -80,3 +80,38 @@ int AiNew_GetDirection(uint tile_a, uint tile_b) {
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

@ -80,6 +80,14 @@ typedef struct Ai_PathFinderInfo {
bool rail_or_road; // true = rail, false = road
} 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 {
uint8 state;
uint tick;
@ -105,6 +113,8 @@ typedef struct PlayerAiNew {
byte action;
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 to_tile;