mirror of https://github.com/OpenTTD/OpenTTD
(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
parent
a7dd461672
commit
5eba928cb8
30
ai.h
30
ai.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
82
ai_new.c
82
ai_new.c
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
ai_shared.c
37
ai_shared.c
|
@ -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;
|
||||
}
|
||||
|
|
10
player.h
10
player.h
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue