mirror of https://github.com/OpenTTD/OpenTTD
(svn r111) -Fix: converted all linebreaks to UNIX-linebreak (\n)
parent
8644360264
commit
309ebe5f3f
486
ai.h
486
ai.h
|
@ -1,243 +1,243 @@
|
||||||
#ifndef AI_H
|
#ifndef AI_H
|
||||||
#define AI_H
|
#define AI_H
|
||||||
|
|
||||||
#include "aystar.h"
|
#include "aystar.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These defines can be altered to change the behavoir of the AI
|
* These defines can be altered to change the behavoir of the AI
|
||||||
*
|
*
|
||||||
* WARNING:
|
* WARNING:
|
||||||
* 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..
|
||||||
#define AI_PATHFINDER_H_MULTIPLER 100
|
#define AI_PATHFINDER_H_MULTIPLER 100
|
||||||
|
|
||||||
// How many loops may AyStar do before it stops
|
// How many loops may AyStar do before it stops
|
||||||
// 0 = infinite
|
// 0 = infinite
|
||||||
#define AI_PATHFINDER_LOOPS_PER_TICK 5
|
#define AI_PATHFINDER_LOOPS_PER_TICK 5
|
||||||
|
|
||||||
// How long may the AI search for one route?
|
// How long may the AI search for one route?
|
||||||
// 0 = infinite
|
// 0 = infinite
|
||||||
// This number is the number of tiles tested.
|
// This number is the number of tiles tested.
|
||||||
// It takes (AI_PATHFINDER_MAX_SEARCH_NODES / AI_PATHFINDER_LOOPS_PER_TICK) ticks
|
// It takes (AI_PATHFINDER_MAX_SEARCH_NODES / AI_PATHFINDER_LOOPS_PER_TICK) ticks
|
||||||
// to get here.. with 5000 / 10 = 500. 500 / 74 (one day) = 8 days till it aborts
|
// to get here.. with 5000 / 10 = 500. 500 / 74 (one day) = 8 days till it aborts
|
||||||
// (that is: if the AI is on VERY FAST! :p
|
// (that is: if the AI is on VERY FAST! :p
|
||||||
#define AI_PATHFINDER_MAX_SEARCH_NODES 5000
|
#define AI_PATHFINDER_MAX_SEARCH_NODES 5000
|
||||||
|
|
||||||
// If you enable this, the AI is not allowed to make 90degree turns
|
// If you enable this, the AI is not allowed to make 90degree turns
|
||||||
#define AI_PATHFINDER_NO_90DEGREES_TURN
|
#define AI_PATHFINDER_NO_90DEGREES_TURN
|
||||||
|
|
||||||
// Below are defines for the g-calculation
|
// Below are defines for the g-calculation
|
||||||
|
|
||||||
// Standard penalty given to a tile
|
// Standard penalty given to a tile
|
||||||
#define AI_PATHFINDER_PENALTY 150
|
#define AI_PATHFINDER_PENALTY 150
|
||||||
// The penalty given to a tile that is going up
|
// The penalty given to a tile that is going up
|
||||||
#define AI_PATHFINDER_TILE_GOES_UP_PENALTY 450
|
#define AI_PATHFINDER_TILE_GOES_UP_PENALTY 450
|
||||||
// Changing direction is a penalty, to prevent curved ways (with that: slow ways)
|
// Changing direction is a penalty, to prevent curved ways (with that: slow ways)
|
||||||
#define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200
|
#define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200
|
||||||
// Same penalty, only for when road already exists
|
// Same penalty, only for when road already exists
|
||||||
#define AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY 50
|
#define AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY 50
|
||||||
// A diagonal track cost the same as a straigh, but a diagonal is faster... so give
|
// A diagonal track cost the same as a straigh, but a diagonal is faster... so give
|
||||||
// a bonus for using diagonal track
|
// a bonus for using diagonal track
|
||||||
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
|
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
|
||||||
#define AI_PATHFINDER_DIAGONAL_BONUS 95
|
#define AI_PATHFINDER_DIAGONAL_BONUS 95
|
||||||
#else
|
#else
|
||||||
#define AI_PATHFINDER_DIAGONAL_BONUS 75
|
#define AI_PATHFINDER_DIAGONAL_BONUS 75
|
||||||
#endif
|
#endif
|
||||||
// If a roadblock already exists, it gets a bonus
|
// If a roadblock already exists, it gets a bonus
|
||||||
#define AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS 140
|
#define AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS 140
|
||||||
// To prevent 3 direction changes in 3 tiles, this penalty is given in such situation
|
// To prevent 3 direction changes in 3 tiles, this penalty is given in such situation
|
||||||
#define AI_PATHFINDER_CURVE_PENALTY 200
|
#define AI_PATHFINDER_CURVE_PENALTY 200
|
||||||
|
|
||||||
// Penalty a bridge gets per length
|
// Penalty a bridge gets per length
|
||||||
#define AI_PATHFINDER_BRIDGE_PENALTY 180
|
#define AI_PATHFINDER_BRIDGE_PENALTY 180
|
||||||
// The penalty for a bridge going up
|
// The penalty for a bridge going up
|
||||||
#define AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY 1000
|
#define AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY 1000
|
||||||
|
|
||||||
// Tunnels are expensive...
|
// Tunnels are expensive...
|
||||||
// Because of that, every tile the cost is increased with 1/8th of his value
|
// Because of that, every tile the cost is increased with 1/8th of his value
|
||||||
// This is also true if you are building a tunnel yourself
|
// This is also true if you are building a tunnel yourself
|
||||||
#define AI_PATHFINDER_TUNNEL_PENALTY 350
|
#define AI_PATHFINDER_TUNNEL_PENALTY 350
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ai_New defines
|
* Ai_New defines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// How long may we search cities and industry for a new route?
|
// How long may we search cities and industry for a new route?
|
||||||
#define AI_LOCATE_ROUTE_MAX_COUNTER 200
|
#define AI_LOCATE_ROUTE_MAX_COUNTER 200
|
||||||
|
|
||||||
// How many days must there be between building the first station and the second station
|
// How many days must there be between building the first station and the second station
|
||||||
// within one city. This number is in days and should be more then 4 months.
|
// within one city. This number is in days and should be more then 4 months.
|
||||||
#define AI_CHECKCITY_DATE_BETWEEN 180
|
#define AI_CHECKCITY_DATE_BETWEEN 180
|
||||||
|
|
||||||
// How many cargo is needed for one station in a city?
|
// How many cargo is needed for one station in a city?
|
||||||
#define AI_CHECKCITY_CARGO_PER_STATION 60
|
#define AI_CHECKCITY_CARGO_PER_STATION 60
|
||||||
// How much cargo must there not be used in a city before we can build a new station?
|
// How much cargo must there not be used in a city before we can build a new station?
|
||||||
#define AI_CHECKCITY_NEEDED_CARGO 50
|
#define AI_CHECKCITY_NEEDED_CARGO 50
|
||||||
// When there is already a station which takes the same good and the rating of that
|
// When there is already a station which takes the same good and the rating of that
|
||||||
// city is higher then this numer, we are not going to attempt to build anything
|
// city is higher then this numer, we are not going to attempt to build anything
|
||||||
// there
|
// there
|
||||||
#define AI_CHECKCITY_CARGO_RATING 50
|
#define AI_CHECKCITY_CARGO_RATING 50
|
||||||
// But, there is a chance of 1 out of this number, that we do ;)
|
// But, there is a chance of 1 out of this number, that we do ;)
|
||||||
#define AI_CHECKCITY_CARGO_RATING_CHANCE 5
|
#define AI_CHECKCITY_CARGO_RATING_CHANCE 5
|
||||||
// If a city is too small to contain a station, there is a small chance
|
// If a city is too small to contain a station, there is a small chance
|
||||||
// that we still do so.. just to make the city bigger!
|
// that we still do so.. just to make the city bigger!
|
||||||
#define AI_CHECKCITY_CITY_CHANCE 5
|
#define AI_CHECKCITY_CITY_CHANCE 5
|
||||||
|
|
||||||
// This number indicates for every unit of cargo, how many tiles two stations maybe be away
|
// This number indicates for every unit of cargo, how many tiles two stations maybe be away
|
||||||
// from eachother. In other words: if we have 120 units of cargo in one station, and 120 units
|
// from eachother. In other words: if we have 120 units of cargo in one station, and 120 units
|
||||||
// of the cargo in the other station, both stations can be 96 units away from eachother, if the
|
// of the cargo in the other station, both stations can be 96 units away from eachother, if the
|
||||||
// next number is 0.4.
|
// next number is 0.4.
|
||||||
#define AI_LOCATEROUTE_BUS_CARGO_DISTANCE 0.4
|
#define AI_LOCATEROUTE_BUS_CARGO_DISTANCE 0.4
|
||||||
#define AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE 0.7
|
#define AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE 0.7
|
||||||
// In whole tiles, the minimum distance for a truck route
|
// In whole tiles, the minimum distance for a truck route
|
||||||
#define AI_LOCATEROUTE_TRUCK_MIN_DISTANCE 30
|
#define AI_LOCATEROUTE_TRUCK_MIN_DISTANCE 30
|
||||||
|
|
||||||
// The amount of tiles in a square from -X to +X that is scanned for a station spot
|
// The amount of tiles in a square from -X to +X that is scanned for a station spot
|
||||||
// (so if this number is 10, 20x20 = 400 tiles are scanned for _the_ perfect spot
|
// (so if this number is 10, 20x20 = 400 tiles are scanned for _the_ perfect spot
|
||||||
// Safe values are between 15 and 5
|
// Safe values are between 15 and 5
|
||||||
#define AI_FINDSTATION_TILE_RANGE 10
|
#define AI_FINDSTATION_TILE_RANGE 10
|
||||||
|
|
||||||
// Building on normal speed goes very fast. Idle this amount of ticks between every
|
// Building on normal speed goes very fast. Idle this amount of ticks between every
|
||||||
// building part. It is calculated like this: (4 - competitor_speed) * num + 1
|
// building part. It is calculated like this: (4 - competitor_speed) * num + 1
|
||||||
// where competitor_speed is between 0 (very slow) to 4 (very fast)
|
// where competitor_speed is between 0 (very slow) to 4 (very fast)
|
||||||
#define AI_BUILDPATH_PAUSE 10
|
#define AI_BUILDPATH_PAUSE 10
|
||||||
|
|
||||||
// Minimum % of reliabilty a vehicle has to have before the AI buys it
|
// Minimum % of reliabilty a vehicle has to have before the AI buys it
|
||||||
#define AI_VEHICLE_MIN_RELIABILTY 60
|
#define AI_VEHICLE_MIN_RELIABILTY 60
|
||||||
|
|
||||||
// The minimum amount of money a player should always have
|
// The minimum amount of money a player should always have
|
||||||
#define AI_MINIMUM_MONEY 15000
|
#define AI_MINIMUM_MONEY 15000
|
||||||
|
|
||||||
// If the most cheap route is build, how much is it going to cost..
|
// If the most cheap route is build, how much is it going to cost..
|
||||||
// This is to prevent the AI from trying to build a route which can not be paid for
|
// This is to prevent the AI from trying to build a route which can not be paid for
|
||||||
#define AI_MINIMUM_BUS_ROUTE_MONEY 25000
|
#define AI_MINIMUM_BUS_ROUTE_MONEY 25000
|
||||||
#define AI_MINIMUM_TRUCK_ROUTE_MONEY 35000
|
#define AI_MINIMUM_TRUCK_ROUTE_MONEY 35000
|
||||||
|
|
||||||
// The minimum amount of money before we are going to repay any money
|
// The minimum amount of money before we are going to repay any money
|
||||||
#define AI_MINIMUM_LOAN_REPAY_MONEY 40000
|
#define AI_MINIMUM_LOAN_REPAY_MONEY 40000
|
||||||
// How many repays do we do if we have enough money to do so?
|
// How many repays do we do if we have enough money to do so?
|
||||||
// Every repay is 10000
|
// Every repay is 10000
|
||||||
#define AI_LOAN_REPAY 2
|
#define AI_LOAN_REPAY 2
|
||||||
// How much income must we have before paying back a loan? Month-based (and looked at the last month)
|
// How much income must we have before paying back a loan? Month-based (and looked at the last month)
|
||||||
#define AI_MINIMUM_INCOME_FOR_LOAN 7000
|
#define AI_MINIMUM_INCOME_FOR_LOAN 7000
|
||||||
|
|
||||||
// If there is <num> time as much cargo in the station then the vehicle can handle
|
// If there is <num> time as much cargo in the station then the vehicle can handle
|
||||||
// reuse the station instead of building a new one!
|
// reuse the station instead of building a new one!
|
||||||
#define AI_STATION_REUSE_MULTIPLER 2
|
#define AI_STATION_REUSE_MULTIPLER 2
|
||||||
|
|
||||||
// No more then this amount of vehicles per station..
|
// No more then this amount of vehicles per station..
|
||||||
#define AI_CHECK_MAX_VEHICLE_PER_STATION 10
|
#define AI_CHECK_MAX_VEHICLE_PER_STATION 10
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
5, // upleft and upright are not valid
|
5, // upleft and upright are not valid
|
||||||
4, // downright and downleft are not valid
|
4, // downright and downleft are not valid
|
||||||
2, // downleft and upleft are not valid
|
2, // downleft and upleft are not valid
|
||||||
3, // upright and downright are not valid
|
3, // upright and downright are not valid
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TileIndexDiff _tiles_around[4] = {
|
static const TileIndexDiff _tiles_around[4] = {
|
||||||
TILE_XY(-1,0),
|
TILE_XY(-1,0),
|
||||||
TILE_XY(0,1),
|
TILE_XY(0,1),
|
||||||
TILE_XY(1,0),
|
TILE_XY(1,0),
|
||||||
TILE_XY(0,-1),
|
TILE_XY(0,-1),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AI_STATE_STARTUP = 0,
|
AI_STATE_STARTUP = 0,
|
||||||
AI_STATE_FIRST_TIME,
|
AI_STATE_FIRST_TIME,
|
||||||
AI_STATE_NOTHING,
|
AI_STATE_NOTHING,
|
||||||
AI_STATE_WAKE_UP,
|
AI_STATE_WAKE_UP,
|
||||||
AI_STATE_LOCATE_ROUTE,
|
AI_STATE_LOCATE_ROUTE,
|
||||||
AI_STATE_FIND_STATION,
|
AI_STATE_FIND_STATION,
|
||||||
AI_STATE_FIND_PATH,
|
AI_STATE_FIND_PATH,
|
||||||
AI_STATE_FIND_DEPOT,
|
AI_STATE_FIND_DEPOT,
|
||||||
AI_STATE_VERIFY_ROUTE,
|
AI_STATE_VERIFY_ROUTE,
|
||||||
AI_STATE_BUILD_STATION,
|
AI_STATE_BUILD_STATION,
|
||||||
AI_STATE_BUILD_PATH,
|
AI_STATE_BUILD_PATH,
|
||||||
AI_STATE_BUILD_DEPOT,
|
AI_STATE_BUILD_DEPOT,
|
||||||
AI_STATE_BUILD_VEHICLE,
|
AI_STATE_BUILD_VEHICLE,
|
||||||
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_ACTION_DONE,
|
AI_STATE_ACTION_DONE,
|
||||||
AI_STATE_STOP, // Temporary function to stop the AI
|
AI_STATE_STOP, // Temporary function to stop the AI
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for tbt (train/bus/truck)
|
// Used for tbt (train/bus/truck)
|
||||||
enum {
|
enum {
|
||||||
AI_TRAIN = 0,
|
AI_TRAIN = 0,
|
||||||
AI_BUS,
|
AI_BUS,
|
||||||
AI_TRUCK,
|
AI_TRUCK,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AI_ACTION_NONE = 0,
|
AI_ACTION_NONE = 0,
|
||||||
AI_ACTION_BUS_ROUTE,
|
AI_ACTION_BUS_ROUTE,
|
||||||
AI_ACTION_TRUCK_ROUTE,
|
AI_ACTION_TRUCK_ROUTE,
|
||||||
AI_ACTION_REPAY_LOAN,
|
AI_ACTION_REPAY_LOAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for from_type/to_type
|
// Used for from_type/to_type
|
||||||
enum {
|
enum {
|
||||||
AI_NO_TYPE = 0,
|
AI_NO_TYPE = 0,
|
||||||
AI_CITY,
|
AI_CITY,
|
||||||
AI_INDUSTRY,
|
AI_INDUSTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
#define AI_PATHFINDER_NO_DIRECTION (byte)-1
|
#define AI_PATHFINDER_NO_DIRECTION (byte)-1
|
||||||
|
|
||||||
// Flags used in user_data
|
// Flags used in user_data
|
||||||
#define AI_PATHFINDER_FLAG_BRIDGE 1
|
#define AI_PATHFINDER_FLAG_BRIDGE 1
|
||||||
#define AI_PATHFINDER_FLAG_TUNNEL 2
|
#define AI_PATHFINDER_FLAG_TUNNEL 2
|
||||||
|
|
||||||
// A macro for mp_street, where 0x20 is depot
|
// A macro for mp_street, where 0x20 is depot
|
||||||
// mp_tunnelbridge, where 0xf0 is a bridge, and 0x4/0x2 means: roadtunnel/bridge
|
// mp_tunnelbridge, where 0xf0 is a bridge, and 0x4/0x2 means: roadtunnel/bridge
|
||||||
#define AI_PATHFINDER_IS_ROAD(tile) ((IS_TILETYPE(tile, MP_STREET) && !(_map5[tile] & 0x20)) || \
|
#define AI_PATHFINDER_IS_ROAD(tile) ((IS_TILETYPE(tile, MP_STREET) && !(_map5[tile] & 0x20)) || \
|
||||||
(IS_TILETYPE(tile, MP_TUNNELBRIDGE) && \
|
(IS_TILETYPE(tile, MP_TUNNELBRIDGE) && \
|
||||||
(((_map5[tile] & 0x80) == 0 && (_map5[tile] & 0x4) == 0x4) || \
|
(((_map5[tile] & 0x80) == 0 && (_map5[tile] & 0x4) == 0x4) || \
|
||||||
((_map5[tile] & 0x80) != 0 && (_map5[tile] & 0x2) == 0x2))))
|
((_map5[tile] & 0x80) != 0 && (_map5[tile] & 0x2) == 0x2))))
|
||||||
|
|
||||||
typedef void AiNew_StateFunction(Player *p);
|
typedef void AiNew_StateFunction(Player *p);
|
||||||
|
|
||||||
// ai_new.c
|
// ai_new.c
|
||||||
void AiNewDoGameLoop(Player *p);
|
void AiNewDoGameLoop(Player *p);
|
||||||
|
|
||||||
// ai_pathfinder.c
|
// ai_pathfinder.c
|
||||||
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo);
|
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo);
|
||||||
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
|
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
|
||||||
|
|
||||||
// ai_shared.c
|
// ai_shared.c
|
||||||
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);
|
||||||
|
|
||||||
// ai_build.c
|
// ai_build.c
|
||||||
bool AiNew_Build_CompanyHQ(Player *p, uint tile);
|
bool AiNew_Build_CompanyHQ(Player *p, uint tile);
|
||||||
int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag);
|
int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag);
|
||||||
int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag);
|
int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag);
|
||||||
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
|
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
|
||||||
int AiNew_PickVehicle(Player *p);
|
int AiNew_PickVehicle(Player *p);
|
||||||
int AiNew_Build_Vehicle(Player *p, uint tile, byte flag);
|
int AiNew_Build_Vehicle(Player *p, uint tile, byte flag);
|
||||||
int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag);
|
int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
514
ai_build.c
514
ai_build.c
|
@ -1,257 +1,257 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ttd.h"
|
#include "ttd.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "ai.h"
|
#include "ai.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
// Build HQ
|
// Build HQ
|
||||||
// Params:
|
// Params:
|
||||||
// tile : tile where HQ is going to be build
|
// tile : tile where HQ is going to be build
|
||||||
bool AiNew_Build_CompanyHQ(Player *p, uint tile) {
|
bool AiNew_Build_CompanyHQ(Player *p, uint tile) {
|
||||||
if (DoCommandByTile(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ) == CMD_ERROR)
|
if (DoCommandByTile(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ) == CMD_ERROR)
|
||||||
return false;
|
return false;
|
||||||
DoCommandByTile(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
|
DoCommandByTile(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build station
|
// Build station
|
||||||
// Params:
|
// Params:
|
||||||
// type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
|
// type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
|
||||||
// tile : tile where station is going to be build
|
// tile : tile where station is going to be build
|
||||||
// length : in case of AI_TRAIN: length of station
|
// length : in case of AI_TRAIN: length of station
|
||||||
// numtracks : in case of AI_TRAIN: tracks of station
|
// numtracks : in case of AI_TRAIN: tracks of station
|
||||||
// direction : the direction of the station
|
// direction : the direction of the station
|
||||||
// flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
|
// flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
|
||||||
int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag) {
|
int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag) {
|
||||||
if (type == AI_TRAIN)
|
if (type == AI_TRAIN)
|
||||||
return DoCommandByTile(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
|
return DoCommandByTile(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
|
||||||
else if (type == AI_BUS)
|
else if (type == AI_BUS)
|
||||||
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_BUS_STATION);
|
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_BUS_STATION);
|
||||||
else
|
else
|
||||||
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRUCK_STATION);
|
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRUCK_STATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builds a brdige. The second best out of the ones available for this player
|
// Builds a brdige. The second best out of the ones available for this player
|
||||||
// Params:
|
// Params:
|
||||||
// tile_a : starting point
|
// tile_a : starting point
|
||||||
// tile_b : end point
|
// tile_b : end point
|
||||||
// flag : flag passed to DoCommand
|
// flag : flag passed to DoCommand
|
||||||
int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag) {
|
int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag) {
|
||||||
int bridge_type, bridge_len, type, type2;
|
int bridge_type, bridge_len, type, type2;
|
||||||
|
|
||||||
// Find a good bridgetype (the best money can buy)
|
// Find a good bridgetype (the best money can buy)
|
||||||
bridge_len = GetBridgeLength(tile_a, tile_b);
|
bridge_len = GetBridgeLength(tile_a, tile_b);
|
||||||
type = type2 = 0;
|
type = type2 = 0;
|
||||||
for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
|
for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
|
||||||
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
|
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
|
||||||
type2 = type;
|
type2 = type;
|
||||||
type = bridge_type;
|
type = bridge_type;
|
||||||
// We found two bridges, exit
|
// We found two bridges, exit
|
||||||
if (type2 != 0)
|
if (type2 != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// There is only one bridge that can be build..
|
// There is only one bridge that can be build..
|
||||||
if (type2 == 0 && type != 0) type2 = type;
|
if (type2 == 0 && type != 0) type2 = type;
|
||||||
|
|
||||||
// Now, simply, build the bridge!
|
// Now, simply, build the bridge!
|
||||||
if (p->ainew.tbt == AI_TRAIN)
|
if (p->ainew.tbt == AI_TRAIN)
|
||||||
return DoCommandByTile(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
|
return DoCommandByTile(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
|
||||||
else
|
else
|
||||||
return DoCommandByTile(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
|
return DoCommandByTile(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build the route part by part
|
// Build the route part by part
|
||||||
// Basicly what this function do, is build that amount of parts of the route
|
// Basicly what this function do, is build that amount of parts of the route
|
||||||
// that go in the same direction. It sets 'part' to the last part of the route builded.
|
// that go in the same direction. It sets 'part' to the last part of the route builded.
|
||||||
// The return value is the cost for the builded parts
|
// The return value is the cost for the builded parts
|
||||||
//
|
//
|
||||||
// Params:
|
// Params:
|
||||||
// PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
|
// PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
|
||||||
// part : Which part we need to build
|
// part : Which part we need to build
|
||||||
//
|
//
|
||||||
// TODO: skip already builded road-pieces (e.g.: cityroad)
|
// TODO: skip already builded road-pieces (e.g.: cityroad)
|
||||||
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag) {
|
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag) {
|
||||||
int part = PathFinderInfo->position;
|
int part = PathFinderInfo->position;
|
||||||
byte *route_extra = PathFinderInfo->route_extra;
|
byte *route_extra = PathFinderInfo->route_extra;
|
||||||
TileIndex *route = PathFinderInfo->route;
|
TileIndex *route = PathFinderInfo->route;
|
||||||
int dir;
|
int dir;
|
||||||
int old_dir = -1;
|
int old_dir = -1;
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
int res;
|
int res;
|
||||||
// We need to calculate the direction with the parent of the parent.. so we skip
|
// We need to calculate the direction with the parent of the parent.. so we skip
|
||||||
// the first pieces and the last piece
|
// the first pieces and the last piece
|
||||||
if (part < 1) part = 1;
|
if (part < 1) part = 1;
|
||||||
// When we are done, stop it
|
// When we are done, stop it
|
||||||
if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; }
|
if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; }
|
||||||
|
|
||||||
|
|
||||||
if (PathFinderInfo->rail_or_road) {
|
if (PathFinderInfo->rail_or_road) {
|
||||||
// Tunnel code
|
// Tunnel code
|
||||||
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
|
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
|
||||||
cost += DoCommandByTile(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
|
cost += DoCommandByTile(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
|
||||||
PathFinderInfo->position++;
|
PathFinderInfo->position++;
|
||||||
// TODO: problems!
|
// TODO: problems!
|
||||||
if (cost == CMD_ERROR) {
|
if (cost == CMD_ERROR) {
|
||||||
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
|
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
// Bridge code
|
// Bridge code
|
||||||
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
|
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
|
||||||
cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
|
cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
|
||||||
PathFinderInfo->position++;
|
PathFinderInfo->position++;
|
||||||
// TODO: problems!
|
// TODO: problems!
|
||||||
if (cost == CMD_ERROR) {
|
if (cost == CMD_ERROR) {
|
||||||
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
|
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build normal rail
|
// Build normal rail
|
||||||
// Keep it doing till we go an other way
|
// Keep it doing till we go an other way
|
||||||
if (route_extra[part-1] == 0 && route_extra[part] == 0) {
|
if (route_extra[part-1] == 0 && route_extra[part] == 0) {
|
||||||
while (route_extra[part] == 0) {
|
while (route_extra[part] == 0) {
|
||||||
// Get the current direction
|
// Get the current direction
|
||||||
dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
|
dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
|
||||||
// Is it the same as the last one?
|
// Is it the same as the last one?
|
||||||
if (old_dir != -1 && old_dir != dir) break;
|
if (old_dir != -1 && old_dir != dir) break;
|
||||||
old_dir = dir;
|
old_dir = dir;
|
||||||
// Build the tile
|
// Build the tile
|
||||||
res = DoCommandByTile(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
|
res = DoCommandByTile(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
|
||||||
if (res == CMD_ERROR) {
|
if (res == CMD_ERROR) {
|
||||||
// Problem.. let's just abort it all!
|
// Problem.. let's just abort it all!
|
||||||
p->ainew.state = AI_STATE_NOTHING;
|
p->ainew.state = AI_STATE_NOTHING;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cost += res;
|
cost += res;
|
||||||
// Go to the next tile
|
// Go to the next tile
|
||||||
part++;
|
part++;
|
||||||
// Check if it is still in range..
|
// Check if it is still in range..
|
||||||
if (part >= PathFinderInfo->route_length - 1) break;
|
if (part >= PathFinderInfo->route_length - 1) break;
|
||||||
}
|
}
|
||||||
part--;
|
part--;
|
||||||
}
|
}
|
||||||
// We want to return the last position, so we go back one
|
// We want to return the last position, so we go back one
|
||||||
PathFinderInfo->position = part;
|
PathFinderInfo->position = part;
|
||||||
} else {
|
} else {
|
||||||
// Tunnel code
|
// Tunnel code
|
||||||
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
|
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
|
||||||
cost += DoCommandByTile(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
|
cost += DoCommandByTile(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
|
||||||
PathFinderInfo->position++;
|
PathFinderInfo->position++;
|
||||||
// TODO: problems!
|
// TODO: problems!
|
||||||
if (cost == CMD_ERROR) {
|
if (cost == CMD_ERROR) {
|
||||||
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
|
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
// Bridge code
|
// Bridge code
|
||||||
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
|
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
|
||||||
cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
|
cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
|
||||||
PathFinderInfo->position++;
|
PathFinderInfo->position++;
|
||||||
// TODO: problems!
|
// TODO: problems!
|
||||||
if (cost == CMD_ERROR) {
|
if (cost == CMD_ERROR) {
|
||||||
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
|
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build normal road
|
// Build normal road
|
||||||
// Keep it doing till we go an other way
|
// Keep it doing till we go an other way
|
||||||
// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
|
// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
|
||||||
// it will wait till the vehicle is gone..
|
// it will wait till the vehicle is gone..
|
||||||
if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
|
if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
|
||||||
while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
|
while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
|
||||||
// Get the current direction
|
// Get the current direction
|
||||||
dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
|
dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
|
||||||
// Is it the same as the last one?
|
// Is it the same as the last one?
|
||||||
if (old_dir != -1 && old_dir != dir) break;
|
if (old_dir != -1 && old_dir != dir) break;
|
||||||
old_dir = dir;
|
old_dir = dir;
|
||||||
// There is already some road, and it is a bridge.. don't build!!!
|
// There is already some road, and it is a bridge.. don't build!!!
|
||||||
if (!IS_TILETYPE(route[part], MP_TUNNELBRIDGE)) {
|
if (!IS_TILETYPE(route[part], MP_TUNNELBRIDGE)) {
|
||||||
// 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 && !IS_TILETYPE(route[part], MP_STREET) && (flag == DC_EXEC && !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;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (res != CMD_ERROR)
|
if (res != CMD_ERROR)
|
||||||
cost += res;
|
cost += res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Go to the next tile
|
// Go to the next tile
|
||||||
part++;
|
part++;
|
||||||
// Check if it is still in range..
|
// Check if it is still in range..
|
||||||
if (part >= PathFinderInfo->route_length - 1) break;
|
if (part >= PathFinderInfo->route_length - 1) break;
|
||||||
}
|
}
|
||||||
part--;
|
part--;
|
||||||
// We want to return the last position, so we go back one
|
// We want to return the last position, so we go back one
|
||||||
}
|
}
|
||||||
if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
|
if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
|
||||||
PathFinderInfo->position = part;
|
PathFinderInfo->position = part;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This functions tries to find the best vehicle for this type of cargo
|
// This functions tries to find the best vehicle for this type of cargo
|
||||||
// It returns vehicle_id or -1 if not found
|
// It returns vehicle_id or -1 if not found
|
||||||
int AiNew_PickVehicle(Player *p) {
|
int AiNew_PickVehicle(Player *p) {
|
||||||
if (p->ainew.tbt == AI_TRAIN) {
|
if (p->ainew.tbt == AI_TRAIN) {
|
||||||
// Not supported yet
|
// Not supported yet
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
int start, count, i, r = CMD_ERROR;
|
int start, count, i, r = CMD_ERROR;
|
||||||
start = _cargoc.ai_roadveh_start[p->ainew.cargo];
|
start = _cargoc.ai_roadveh_start[p->ainew.cargo];
|
||||||
count = _cargoc.ai_roadveh_count[p->ainew.cargo];
|
count = _cargoc.ai_roadveh_count[p->ainew.cargo];
|
||||||
|
|
||||||
// Let's check it backwards.. we simply want to best engine available..
|
// Let's check it backwards.. we simply want to best engine available..
|
||||||
for (i=start+count-1;i>=start;i--) {
|
for (i=start+count-1;i>=start;i--) {
|
||||||
// Is it availiable?
|
// Is it availiable?
|
||||||
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
|
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
|
||||||
if (!HASBIT(_engines[i].player_avail, _current_player) || _engines[i].reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
|
if (!HASBIT(_engines[i].player_avail, _current_player) || _engines[i].reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
|
||||||
// Can we build it?
|
// Can we build it?
|
||||||
r = DoCommandByTile(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
|
r = DoCommandByTile(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
|
||||||
if (r != CMD_ERROR) break;
|
if (r != CMD_ERROR) break;
|
||||||
}
|
}
|
||||||
// We did not find a vehicle :(
|
// We did not find a vehicle :(
|
||||||
if (r == CMD_ERROR) { return -1; }
|
if (r == CMD_ERROR) { return -1; }
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builds the best vehicle possible
|
// Builds the best vehicle possible
|
||||||
int AiNew_Build_Vehicle(Player *p, uint tile, byte flag) {
|
int AiNew_Build_Vehicle(Player *p, uint tile, byte flag) {
|
||||||
int i = AiNew_PickVehicle(p);
|
int i = AiNew_PickVehicle(p);
|
||||||
if (i == -1) return CMD_ERROR;
|
if (i == -1) return CMD_ERROR;
|
||||||
|
|
||||||
if (p->ainew.tbt == AI_TRAIN) {
|
if (p->ainew.tbt == AI_TRAIN) {
|
||||||
return CMD_ERROR;
|
return CMD_ERROR;
|
||||||
} else {
|
} else {
|
||||||
return DoCommandByTile(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
|
return DoCommandByTile(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag) {
|
int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag) {
|
||||||
static const byte _roadbits_by_dir[4] = {2,1,8,4};
|
static const byte _roadbits_by_dir[4] = {2,1,8,4};
|
||||||
int r, r2;
|
int r, r2;
|
||||||
if (p->ainew.tbt == AI_TRAIN) {
|
if (p->ainew.tbt == AI_TRAIN) {
|
||||||
return DoCommandByTile(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
|
return DoCommandByTile(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
|
||||||
} else {
|
} else {
|
||||||
r = DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
|
r = DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
|
||||||
if (r == CMD_ERROR) return r;
|
if (r == CMD_ERROR) return r;
|
||||||
// Try to build the road from the depot
|
// Try to build the road from the depot
|
||||||
r2 = DoCommandByTile(tile + _tileoffs_by_dir[direction], _roadbits_by_dir[direction], 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
|
r2 = DoCommandByTile(tile + _tileoffs_by_dir[direction], _roadbits_by_dir[direction], 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
|
||||||
// If it fails, ignore it..
|
// If it fails, ignore it..
|
||||||
if (r2 == CMD_ERROR) return r;
|
if (r2 == CMD_ERROR) return r;
|
||||||
return r + r2;
|
return r + r2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
914
ai_pathfinder.c
914
ai_pathfinder.c
|
@ -1,457 +1,457 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ttd.h"
|
#include "ttd.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "ai.h"
|
#include "ai.h"
|
||||||
|
|
||||||
#define TEST_STATION_NO_DIR 0xFF
|
#define TEST_STATION_NO_DIR 0xFF
|
||||||
|
|
||||||
// Tests if a station can be build on the given spot
|
// Tests if a station can be build on the given spot
|
||||||
// TODO: make it train compatible
|
// TODO: make it train compatible
|
||||||
bool TestCanBuildStationHere(uint tile, byte dir) {
|
bool TestCanBuildStationHere(uint tile, byte dir) {
|
||||||
Player *p = DEREF_PLAYER(_current_player);
|
Player *p = DEREF_PLAYER(_current_player);
|
||||||
if (dir == TEST_STATION_NO_DIR) {
|
if (dir == TEST_STATION_NO_DIR) {
|
||||||
// TODO: currently we only allow spots that can be access from al 4 directions...
|
// TODO: currently we only allow spots that can be access from al 4 directions...
|
||||||
// should be fixed!!!
|
// should be fixed!!!
|
||||||
for (dir=0;dir<4;dir++) {
|
for (dir=0;dir<4;dir++) {
|
||||||
int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
|
int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
|
||||||
if (res != CMD_ERROR)
|
if (res != CMD_ERROR)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
|
int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
|
||||||
if (res == CMD_ERROR)
|
if (res == CMD_ERROR)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a tile 'a' is between the tiles 'b' and 'c'
|
// Checks if a tile 'a' is between the tiles 'b' and 'c'
|
||||||
#define TILES_BETWEEN(a,b,c) (GET_TILE_X(a) >= GET_TILE_X(b) && GET_TILE_X(a) <= GET_TILE_X(c) && GET_TILE_Y(a) >= GET_TILE_Y(b) && GET_TILE_Y(a) <= GET_TILE_Y(c))
|
#define TILES_BETWEEN(a,b,c) (GET_TILE_X(a) >= GET_TILE_X(b) && GET_TILE_X(a) <= GET_TILE_X(c) && GET_TILE_Y(a) >= GET_TILE_Y(b) && GET_TILE_Y(a) <= GET_TILE_Y(c))
|
||||||
|
|
||||||
// Check if the current tile is in our end-area
|
// Check if the current tile is in our end-area
|
||||||
int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current) {
|
int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current) {
|
||||||
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
||||||
// It is not allowed to have a station on the end of a bridge or tunnel ;)
|
// It is not allowed to have a station on the end of a bridge or tunnel ;)
|
||||||
if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
|
if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
|
||||||
if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
|
if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
|
||||||
if (IS_TILETYPE(current->path.node.tile, MP_CLEAR) || IS_TILETYPE(current->path.node.tile, MP_TREES))
|
if (IS_TILETYPE(current->path.node.tile, MP_CLEAR) || IS_TILETYPE(current->path.node.tile, MP_TREES))
|
||||||
if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile,AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
|
if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile,AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
|
||||||
return AYSTAR_FOUND_END_NODE;
|
return AYSTAR_FOUND_END_NODE;
|
||||||
|
|
||||||
return AYSTAR_DONE;
|
return AYSTAR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the hash
|
// Calculates the hash
|
||||||
// Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
|
// Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
|
||||||
uint AiPathFinder_Hash(uint key1, uint key2) {
|
uint AiPathFinder_Hash(uint key1, uint key2) {
|
||||||
return (GET_TILE_X(key1) & 0x1F) + ((GET_TILE_Y(key1) & 0x1F) << 5);
|
return (GET_TILE_X(key1) & 0x1F) + ((GET_TILE_Y(key1) & 0x1F) << 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the memory of all the things
|
// Clear the memory of all the things
|
||||||
void AyStar_AiPathFinder_Free(AyStar *aystar) {
|
void AyStar_AiPathFinder_Free(AyStar *aystar) {
|
||||||
AyStarMain_Free(aystar);
|
AyStarMain_Free(aystar);
|
||||||
free(aystar);
|
free(aystar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
|
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
|
||||||
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
|
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
|
||||||
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
|
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
|
||||||
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
|
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
|
||||||
|
|
||||||
// This creates the AiPathFinder
|
// This creates the AiPathFinder
|
||||||
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo) {
|
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo) {
|
||||||
PathNode start_node;
|
PathNode start_node;
|
||||||
uint x,y;
|
uint x,y;
|
||||||
// Create AyStar
|
// Create AyStar
|
||||||
AyStar *result = malloc(sizeof(AyStar));
|
AyStar *result = malloc(sizeof(AyStar));
|
||||||
init_AyStar(result, AiPathFinder_Hash, 1 << 10);
|
init_AyStar(result, AiPathFinder_Hash, 1 << 10);
|
||||||
// Set the function pointers
|
// Set the function pointers
|
||||||
result->CalculateG = AyStar_AiPathFinder_CalculateG;
|
result->CalculateG = AyStar_AiPathFinder_CalculateG;
|
||||||
result->CalculateH = AyStar_AiPathFinder_CalculateH;
|
result->CalculateH = AyStar_AiPathFinder_CalculateH;
|
||||||
result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
|
result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
|
||||||
result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
|
result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
|
||||||
result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
|
result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
|
||||||
|
|
||||||
result->free = AyStar_AiPathFinder_Free;
|
result->free = AyStar_AiPathFinder_Free;
|
||||||
|
|
||||||
// Set some information
|
// Set some information
|
||||||
result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
|
result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
|
||||||
result->max_path_cost = 0;
|
result->max_path_cost = 0;
|
||||||
result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
|
result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
|
||||||
|
|
||||||
// Set the user_data to the PathFinderInfo
|
// Set the user_data to the PathFinderInfo
|
||||||
result->user_target = PathFinderInfo;
|
result->user_target = PathFinderInfo;
|
||||||
|
|
||||||
// Set the start node
|
// Set the start node
|
||||||
start_node.parent = NULL;
|
start_node.parent = NULL;
|
||||||
start_node.node.direction = 0;
|
start_node.node.direction = 0;
|
||||||
start_node.node.user_data[0] = 0;
|
start_node.node.user_data[0] = 0;
|
||||||
|
|
||||||
// Now we add all the starting tiles
|
// Now we add all the starting tiles
|
||||||
for (x=GET_TILE_X(PathFinderInfo->start_tile_tl);x<=GET_TILE_X(PathFinderInfo->start_tile_br);x++) {
|
for (x=GET_TILE_X(PathFinderInfo->start_tile_tl);x<=GET_TILE_X(PathFinderInfo->start_tile_br);x++) {
|
||||||
for (y=GET_TILE_Y(PathFinderInfo->start_tile_tl);y<=GET_TILE_Y(PathFinderInfo->start_tile_br);y++) {
|
for (y=GET_TILE_Y(PathFinderInfo->start_tile_tl);y<=GET_TILE_Y(PathFinderInfo->start_tile_br);y++) {
|
||||||
start_node.node.tile = TILE_XY(x,y);
|
start_node.node.tile = TILE_XY(x,y);
|
||||||
result->addstart(result, &start_node.node);
|
result->addstart(result, &start_node.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To reuse AyStar we sometimes have to clean all the memory
|
// To reuse AyStar we sometimes have to clean all the memory
|
||||||
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo) {
|
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo) {
|
||||||
PathNode start_node;
|
PathNode start_node;
|
||||||
uint x,y;
|
uint x,y;
|
||||||
|
|
||||||
aystar->clear(aystar);
|
aystar->clear(aystar);
|
||||||
|
|
||||||
// Set the user_data to the PathFinderInfo
|
// Set the user_data to the PathFinderInfo
|
||||||
aystar->user_target = PathFinderInfo;
|
aystar->user_target = PathFinderInfo;
|
||||||
|
|
||||||
// Set the start node
|
// Set the start node
|
||||||
start_node.parent = NULL;
|
start_node.parent = NULL;
|
||||||
start_node.node.direction = 0;
|
start_node.node.direction = 0;
|
||||||
start_node.node.user_data[0] = 0;
|
start_node.node.user_data[0] = 0;
|
||||||
start_node.node.tile = PathFinderInfo->start_tile_tl;
|
start_node.node.tile = PathFinderInfo->start_tile_tl;
|
||||||
|
|
||||||
// Now we add all the starting tiles
|
// Now we add all the starting tiles
|
||||||
for (x=GET_TILE_X(PathFinderInfo->start_tile_tl);x<=GET_TILE_X(PathFinderInfo->start_tile_br);x++) {
|
for (x=GET_TILE_X(PathFinderInfo->start_tile_tl);x<=GET_TILE_X(PathFinderInfo->start_tile_br);x++) {
|
||||||
for (y=GET_TILE_Y(PathFinderInfo->start_tile_tl);y<=GET_TILE_Y(PathFinderInfo->start_tile_br);y++) {
|
for (y=GET_TILE_Y(PathFinderInfo->start_tile_tl);y<=GET_TILE_Y(PathFinderInfo->start_tile_br);y++) {
|
||||||
if (!(IS_TILETYPE(TILE_XY(x,y), MP_CLEAR) || IS_TILETYPE(TILE_XY(x,y), MP_TREES))) continue;
|
if (!(IS_TILETYPE(TILE_XY(x,y), MP_CLEAR) || IS_TILETYPE(TILE_XY(x,y), MP_TREES))) continue;
|
||||||
if (!TestCanBuildStationHere(TILE_XY(x,y),TEST_STATION_NO_DIR)) continue;
|
if (!TestCanBuildStationHere(TILE_XY(x,y),TEST_STATION_NO_DIR)) continue;
|
||||||
start_node.node.tile = TILE_XY(x,y);
|
start_node.node.tile = TILE_XY(x,y);
|
||||||
aystar->addstart(aystar, &start_node.node);
|
aystar->addstart(aystar, &start_node.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The h-value, simple calculation
|
// The h-value, simple calculation
|
||||||
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
||||||
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
||||||
int r, r2;
|
int r, r2;
|
||||||
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
|
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
|
||||||
// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
|
// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
|
||||||
r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl + _tiles_around[PathFinderInfo->end_direction]);
|
r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl + _tiles_around[PathFinderInfo->end_direction]);
|
||||||
r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br + _tiles_around[PathFinderInfo->end_direction]);
|
r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br + _tiles_around[PathFinderInfo->end_direction]);
|
||||||
} else {
|
} else {
|
||||||
// No direction, so just get the fastest route to the station
|
// No direction, so just get the fastest route to the station
|
||||||
r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl);
|
r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl);
|
||||||
r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br);
|
r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br);
|
||||||
}
|
}
|
||||||
// See if the bottomright is faster then the topleft..
|
// See if the bottomright is faster then the topleft..
|
||||||
if (r2 < r) r = r2;
|
if (r2 < r) r = r2;
|
||||||
return r * AI_PATHFINDER_H_MULTIPLER;
|
return r * AI_PATHFINDER_H_MULTIPLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We found the end.. let's get the route back and put it in an array
|
// We found the end.. let's get the route back and put it in an array
|
||||||
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current) {
|
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current) {
|
||||||
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
PathNode *parent = ¤t->path;
|
PathNode *parent = ¤t->path;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PathFinderInfo->route_extra[i] = parent->node.user_data[0];
|
PathFinderInfo->route_extra[i] = parent->node.user_data[0];
|
||||||
PathFinderInfo->route[i++] = parent->node.tile;
|
PathFinderInfo->route[i++] = parent->node.tile;
|
||||||
if (i > lengthof(PathFinderInfo->route)) {
|
if (i > lengthof(PathFinderInfo->route)) {
|
||||||
// We ran out of space for the PathFinder
|
// We ran out of space for the PathFinder
|
||||||
DEBUG(ai,0)("[AiPathFinder] Ran out of spacein the route[] array!!!");
|
DEBUG(ai,0)("[AiPathFinder] Ran out of spacein the route[] array!!!");
|
||||||
PathFinderInfo->route_length = -1; // -1 indicates out of space
|
PathFinderInfo->route_length = -1; // -1 indicates out of space
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parent = parent->parent;
|
parent = parent->parent;
|
||||||
} while (parent != NULL);
|
} while (parent != NULL);
|
||||||
PathFinderInfo->route_length = i;
|
PathFinderInfo->route_length = i;
|
||||||
DEBUG(ai,1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching",i,Hash_Size(&aystar->ClosedListHash));
|
DEBUG(ai,1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching",i,Hash_Size(&aystar->ClosedListHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
// What tiles are around us.
|
// What tiles are around us.
|
||||||
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current) {
|
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current) {
|
||||||
int i, r, dir;
|
int i, r, dir;
|
||||||
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
||||||
|
|
||||||
aystar->num_neighbours = 0;
|
aystar->num_neighbours = 0;
|
||||||
|
|
||||||
// Go through all surrounding tiles and check if they are within the limits
|
// Go through all surrounding tiles and check if they are within the limits
|
||||||
for (i=0;i<4;i++) {
|
for (i=0;i<4;i++) {
|
||||||
if (GET_TILE_X(_tiles_around[i] + current->path.node.tile) > 1 && GET_TILE_X(_tiles_around[i] + current->path.node.tile) < TILE_X_MAX - 1 &&
|
if (GET_TILE_X(_tiles_around[i] + current->path.node.tile) > 1 && GET_TILE_X(_tiles_around[i] + current->path.node.tile) < TILE_X_MAX - 1 &&
|
||||||
GET_TILE_Y(_tiles_around[i] + current->path.node.tile) > 1 && GET_TILE_Y(_tiles_around[i] + current->path.node.tile) < TILE_Y_MAX - 1) {
|
GET_TILE_Y(_tiles_around[i] + current->path.node.tile) > 1 && GET_TILE_Y(_tiles_around[i] + current->path.node.tile) < TILE_Y_MAX - 1) {
|
||||||
// We also directly test if the current tile can connect to this tile..
|
// We also directly test if the current tile can connect to this tile..
|
||||||
// We do this simply by just building the tile!
|
// We do this simply by just building the tile!
|
||||||
|
|
||||||
// If the next step is a bridge, we have to enter it the right way
|
// If the next step is a bridge, we have to enter it the right way
|
||||||
if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile + _tiles_around[i])) {
|
if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile + _tiles_around[i])) {
|
||||||
if (IS_TILETYPE(current->path.node.tile + _tiles_around[i], MP_TUNNELBRIDGE)) {
|
if (IS_TILETYPE(current->path.node.tile + _tiles_around[i], MP_TUNNELBRIDGE)) {
|
||||||
// An existing bridge... let's test the direction ;)
|
// An existing bridge... let's test the direction ;)
|
||||||
if ((_map5[current->path.node.tile + _tiles_around[i]] & 1) != (i & 1)) continue;
|
if ((_map5[current->path.node.tile + _tiles_around[i]] & 1) != (i & 1)) continue;
|
||||||
// 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^2) != (_map5[current->path.node.tile + _tiles_around[i]] & 3)) continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// But also if we are on a bridge, we can only move a certain direction
|
// But also if we are on a bridge, we can only move a certain direction
|
||||||
if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile)) {
|
if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile)) {
|
||||||
if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) {
|
if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) {
|
||||||
// An existing bridge/tunnel... let's test the direction ;)
|
// An existing bridge/tunnel... let's test the direction ;)
|
||||||
if ((_map5[current->path.node.tile] & 1) != (i & 1)) continue;
|
if ((_map5[current->path.node.tile] & 1) != (i & 1)) continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
|
if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
|
||||||
(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
|
(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
|
||||||
// We are a bridge/tunnel, how cool!!
|
// We are a bridge/tunnel, how cool!!
|
||||||
// This means we can only point forward.. get the direction from the user_data
|
// This means we can only point forward.. get the direction from the user_data
|
||||||
if (i != (current->path.node.user_data[0] >> 8)) continue;
|
if (i != (current->path.node.user_data[0] >> 8)) continue;
|
||||||
}
|
}
|
||||||
dir = 0;
|
dir = 0;
|
||||||
|
|
||||||
// First, check if we have a parent
|
// First, check if we have a parent
|
||||||
if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
|
if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
|
||||||
// If not, this means we are at the starting station
|
// If not, this means we are at the starting station
|
||||||
if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
|
if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
|
||||||
// We do need a direction?
|
// We do need a direction?
|
||||||
if (AiNew_GetDirection(current->path.node.tile, current->path.node.tile + _tiles_around[i]) != PathFinderInfo->start_direction)
|
if (AiNew_GetDirection(current->path.node.tile, current->path.node.tile + _tiles_around[i]) != PathFinderInfo->start_direction)
|
||||||
// We are not pointing the right way, invalid tile
|
// We are not pointing the right way, invalid tile
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (current->path.node.user_data[0] == 0) {
|
} else if (current->path.node.user_data[0] == 0) {
|
||||||
if (PathFinderInfo->rail_or_road) {
|
if (PathFinderInfo->rail_or_road) {
|
||||||
// Rail check
|
// Rail check
|
||||||
dir = AiNew_GetRailDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + _tiles_around[i]);
|
dir = AiNew_GetRailDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + _tiles_around[i]);
|
||||||
r = DoCommandByTile(current->path.node.tile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
|
r = DoCommandByTile(current->path.node.tile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
|
||||||
if (r == CMD_ERROR) continue;
|
if (r == CMD_ERROR) continue;
|
||||||
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
|
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
|
||||||
if (current->path.parent->parent != NULL) {
|
if (current->path.parent->parent != NULL) {
|
||||||
// Check if we don't make a 90degree curve
|
// Check if we don't make a 90degree curve
|
||||||
int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, current->path.node.tile);
|
int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, current->path.node.tile);
|
||||||
if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
|
if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// Road check
|
// Road check
|
||||||
dir = AiNew_GetRoadDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + _tiles_around[i]);
|
dir = AiNew_GetRoadDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + _tiles_around[i]);
|
||||||
if (AI_PATHFINDER_IS_ROAD(current->path.node.tile)) {
|
if (AI_PATHFINDER_IS_ROAD(current->path.node.tile)) {
|
||||||
if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) {
|
if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) {
|
||||||
// We have a bridge, how nicely! We should mark it...
|
// We have a bridge, how nicely! We should mark it...
|
||||||
dir = 0;
|
dir = 0;
|
||||||
} else {
|
} else {
|
||||||
// It already has road.. check if we miss any bits!
|
// It already has road.. check if we miss any bits!
|
||||||
if ((_map5[current->path.node.tile] & dir) != dir) {
|
if ((_map5[current->path.node.tile] & dir) != dir) {
|
||||||
// We do miss some pieces :(
|
// We do miss some pieces :(
|
||||||
dir &= ~_map5[current->path.node.tile];
|
dir &= ~_map5[current->path.node.tile];
|
||||||
} else {
|
} else {
|
||||||
dir = 0;
|
dir = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Only destruct things if it is MP_CLEAR of MP_TREES
|
// Only destruct things if it is MP_CLEAR of MP_TREES
|
||||||
if (dir != 0) {
|
if (dir != 0) {
|
||||||
r = DoCommandByTile(current->path.node.tile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
|
r = DoCommandByTile(current->path.node.tile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
|
||||||
if (r == CMD_ERROR) continue;
|
if (r == CMD_ERROR) continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tile can be connected
|
// The tile can be connected
|
||||||
aystar->neighbours[aystar->num_neighbours].tile = _tiles_around[i] + current->path.node.tile;
|
aystar->neighbours[aystar->num_neighbours].tile = _tiles_around[i] + current->path.node.tile;
|
||||||
aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
|
aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
|
||||||
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next step, check for bridges and tunnels
|
// Next step, check for bridges and tunnels
|
||||||
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
|
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
|
||||||
|
|
||||||
TileInfo ti;
|
TileInfo ti;
|
||||||
// First we get the dir from this tile and his parent
|
// First we get the dir from this tile and his parent
|
||||||
int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
|
int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
|
||||||
// It means we can only walk with the track, so the bridge has to be in the same direction
|
// It means we can only walk with the track, so the bridge has to be in the same direction
|
||||||
TileIndex tile = current->path.node.tile;
|
TileIndex tile = current->path.node.tile;
|
||||||
TileIndex new_tile = tile;
|
TileIndex new_tile = tile;
|
||||||
|
|
||||||
FindLandscapeHeightByTile(&ti, tile);
|
FindLandscapeHeightByTile(&ti, tile);
|
||||||
|
|
||||||
// Bridges can only be build on land that is not flat
|
// Bridges can only be build on land that is not flat
|
||||||
// And if there is a road or rail blocking
|
// And if there is a road or rail blocking
|
||||||
if (ti.tileh != 0 ||
|
if (ti.tileh != 0 ||
|
||||||
(PathFinderInfo->rail_or_road && IS_TILETYPE(tile + _tiles_around[dir], MP_STREET)) ||
|
(PathFinderInfo->rail_or_road && IS_TILETYPE(tile + _tiles_around[dir], MP_STREET)) ||
|
||||||
(!PathFinderInfo->rail_or_road && IS_TILETYPE(tile + _tiles_around[dir], MP_RAILWAY))) {
|
(!PathFinderInfo->rail_or_road && IS_TILETYPE(tile + _tiles_around[dir], MP_RAILWAY))) {
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
new_tile += _tiles_around[dir];
|
new_tile += _tiles_around[dir];
|
||||||
|
|
||||||
// Precheck, is the length allowed?
|
// Precheck, is the length allowed?
|
||||||
if (!CheckBridge_Stuff(0,GetBridgeLength(tile, new_tile))) break;
|
if (!CheckBridge_Stuff(0,GetBridgeLength(tile, new_tile))) break;
|
||||||
|
|
||||||
// Check if we hit the station-tile.. we don't like that!
|
// Check if we hit the station-tile.. we don't like that!
|
||||||
if (TILES_BETWEEN(new_tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) break;
|
if (TILES_BETWEEN(new_tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) break;
|
||||||
|
|
||||||
// Try building the bridge..
|
// Try building the bridge..
|
||||||
r = DoCommandByTile(tile, new_tile, (0<<8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
|
r = DoCommandByTile(tile, new_tile, (0<<8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
|
||||||
if (r == CMD_ERROR) continue;
|
if (r == CMD_ERROR) continue;
|
||||||
// We can build a bridge here.. add him to the neighbours
|
// We can build a bridge here.. add him to the neighbours
|
||||||
aystar->neighbours[aystar->num_neighbours].tile = new_tile;
|
aystar->neighbours[aystar->num_neighbours].tile = new_tile;
|
||||||
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
|
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
|
||||||
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
||||||
// We can only have 12 neighbours, and we need 1 left for tunnels
|
// We can only have 12 neighbours, and we need 1 left for tunnels
|
||||||
if (aystar->num_neighbours == 11) break;
|
if (aystar->num_neighbours == 11) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, check for tunnels!
|
// Next, check for tunnels!
|
||||||
// Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction
|
// Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction
|
||||||
// For now, we check both sides for this tile.. terraforming gives fuzzy result
|
// For now, we check both sides for this tile.. terraforming gives fuzzy result
|
||||||
if ((dir == 0 && ti.tileh == 12) ||
|
if ((dir == 0 && ti.tileh == 12) ||
|
||||||
(dir == 1 && ti.tileh == 6) ||
|
(dir == 1 && ti.tileh == 6) ||
|
||||||
(dir == 2 && ti.tileh == 3) ||
|
(dir == 2 && ti.tileh == 3) ||
|
||||||
(dir == 3 && ti.tileh == 9)) {
|
(dir == 3 && ti.tileh == 9)) {
|
||||||
// Now simply check if a tunnel can be build
|
// Now simply check if a tunnel can be build
|
||||||
r = DoCommandByTile(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
|
r = DoCommandByTile(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
|
||||||
FindLandscapeHeightByTile(&ti, _build_tunnel_endtile);
|
FindLandscapeHeightByTile(&ti, _build_tunnel_endtile);
|
||||||
if (r != CMD_ERROR && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) {
|
if (r != CMD_ERROR && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) {
|
||||||
aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
|
aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
|
||||||
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
|
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
|
||||||
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
aystar->neighbours[aystar->num_neighbours++].direction = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint GetRailFoundation(uint tileh, uint bits);
|
extern uint GetRailFoundation(uint tileh, uint bits);
|
||||||
extern uint GetRoadFoundation(uint tileh, uint bits);
|
extern uint GetRoadFoundation(uint tileh, uint bits);
|
||||||
extern uint GetBridgeFoundation(uint tileh, byte direction);
|
extern uint GetBridgeFoundation(uint tileh, byte direction);
|
||||||
enum {
|
enum {
|
||||||
BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
|
BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The most important function: it calculates the g-value
|
// The most important function: it calculates the g-value
|
||||||
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
||||||
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
|
||||||
int r, res = 0;
|
int r, res = 0;
|
||||||
TileInfo ti, parent_ti;
|
TileInfo ti, parent_ti;
|
||||||
|
|
||||||
// Gather some information about the tile..
|
// Gather some information about the tile..
|
||||||
FindLandscapeHeightByTile(&ti, current->tile);
|
FindLandscapeHeightByTile(&ti, current->tile);
|
||||||
FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile);
|
FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile);
|
||||||
|
|
||||||
// Check if we hit the end-tile
|
// Check if we hit the end-tile
|
||||||
if (TILES_BETWEEN(current->tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) {
|
if (TILES_BETWEEN(current->tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) {
|
||||||
// We are at the end-tile, check if we had a direction or something...
|
// We are at the end-tile, check if we had a direction or something...
|
||||||
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction)
|
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction)
|
||||||
// We are not pointing the right way, invalid tile
|
// We are not pointing the right way, invalid tile
|
||||||
return AYSTAR_INVALID_NODE;
|
return AYSTAR_INVALID_NODE;
|
||||||
// If it was valid, drop out.. we don't build on the endtile
|
// If it was valid, drop out.. we don't build on the endtile
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give everything a small penalty
|
// Give everything a small penalty
|
||||||
res += AI_PATHFINDER_PENALTY;
|
res += AI_PATHFINDER_PENALTY;
|
||||||
|
|
||||||
if (!PathFinderInfo->rail_or_road) {
|
if (!PathFinderInfo->rail_or_road) {
|
||||||
// Road has the lovely advantage it can use other road... check if
|
// Road has the lovely advantage it can use other road... check if
|
||||||
// the current tile is road, and if so, give a good bonus
|
// the current tile is road, and if so, give a good bonus
|
||||||
if (AI_PATHFINDER_IS_ROAD(current->tile)) {
|
if (AI_PATHFINDER_IS_ROAD(current->tile)) {
|
||||||
res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
|
res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should give a penalty when the tile is going up or down.. this is one way to do so!
|
// We should give a penalty when the tile is going up or down.. this is one way to do so!
|
||||||
// Too bad we have to count it from the parent.. but that is not so bad
|
// Too bad we have to count it from the parent.. but that is not so bad
|
||||||
if (parent_ti.tileh != 0 && parent->path.parent != NULL) {
|
if (parent_ti.tileh != 0 && parent->path.parent != NULL) {
|
||||||
// Skip if the tile was from a bridge or tunnel
|
// Skip if the tile was from a bridge or tunnel
|
||||||
if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
|
if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
|
||||||
if (PathFinderInfo->rail_or_road) {
|
if (PathFinderInfo->rail_or_road) {
|
||||||
r = GetRailFoundation(parent_ti.tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
|
r = GetRailFoundation(parent_ti.tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
|
||||||
// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
|
// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
|
||||||
if (r >= 15 || (r == 0 && (BRIDGE_NO_FOUNDATION & (1 << ti.tileh)))) {
|
if (r >= 15 || (r == 0 && (BRIDGE_NO_FOUNDATION & (1 << ti.tileh)))) {
|
||||||
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!(AI_PATHFINDER_IS_ROAD(parent->path.node.tile) && IS_TILETYPE(parent->path.node.tile, MP_TUNNELBRIDGE))) {
|
if (!(AI_PATHFINDER_IS_ROAD(parent->path.node.tile) && IS_TILETYPE(parent->path.node.tile, MP_TUNNELBRIDGE))) {
|
||||||
r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
|
r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
|
||||||
if (r >= 15 || r == 0)
|
if (r >= 15 || r == 0)
|
||||||
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we part of a tunnel?
|
// Are we part of a tunnel?
|
||||||
if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
|
if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
|
||||||
// Tunnels are very expensive when build on long routes..
|
// Tunnels are very expensive when build on long routes..
|
||||||
// Ironicly, we are using BridgeCode here ;)
|
// Ironicly, we are using BridgeCode here ;)
|
||||||
r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
|
r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
|
||||||
res += r + (r >> 8);
|
res += r + (r >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we part of a bridge?
|
// Are we part of a bridge?
|
||||||
if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
|
if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
|
||||||
// That means for every length a penalty
|
// That means for every length a penalty
|
||||||
res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
|
res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
|
||||||
// Check if we are going up or down, first for the starting point
|
// Check if we are going up or down, first for the starting point
|
||||||
// In user_data[0] is at the 8th bit the direction
|
// In user_data[0] is at the 8th bit the direction
|
||||||
if (!(BRIDGE_NO_FOUNDATION & (1 << parent_ti.tileh))) {
|
if (!(BRIDGE_NO_FOUNDATION & (1 << parent_ti.tileh))) {
|
||||||
if (GetBridgeFoundation(parent_ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
|
if (GetBridgeFoundation(parent_ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
|
||||||
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
||||||
}
|
}
|
||||||
// Second for the end point
|
// Second for the end point
|
||||||
if (!(BRIDGE_NO_FOUNDATION & (1 << ti.tileh))) {
|
if (!(BRIDGE_NO_FOUNDATION & (1 << ti.tileh))) {
|
||||||
if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
|
if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
|
||||||
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
||||||
}
|
}
|
||||||
if (parent_ti.tileh == 0)
|
if (parent_ti.tileh == 0)
|
||||||
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
||||||
if (ti.tileh == 0)
|
if (ti.tileh == 0)
|
||||||
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To prevent the AI from taking the fastest way in tiles, but not the fastest way
|
// To prevent the AI from taking the fastest way in tiles, but not the fastest way
|
||||||
// in speed, we have to give a good penalty to direction changing
|
// in speed, we have to give a good penalty to direction changing
|
||||||
// This way, we get almost the fastest way in tiles, and a very good speed on the track
|
// This way, we get almost the fastest way in tiles, and a very good speed on the track
|
||||||
if (!PathFinderInfo->rail_or_road) {
|
if (!PathFinderInfo->rail_or_road) {
|
||||||
if (parent->path.parent != NULL &&
|
if (parent->path.parent != NULL &&
|
||||||
AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
|
AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
|
||||||
// When road exists, we don't like turning, but its free, so don't be to piggy about it
|
// When road exists, we don't like turning, but its free, so don't be to piggy about it
|
||||||
if (AI_PATHFINDER_IS_ROAD(parent->path.node.tile))
|
if (AI_PATHFINDER_IS_ROAD(parent->path.node.tile))
|
||||||
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
|
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
|
||||||
else
|
else
|
||||||
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
|
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For rail we have 1 exeption: diagonal rail..
|
// For rail we have 1 exeption: diagonal rail..
|
||||||
// So we fetch 2 raildirection. That of the current one, and of the one before that
|
// So we fetch 2 raildirection. That of the current one, and of the one before that
|
||||||
if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
|
if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
|
||||||
int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
|
int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
|
||||||
int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
|
int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
|
||||||
// First, see if we are on diagonal path, that is better then straight path
|
// First, see if we are on diagonal path, that is better then straight path
|
||||||
if (dir1 > 1) { res -= AI_PATHFINDER_DIAGONAL_BONUS; }
|
if (dir1 > 1) { res -= AI_PATHFINDER_DIAGONAL_BONUS; }
|
||||||
|
|
||||||
// First see if they are different
|
// First see if they are different
|
||||||
if (dir1 != dir2) {
|
if (dir1 != dir2) {
|
||||||
// dir 2 and 3 are 1 diagonal track, and 4 and 5.
|
// dir 2 and 3 are 1 diagonal track, and 4 and 5.
|
||||||
if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
|
if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
|
||||||
// It is not, so we changed of direction
|
// It is not, so we changed of direction
|
||||||
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
|
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
|
||||||
}
|
}
|
||||||
if (parent->path.parent->parent->parent != NULL) {
|
if (parent->path.parent->parent->parent != NULL) {
|
||||||
int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
|
int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
|
||||||
// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
|
// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
|
||||||
if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
|
if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
|
||||||
res += AI_PATHFINDER_CURVE_PENALTY;
|
res += AI_PATHFINDER_CURVE_PENALTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Res should never be below zero.. if so, make it zero!
|
// Res should never be below zero.. if so, make it zero!
|
||||||
if (res < 0) { res = 0; }
|
if (res < 0) { res = 0; }
|
||||||
|
|
||||||
// Return our value
|
// Return our value
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
164
ai_shared.c
164
ai_shared.c
|
@ -1,82 +1,82 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ttd.h"
|
#include "ttd.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "ai.h"
|
#include "ai.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
|
||||||
// 1 = horz
|
// 1 = horz
|
||||||
// 2 = dig up-left
|
// 2 = dig up-left
|
||||||
// 3 = dig down-right
|
// 3 = dig down-right
|
||||||
// 4 = dig down-left
|
// 4 = dig down-left
|
||||||
// 5 = dig up-right
|
// 5 = dig up-right
|
||||||
|
|
||||||
int x1, x2, x3;
|
int x1, x2, x3;
|
||||||
int y1, y2, y3;
|
int y1, y2, y3;
|
||||||
|
|
||||||
x1 = GET_TILE_X(tile_a);
|
x1 = GET_TILE_X(tile_a);
|
||||||
x2 = GET_TILE_X(tile_b);
|
x2 = GET_TILE_X(tile_b);
|
||||||
x3 = GET_TILE_X(tile_c);
|
x3 = GET_TILE_X(tile_c);
|
||||||
|
|
||||||
y1 = GET_TILE_Y(tile_a);
|
y1 = GET_TILE_Y(tile_a);
|
||||||
y2 = GET_TILE_Y(tile_b);
|
y2 = GET_TILE_Y(tile_b);
|
||||||
y3 = GET_TILE_Y(tile_c);
|
y3 = GET_TILE_Y(tile_c);
|
||||||
|
|
||||||
if (y1 == y2 && y2 == y3) return 0;
|
if (y1 == y2 && y2 == y3) return 0;
|
||||||
if (x1 == x2 && x2 == x3) return 1;
|
if (x1 == x2 && x2 == x3) return 1;
|
||||||
if (y2 > y1) {
|
if (y2 > y1) {
|
||||||
if (x2 > x3) return 2;
|
if (x2 > x3) return 2;
|
||||||
else return 4;
|
else return 4;
|
||||||
}
|
}
|
||||||
if (x2 > x1) {
|
if (x2 > x1) {
|
||||||
if (y2 > y3) return 2;
|
if (y2 > y3) return 2;
|
||||||
else return 5;
|
else return 5;
|
||||||
}
|
}
|
||||||
if (y1 > y2) {
|
if (y1 > y2) {
|
||||||
if (x2 > x3) return 5;
|
if (x2 > x3) return 5;
|
||||||
else return 3;
|
else return 3;
|
||||||
}
|
}
|
||||||
if (x1 > x2) {
|
if (x1 > x2) {
|
||||||
if (y2 > y3) return 4;
|
if (y2 > y3) return 4;
|
||||||
else return 3;
|
else return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 x1, x2, x3;
|
int x1, x2, x3;
|
||||||
int y1, y2, y3;
|
int y1, y2, y3;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
x1 = GET_TILE_X(tile_a);
|
x1 = GET_TILE_X(tile_a);
|
||||||
x2 = GET_TILE_X(tile_b);
|
x2 = GET_TILE_X(tile_b);
|
||||||
x3 = GET_TILE_X(tile_c);
|
x3 = GET_TILE_X(tile_c);
|
||||||
|
|
||||||
y1 = GET_TILE_Y(tile_a);
|
y1 = GET_TILE_Y(tile_a);
|
||||||
y2 = GET_TILE_Y(tile_b);
|
y2 = GET_TILE_Y(tile_b);
|
||||||
y3 = GET_TILE_Y(tile_c);
|
y3 = GET_TILE_Y(tile_c);
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
if (x1 < x2) r += 8;
|
if (x1 < x2) r += 8;
|
||||||
if (y1 < y2) r += 1;
|
if (y1 < y2) r += 1;
|
||||||
if (x1 > x2) r += 2;
|
if (x1 > x2) r += 2;
|
||||||
if (y1 > y2) r += 4;
|
if (y1 > y2) r += 4;
|
||||||
|
|
||||||
if (x2 < x3) r += 2;
|
if (x2 < x3) r += 2;
|
||||||
if (y2 < y3) r += 4;
|
if (y2 < y3) r += 4;
|
||||||
if (x2 > x3) r += 8;
|
if (x2 > x3) r += 8;
|
||||||
if (y2 > y3) r += 1;
|
if (y2 > y3) r += 1;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get's the direction between 2 tiles seen from tile_a
|
// Get's the direction between 2 tiles seen from tile_a
|
||||||
int AiNew_GetDirection(uint tile_a, uint tile_b) {
|
int AiNew_GetDirection(uint tile_a, uint tile_b) {
|
||||||
if (GET_TILE_Y(tile_a) < GET_TILE_Y(tile_b)) return 1;
|
if (GET_TILE_Y(tile_a) < GET_TILE_Y(tile_b)) return 1;
|
||||||
if (GET_TILE_Y(tile_a) > GET_TILE_Y(tile_b)) return 3;
|
if (GET_TILE_Y(tile_a) > GET_TILE_Y(tile_b)) return 3;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
542
aystar.c
542
aystar.c
|
@ -1,271 +1,271 @@
|
||||||
/*
|
/*
|
||||||
* This file has the core function for AyStar
|
* This file has the core function for AyStar
|
||||||
* AyStar is a fast pathfinding routine and is used for things like
|
* AyStar is a fast pathfinding routine and is used for things like
|
||||||
* AI_pathfinding and Train_pathfinding.
|
* AI_pathfinding and Train_pathfinding.
|
||||||
* For more information about AyStar (A* Algorithm), you can look at
|
* For more information about AyStar (A* Algorithm), you can look at
|
||||||
* http://en.wikipedia.org/wiki/A-star_search_algorithm
|
* http://en.wikipedia.org/wiki/A-star_search_algorithm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Friendly reminder:
|
* Friendly reminder:
|
||||||
* Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
|
* Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
|
||||||
* And when not free'd, it can cause system-crashes.
|
* And when not free'd, it can cause system-crashes.
|
||||||
* Also remember that when you stop an algorithm before it is finished, your
|
* Also remember that when you stop an algorithm before it is finished, your
|
||||||
* should call clear() yourself!
|
* should call clear() yourself!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ttd.h"
|
#include "ttd.h"
|
||||||
#include "aystar.h"
|
#include "aystar.h"
|
||||||
// This looks in the Hash if a node exists in ClosedList
|
// This looks in the Hash if a node exists in ClosedList
|
||||||
// If so, it returns the PathNode, else NULL
|
// If so, it returns the PathNode, else NULL
|
||||||
PathNode *AyStarMain_ClosedList_IsInList(AyStar *aystar, AyStarNode *node) {
|
PathNode *AyStarMain_ClosedList_IsInList(AyStar *aystar, AyStarNode *node) {
|
||||||
return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
|
return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This adds a node to the ClosedList
|
// This adds a node to the ClosedList
|
||||||
// It makes a copy of the data
|
// It makes a copy of the data
|
||||||
void AyStarMain_ClosedList_Add(AyStar *aystar, PathNode *node) {
|
void AyStarMain_ClosedList_Add(AyStar *aystar, PathNode *node) {
|
||||||
// Add a node to the ClosedList
|
// Add a node to the ClosedList
|
||||||
PathNode *new_node = malloc(sizeof(PathNode));
|
PathNode *new_node = malloc(sizeof(PathNode));
|
||||||
*new_node = *node;
|
*new_node = *node;
|
||||||
Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
|
Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a node is in the OpenList
|
// Checks if a node is in the OpenList
|
||||||
// If so, it returns the OpenListNode, else NULL
|
// If so, it returns the OpenListNode, else NULL
|
||||||
OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, AyStarNode *node) {
|
OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, AyStarNode *node) {
|
||||||
return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
|
return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the best node from OpenList
|
// Gets the best node from OpenList
|
||||||
// returns the best node, or NULL of none is found
|
// returns the best node, or NULL of none is found
|
||||||
// Also it deletes the node from the OpenList
|
// Also it deletes the node from the OpenList
|
||||||
OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar) {
|
OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar) {
|
||||||
// Return the item the Queue returns.. the best next OpenList item.
|
// Return the item the Queue returns.. the best next OpenList item.
|
||||||
OpenListNode* res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
|
OpenListNode* res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
|
Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a node to the OpenList
|
// Adds a node to the OpenList
|
||||||
// It makes a copy of node, and puts the pointer of parent in the struct
|
// It makes a copy of node, and puts the pointer of parent in the struct
|
||||||
void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g, int userdata) {
|
void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g, int userdata) {
|
||||||
// Add a new Node to the OpenList
|
// Add a new Node to the OpenList
|
||||||
OpenListNode* new_node = malloc(sizeof(OpenListNode));
|
OpenListNode* new_node = malloc(sizeof(OpenListNode));
|
||||||
new_node->g = g;
|
new_node->g = g;
|
||||||
new_node->path.parent = parent;
|
new_node->path.parent = parent;
|
||||||
new_node->path.node = *node;
|
new_node->path.node = *node;
|
||||||
Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
|
Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
|
||||||
|
|
||||||
// Add it to the queue
|
// Add it to the queue
|
||||||
aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
|
aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks one tile and calculate his f-value
|
* Checks one tile and calculate his f-value
|
||||||
* return values:
|
* return values:
|
||||||
* AYSTAR_DONE : indicates we are done
|
* AYSTAR_DONE : indicates we are done
|
||||||
*/
|
*/
|
||||||
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
|
||||||
int new_f, new_g, new_h;
|
int new_f, new_g, new_h;
|
||||||
PathNode *closedlist_parent;
|
PathNode *closedlist_parent;
|
||||||
OpenListNode *check;
|
OpenListNode *check;
|
||||||
|
|
||||||
// Check the new node against the ClosedList
|
// Check the new node against the ClosedList
|
||||||
if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
|
if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
|
||||||
|
|
||||||
// Calculate the G-value for this node
|
// Calculate the G-value for this node
|
||||||
new_g = aystar->CalculateG(aystar, current, parent);
|
new_g = aystar->CalculateG(aystar, current, parent);
|
||||||
// If the value was INVALID_NODE, we don't do anything with this node
|
// If the value was INVALID_NODE, we don't do anything with this node
|
||||||
if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
|
if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
|
||||||
|
|
||||||
// There should not be given any other error-code..
|
// There should not be given any other error-code..
|
||||||
assert(new_g >= 0);
|
assert(new_g >= 0);
|
||||||
// Add the parent g-value to the new g-value
|
// Add the parent g-value to the new g-value
|
||||||
new_g += parent->g;
|
new_g += parent->g;
|
||||||
if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
|
if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
|
||||||
|
|
||||||
// Calculate the h-value
|
// Calculate the h-value
|
||||||
new_h = aystar->CalculateH(aystar, current, parent);
|
new_h = aystar->CalculateH(aystar, current, parent);
|
||||||
// There should not be given any error-code..
|
// There should not be given any error-code..
|
||||||
assert(new_h >= 0);
|
assert(new_h >= 0);
|
||||||
|
|
||||||
// The f-value if g + h
|
// The f-value if g + h
|
||||||
new_f = new_g + new_h;
|
new_f = new_g + new_h;
|
||||||
|
|
||||||
// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
|
// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
|
||||||
closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
|
closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
|
||||||
|
|
||||||
// Check if this item is already in the OpenList
|
// Check if this item is already in the OpenList
|
||||||
if ((check = AyStarMain_OpenList_IsInList(aystar, current)) != NULL) {
|
if ((check = AyStarMain_OpenList_IsInList(aystar, current)) != NULL) {
|
||||||
int i;
|
int i;
|
||||||
// Yes, check if this g value is lower..
|
// Yes, check if this g value is lower..
|
||||||
if (new_g > check->g) return AYSTAR_DONE;
|
if (new_g > check->g) return AYSTAR_DONE;
|
||||||
aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
|
aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
|
||||||
// It is lower, so change it to this item
|
// It is lower, so change it to this item
|
||||||
check->g = new_g;
|
check->g = new_g;
|
||||||
check->path.parent = closedlist_parent;
|
check->path.parent = closedlist_parent;
|
||||||
/* Copy user data, will probably have changed */
|
/* Copy user data, will probably have changed */
|
||||||
for (i=0;i<lengthof(current->user_data);i++)
|
for (i=0;i<lengthof(current->user_data);i++)
|
||||||
check->path.node.user_data[i] = current->user_data[i];
|
check->path.node.user_data[i] = current->user_data[i];
|
||||||
// Readd him in the OpenListQueue
|
// Readd him in the OpenListQueue
|
||||||
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
|
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
|
||||||
} else {
|
} else {
|
||||||
// A new node, add him to the OpenList
|
// A new node, add him to the OpenList
|
||||||
AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g, 0);
|
AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AYSTAR_DONE;
|
return AYSTAR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is the core of AyStar. It handles one item and checks
|
* This function is the core of AyStar. It handles one item and checks
|
||||||
* his neighbour items. If they are valid, they are added to be checked too.
|
* his neighbour items. If they are valid, they are added to be checked too.
|
||||||
* return values:
|
* return values:
|
||||||
* AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
|
* AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
|
||||||
* has been found.
|
* has been found.
|
||||||
* AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
|
* AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
|
||||||
* reached.
|
* reached.
|
||||||
* AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
|
* AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
|
||||||
* AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
|
* AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
|
||||||
*/
|
*/
|
||||||
int AyStarMain_Loop(AyStar *aystar) {
|
int AyStarMain_Loop(AyStar *aystar) {
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
// Get the best node from OpenList
|
// Get the best node from OpenList
|
||||||
OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
|
OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
|
||||||
// If empty, drop an error
|
// If empty, drop an error
|
||||||
if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
|
if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
|
||||||
|
|
||||||
// Check for end node and if found, return that code
|
// Check for end node and if found, return that code
|
||||||
if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
|
if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
|
||||||
if (aystar->FoundEndNode != NULL)
|
if (aystar->FoundEndNode != NULL)
|
||||||
aystar->FoundEndNode(aystar, current);
|
aystar->FoundEndNode(aystar, current);
|
||||||
free(current);
|
free(current);
|
||||||
return AYSTAR_FOUND_END_NODE;
|
return AYSTAR_FOUND_END_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the node to the ClosedList
|
// Add the node to the ClosedList
|
||||||
AyStarMain_ClosedList_Add(aystar, ¤t->path);
|
AyStarMain_ClosedList_Add(aystar, ¤t->path);
|
||||||
|
|
||||||
// Load the neighbours
|
// Load the neighbours
|
||||||
aystar->GetNeighbours(aystar, current);
|
aystar->GetNeighbours(aystar, current);
|
||||||
|
|
||||||
// Go through all neighbours
|
// Go through all neighbours
|
||||||
for (i=0;i<aystar->num_neighbours;i++) {
|
for (i=0;i<aystar->num_neighbours;i++) {
|
||||||
// Check and add them to the OpenList if needed
|
// Check and add them to the OpenList if needed
|
||||||
r = aystar->checktile(aystar, &aystar->neighbours[i], current);
|
r = aystar->checktile(aystar, &aystar->neighbours[i], current);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the node
|
// Free the node
|
||||||
free(current);
|
free(current);
|
||||||
|
|
||||||
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes)
|
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes)
|
||||||
/* We've expanded enough nodes */
|
/* We've expanded enough nodes */
|
||||||
return AYSTAR_LIMIT_REACHED;
|
return AYSTAR_LIMIT_REACHED;
|
||||||
else
|
else
|
||||||
// Return that we are still busy
|
// Return that we are still busy
|
||||||
return AYSTAR_STILL_BUSY;
|
return AYSTAR_STILL_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function frees the memory it allocated
|
* This function frees the memory it allocated
|
||||||
*/
|
*/
|
||||||
void AyStarMain_Free(AyStar *aystar) {
|
void AyStarMain_Free(AyStar *aystar) {
|
||||||
aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
|
aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
|
||||||
/* 2nd argument above is false, below is true, to free the values only
|
/* 2nd argument above is false, below is true, to free the values only
|
||||||
* once */
|
* once */
|
||||||
delete_Hash(&aystar->OpenListHash, true);
|
delete_Hash(&aystar->OpenListHash, true);
|
||||||
delete_Hash(&aystar->ClosedListHash, true);
|
delete_Hash(&aystar->ClosedListHash, true);
|
||||||
#ifdef AYSTAR_DEBUG
|
#ifdef AYSTAR_DEBUG
|
||||||
printf("[AyStar] Memory free'd\n");
|
printf("[AyStar] Memory free'd\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function make the memory go back to zero
|
* This function make the memory go back to zero
|
||||||
* This function should be called when you are using the same instance again.
|
* This function should be called when you are using the same instance again.
|
||||||
*/
|
*/
|
||||||
void AyStarMain_Clear(AyStar *aystar) {
|
void AyStarMain_Clear(AyStar *aystar) {
|
||||||
// Clean the Queue, but not the elements within. That will be done by
|
// Clean the Queue, but not the elements within. That will be done by
|
||||||
// the hash.
|
// the hash.
|
||||||
aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
|
aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
|
||||||
// Clean the hashes
|
// Clean the hashes
|
||||||
clear_Hash(&aystar->OpenListHash, true);
|
clear_Hash(&aystar->OpenListHash, true);
|
||||||
clear_Hash(&aystar->ClosedListHash, true);
|
clear_Hash(&aystar->ClosedListHash, true);
|
||||||
|
|
||||||
#ifdef AYSTAR_DEBUG
|
#ifdef AYSTAR_DEBUG
|
||||||
printf("[AyStar] Cleared AyStar\n");
|
printf("[AyStar] Cleared AyStar\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the function you call to run AyStar.
|
* This is the function you call to run AyStar.
|
||||||
* return values:
|
* return values:
|
||||||
* AYSTAR_FOUND_END_NODE : indicates we found an end node.
|
* AYSTAR_FOUND_END_NODE : indicates we found an end node.
|
||||||
* AYSTAR_NO_PATH : indicates that there was no path found.
|
* AYSTAR_NO_PATH : indicates that there was no path found.
|
||||||
* AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
|
* AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
|
||||||
* When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
|
* When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
|
||||||
* aystar->clear() is called. Note that when you stop the algorithm halfway,
|
* aystar->clear() is called. Note that when you stop the algorithm halfway,
|
||||||
* you should still call clear() yourself!
|
* you should still call clear() yourself!
|
||||||
*/
|
*/
|
||||||
int AyStarMain_Main(AyStar *aystar) {
|
int AyStarMain_Main(AyStar *aystar) {
|
||||||
int r, i = 0;
|
int r, i = 0;
|
||||||
// Loop through the OpenList
|
// Loop through the OpenList
|
||||||
// Quit if result is no AYSTAR_STILL_BUSY or is more then loops_per_tick
|
// Quit if result is no AYSTAR_STILL_BUSY or is more then loops_per_tick
|
||||||
while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
|
while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
|
||||||
#ifdef AYSTAR_DEBUG
|
#ifdef AYSTAR_DEBUG
|
||||||
if (r == AYSTAR_FOUND_END_NODE)
|
if (r == AYSTAR_FOUND_END_NODE)
|
||||||
printf("[AyStar] Found path!\n");
|
printf("[AyStar] Found path!\n");
|
||||||
else if (r == AYSTAR_EMPTY_OPENLIST)
|
else if (r == AYSTAR_EMPTY_OPENLIST)
|
||||||
printf("[AyStar] OpenList run dry, no path found\n");
|
printf("[AyStar] OpenList run dry, no path found\n");
|
||||||
else if (r == AYSTAR_LIMIT_REACHED)
|
else if (r == AYSTAR_LIMIT_REACHED)
|
||||||
printf("[AyStar] Exceeded search_nodes, no path found\n");
|
printf("[AyStar] Exceeded search_nodes, no path found\n");
|
||||||
#endif
|
#endif
|
||||||
if (r != AYSTAR_STILL_BUSY)
|
if (r != AYSTAR_STILL_BUSY)
|
||||||
/* We're done, clean up */
|
/* We're done, clean up */
|
||||||
aystar->clear(aystar);
|
aystar->clear(aystar);
|
||||||
|
|
||||||
// Check result-value
|
// Check result-value
|
||||||
if (r == AYSTAR_FOUND_END_NODE) return AYSTAR_FOUND_END_NODE;
|
if (r == AYSTAR_FOUND_END_NODE) return AYSTAR_FOUND_END_NODE;
|
||||||
// Check if we have some left in the OpenList
|
// Check if we have some left in the OpenList
|
||||||
if (r == AYSTAR_EMPTY_OPENLIST || r == AYSTAR_LIMIT_REACHED) return AYSTAR_NO_PATH;
|
if (r == AYSTAR_EMPTY_OPENLIST || r == AYSTAR_LIMIT_REACHED) return AYSTAR_NO_PATH;
|
||||||
|
|
||||||
// Return we are still busy
|
// Return we are still busy
|
||||||
return AYSTAR_STILL_BUSY;
|
return AYSTAR_STILL_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds a node from where to start an algorithm. Multiple nodes can be added
|
* Adds a node from where to start an algorithm. Multiple nodes can be added
|
||||||
* if wanted. You should make sure that clear() is called before adding nodes
|
* if wanted. You should make sure that clear() is called before adding nodes
|
||||||
* if the AyStar has been used before (though the normal main loop calls
|
* if the AyStar has been used before (though the normal main loop calls
|
||||||
* clear() automatically when the algorithm finishes
|
* clear() automatically when the algorithm finishes
|
||||||
*/
|
*/
|
||||||
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node) {
|
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node) {
|
||||||
#ifdef AYSTAR_DEBUG
|
#ifdef AYSTAR_DEBUG
|
||||||
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", GET_TILE_X(start_node->tile), GET_TILE_Y(start_node->tile), start_node->direction);
|
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", GET_TILE_X(start_node->tile), GET_TILE_Y(start_node->tile), start_node->direction);
|
||||||
#endif
|
#endif
|
||||||
AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, 0, 0);
|
AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) {
|
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) {
|
||||||
// Allocated the Hash for the OpenList and ClosedList
|
// Allocated the Hash for the OpenList and ClosedList
|
||||||
init_Hash(&aystar->OpenListHash, hash, num_buckets);
|
init_Hash(&aystar->OpenListHash, hash, num_buckets);
|
||||||
init_Hash(&aystar->ClosedListHash, hash, num_buckets);
|
init_Hash(&aystar->ClosedListHash, hash, num_buckets);
|
||||||
|
|
||||||
// Set up our sorting queue
|
// Set up our sorting queue
|
||||||
// BinaryHeap allocates a block of 1024 nodes
|
// BinaryHeap allocates a block of 1024 nodes
|
||||||
// When thatone gets full it reserves an otherone, till this number
|
// When thatone gets full it reserves an otherone, till this number
|
||||||
// That is why it can stay this high
|
// That is why it can stay this high
|
||||||
init_BinaryHeap(&aystar->OpenListQueue, 102400);
|
init_BinaryHeap(&aystar->OpenListQueue, 102400);
|
||||||
|
|
||||||
aystar->addstart = AyStarMain_AddStartNode;
|
aystar->addstart = AyStarMain_AddStartNode;
|
||||||
aystar->main = AyStarMain_Main;
|
aystar->main = AyStarMain_Main;
|
||||||
aystar->loop = AyStarMain_Loop;
|
aystar->loop = AyStarMain_Loop;
|
||||||
aystar->free = AyStarMain_Free;
|
aystar->free = AyStarMain_Free;
|
||||||
aystar->clear = AyStarMain_Clear;
|
aystar->clear = AyStarMain_Clear;
|
||||||
aystar->checktile = AyStarMain_CheckTile;
|
aystar->checktile = AyStarMain_CheckTile;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1564,7 +1564,7 @@ Industry *CreateNewIndustry(uint tile, int type)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const byte _numof_industry_table[4][12] = {
|
static const byte _numof_industry_table[4][12] = {
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
{0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5},
|
{0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5},
|
||||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||||
|
@ -1574,8 +1574,8 @@ static const byte _numof_industry_table[4][12] = {
|
||||||
static void PlaceInitialIndustry(byte type, int amount)
|
static void PlaceInitialIndustry(byte type, int amount)
|
||||||
{
|
{
|
||||||
int num = _numof_industry_table[_opt.diff.number_industries][amount];
|
int num = _numof_industry_table[_opt.diff.number_industries][amount];
|
||||||
|
|
||||||
if (_opt.diff.number_industries != 0)
|
if (_opt.diff.number_industries != 0)
|
||||||
{
|
{
|
||||||
assert(num > 0);
|
assert(num > 0);
|
||||||
|
|
||||||
|
@ -1585,7 +1585,7 @@ static void PlaceInitialIndustry(byte type, int amount)
|
||||||
if (CreateNewIndustry(TILE_MASK(Random()), type) != NULL)
|
if (CreateNewIndustry(TILE_MASK(Random()), type) != NULL)
|
||||||
break;
|
break;
|
||||||
} while (--i != 0);
|
} while (--i != 0);
|
||||||
} while (--num);
|
} while (--num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
network.c
16
network.c
|
@ -1252,14 +1252,14 @@ void NetworkIPListInit() {
|
||||||
gethostname(hostname,250);
|
gethostname(hostname,250);
|
||||||
DEBUG(misc,2) ("[NET][IP] init for host %s", hostname);
|
DEBUG(misc,2) ("[NET][IP] init for host %s", hostname);
|
||||||
he=gethostbyname((char *) hostname);
|
he=gethostbyname((char *) hostname);
|
||||||
|
|
||||||
if (he == NULL) {
|
if (he == NULL) {
|
||||||
he = gethostbyname("localhost");
|
he = gethostbyname("localhost");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (he == NULL) {
|
if (he == NULL) {
|
||||||
bcaddr = inet_addr("127.0.0.1");
|
bcaddr = inet_addr("127.0.0.1");
|
||||||
he = gethostbyaddr(inet_ntoa(*(struct in_addr *) &bcaddr), sizeof(bcaddr), AF_INET);
|
he = gethostbyaddr(inet_ntoa(*(struct in_addr *) &bcaddr), sizeof(bcaddr), AF_INET);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (he == NULL) {
|
if (he == NULL) {
|
||||||
|
|
406
queue.h
406
queue.h
|
@ -1,203 +1,203 @@
|
||||||
#ifndef QUEUE_H
|
#ifndef QUEUE_H
|
||||||
#define QUEUE_H
|
#define QUEUE_H
|
||||||
|
|
||||||
//#define NOFREE
|
//#define NOFREE
|
||||||
//#define QUEUE_DEBUG
|
//#define QUEUE_DEBUG
|
||||||
//#define HASH_DEBUG
|
//#define HASH_DEBUG
|
||||||
|
|
||||||
|
|
||||||
typedef struct Queue Queue;
|
typedef struct Queue Queue;
|
||||||
typedef bool Queue_PushProc(Queue* q, void* item, int priority);
|
typedef bool Queue_PushProc(Queue* q, void* item, int priority);
|
||||||
typedef void* Queue_PopProc(Queue* q);
|
typedef void* Queue_PopProc(Queue* q);
|
||||||
typedef bool Queue_DeleteProc(Queue* q, void* item, int priority);
|
typedef bool Queue_DeleteProc(Queue* q, void* item, int priority);
|
||||||
typedef void Queue_ClearProc(Queue* q, bool free_values);
|
typedef void Queue_ClearProc(Queue* q, bool free_values);
|
||||||
typedef void Queue_FreeProc(Queue* q, bool free_values);
|
typedef void Queue_FreeProc(Queue* q, bool free_values);
|
||||||
|
|
||||||
typedef struct InsSortNode InsSortNode;
|
typedef struct InsSortNode InsSortNode;
|
||||||
struct InsSortNode {
|
struct InsSortNode {
|
||||||
void* item;
|
void* item;
|
||||||
int priority;
|
int priority;
|
||||||
InsSortNode* next;
|
InsSortNode* next;
|
||||||
};
|
};
|
||||||
typedef struct BinaryHeapNode BinaryHeapNode;
|
typedef struct BinaryHeapNode BinaryHeapNode;
|
||||||
struct BinaryHeapNode {
|
struct BinaryHeapNode {
|
||||||
void* item;
|
void* item;
|
||||||
int priority;
|
int priority;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Queue{
|
struct Queue{
|
||||||
/*
|
/*
|
||||||
* Pushes an element into the queue, at the appropriate place for the queue.
|
* Pushes an element into the queue, at the appropriate place for the queue.
|
||||||
* Requires the queue pointer to be of an appropriate type, of course.
|
* Requires the queue pointer to be of an appropriate type, of course.
|
||||||
*/
|
*/
|
||||||
Queue_PushProc* push;
|
Queue_PushProc* push;
|
||||||
/*
|
/*
|
||||||
* Pops the first element from the queue. What exactly is the first element,
|
* Pops the first element from the queue. What exactly is the first element,
|
||||||
* is defined by the exact type of queue.
|
* is defined by the exact type of queue.
|
||||||
*/
|
*/
|
||||||
Queue_PopProc* pop;
|
Queue_PopProc* pop;
|
||||||
/*
|
/*
|
||||||
* Deletes the item from the queue. priority should be specified if
|
* Deletes the item from the queue. priority should be specified if
|
||||||
* known, which speeds up the deleting for some queue's. Should be -1
|
* known, which speeds up the deleting for some queue's. Should be -1
|
||||||
* if not known.
|
* if not known.
|
||||||
*/
|
*/
|
||||||
Queue_DeleteProc* del;
|
Queue_DeleteProc* del;
|
||||||
|
|
||||||
/* Clears the queue, by removing all values from it. It's state is
|
/* Clears the queue, by removing all values from it. It's state is
|
||||||
* effectively reset. If free_items is true, each of the items cleared
|
* effectively reset. If free_items is true, each of the items cleared
|
||||||
* in this way are free()'d.
|
* in this way are free()'d.
|
||||||
*/
|
*/
|
||||||
Queue_ClearProc* clear;
|
Queue_ClearProc* clear;
|
||||||
/* Frees the queue, by reclaiming all memory allocated by it. After
|
/* Frees the queue, by reclaiming all memory allocated by it. After
|
||||||
* this it is no longer usable. If free_items is true, any remaining
|
* this it is no longer usable. If free_items is true, any remaining
|
||||||
* items are free()'d too.
|
* items are free()'d too.
|
||||||
*/
|
*/
|
||||||
Queue_FreeProc* free;
|
Queue_FreeProc* free;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint max_size;
|
uint max_size;
|
||||||
uint size;
|
uint size;
|
||||||
void** elements;
|
void** elements;
|
||||||
} stack;
|
} stack;
|
||||||
struct {
|
struct {
|
||||||
uint max_size;
|
uint max_size;
|
||||||
uint head; /* The index where the last element should be inserted */
|
uint head; /* The index where the last element should be inserted */
|
||||||
uint tail; /* The index where the next element should be read */
|
uint tail; /* The index where the next element should be read */
|
||||||
void** elements;
|
void** elements;
|
||||||
} fifo;
|
} fifo;
|
||||||
struct {
|
struct {
|
||||||
InsSortNode* first;
|
InsSortNode* first;
|
||||||
} inssort;
|
} inssort;
|
||||||
struct {
|
struct {
|
||||||
uint max_size;
|
uint max_size;
|
||||||
uint size;
|
uint size;
|
||||||
uint blocks; /* The amount of blocks for which space is reserved in elements */
|
uint blocks; /* The amount of blocks for which space is reserved in elements */
|
||||||
BinaryHeapNode** elements;
|
BinaryHeapNode** elements;
|
||||||
} binaryheap;
|
} binaryheap;
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
/* If true, this struct will be free'd when the
|
/* If true, this struct will be free'd when the
|
||||||
* Queue is deleted. */
|
* Queue is deleted. */
|
||||||
bool freeq;
|
bool freeq;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initializes a stack and allocates internal memory. */
|
/* Initializes a stack and allocates internal memory. */
|
||||||
void init_Stack(Queue* q, uint max_size);
|
void init_Stack(Queue* q, uint max_size);
|
||||||
|
|
||||||
/* Allocate a new stack with a maximum of max_size elements. */
|
/* Allocate a new stack with a maximum of max_size elements. */
|
||||||
Queue* new_Stack(uint max_size);
|
Queue* new_Stack(uint max_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fifo
|
* Fifo
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Initializes a fifo and allocates internal memory for maximum of max_size
|
/* Initializes a fifo and allocates internal memory for maximum of max_size
|
||||||
* elements */
|
* elements */
|
||||||
void init_Fifo(Queue* q, uint max_size);
|
void init_Fifo(Queue* q, uint max_size);
|
||||||
|
|
||||||
/* Allocate a new fifo and initializes it with a maximum of max_size elements. */
|
/* Allocate a new fifo and initializes it with a maximum of max_size elements. */
|
||||||
Queue* new_Fifo(uint max_size);
|
Queue* new_Fifo(uint max_size);
|
||||||
|
|
||||||
Queue* new_Fifo_in_buffer(uint max_size, void* buffer);
|
Queue* new_Fifo_in_buffer(uint max_size, void* buffer);
|
||||||
|
|
||||||
int build_Fifo(void* buffer, uint size);
|
int build_Fifo(void* buffer, uint size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insertion Sorter
|
* Insertion Sorter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Initializes a inssort and allocates internal memory. There is no maximum
|
/* Initializes a inssort and allocates internal memory. There is no maximum
|
||||||
* size */
|
* size */
|
||||||
void init_InsSort(Queue* q);
|
void init_InsSort(Queue* q);
|
||||||
|
|
||||||
/* Allocate a new fifo and initializes it. There is no maximum size */
|
/* Allocate a new fifo and initializes it. There is no maximum size */
|
||||||
Queue* new_InsSort();
|
Queue* new_InsSort();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Binary Heap
|
* Binary Heap
|
||||||
* For information, see:
|
* For information, see:
|
||||||
* http://www.policyalmanac.org/games/binaryHeaps.htm
|
* http://www.policyalmanac.org/games/binaryHeaps.htm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The amount of elements that will be malloc'd at a time */
|
/* The amount of elements that will be malloc'd at a time */
|
||||||
#define BINARY_HEAP_BLOCKSIZE_BITS 10
|
#define BINARY_HEAP_BLOCKSIZE_BITS 10
|
||||||
|
|
||||||
/* Initializes a binary heap and allocates internal memory for maximum of
|
/* Initializes a binary heap and allocates internal memory for maximum of
|
||||||
* max_size elements */
|
* max_size elements */
|
||||||
void init_BinaryHeap(Queue* q, uint max_size);
|
void init_BinaryHeap(Queue* q, uint max_size);
|
||||||
|
|
||||||
/* Allocate a new binary heap and initializes it with a maximum of max_size
|
/* Allocate a new binary heap and initializes it with a maximum of max_size
|
||||||
* elements. */
|
* elements. */
|
||||||
Queue* new_BinaryHeap(uint max_size);
|
Queue* new_BinaryHeap(uint max_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hash
|
* Hash
|
||||||
*/
|
*/
|
||||||
typedef struct HashNode HashNode;
|
typedef struct HashNode HashNode;
|
||||||
struct HashNode {
|
struct HashNode {
|
||||||
uint key1;
|
uint key1;
|
||||||
uint key2;
|
uint key2;
|
||||||
void* value;
|
void* value;
|
||||||
HashNode* next;
|
HashNode* next;
|
||||||
};
|
};
|
||||||
/* Generates a hash code from the given key pair. You should make sure that
|
/* Generates a hash code from the given key pair. You should make sure that
|
||||||
* the resulting range is clearly defined.
|
* the resulting range is clearly defined.
|
||||||
*/
|
*/
|
||||||
typedef uint Hash_HashProc(uint key1, uint key2);
|
typedef uint Hash_HashProc(uint key1, uint key2);
|
||||||
typedef struct Hash {
|
typedef struct Hash {
|
||||||
/* The hash function used */
|
/* The hash function used */
|
||||||
Hash_HashProc* hash;
|
Hash_HashProc* hash;
|
||||||
/* The amount of items in the hash */
|
/* The amount of items in the hash */
|
||||||
uint size;
|
uint size;
|
||||||
/* The number of buckets allocated */
|
/* The number of buckets allocated */
|
||||||
uint num_buckets;
|
uint num_buckets;
|
||||||
/* A pointer to an array of num_buckets buckets. */
|
/* A pointer to an array of num_buckets buckets. */
|
||||||
HashNode* buckets;
|
HashNode* buckets;
|
||||||
/* A pointer to an array of numbuckets booleans, which will be true if
|
/* A pointer to an array of numbuckets booleans, which will be true if
|
||||||
* there are any Nodes in the bucket */
|
* there are any Nodes in the bucket */
|
||||||
bool* buckets_in_use;
|
bool* buckets_in_use;
|
||||||
/* If true, buckets will be freed in delete_hash */
|
/* If true, buckets will be freed in delete_hash */
|
||||||
bool freeb;
|
bool freeb;
|
||||||
/* If true, the pointer to this struct will be freed in delete_hash */
|
/* If true, the pointer to this struct will be freed in delete_hash */
|
||||||
bool freeh;
|
bool freeh;
|
||||||
} Hash;
|
} Hash;
|
||||||
|
|
||||||
/* Call these function to manipulate a hash */
|
/* Call these function to manipulate a hash */
|
||||||
|
|
||||||
/* Deletes the value with the specified key pair from the hash and returns
|
/* Deletes the value with the specified key pair from the hash and returns
|
||||||
* that value. Returns NULL when the value was not present. The value returned
|
* that value. Returns NULL when the value was not present. The value returned
|
||||||
* is _not_ free()'d! */
|
* is _not_ free()'d! */
|
||||||
void* Hash_Delete(Hash* h, uint key1, uint key2);
|
void* Hash_Delete(Hash* h, uint key1, uint key2);
|
||||||
/* Sets the value associated with the given key pair to the given value.
|
/* Sets the value associated with the given key pair to the given value.
|
||||||
* Returns the old value if the value was replaced, NULL when it was not yet present. */
|
* Returns the old value if the value was replaced, NULL when it was not yet present. */
|
||||||
void* Hash_Set(Hash* h, uint key1, uint key2, void* value);
|
void* Hash_Set(Hash* h, uint key1, uint key2, void* value);
|
||||||
/* Gets the value associated with the given key pair, or NULL when it is not
|
/* Gets the value associated with the given key pair, or NULL when it is not
|
||||||
* present. */
|
* present. */
|
||||||
void* Hash_Get(Hash* h, uint key1, uint key2);
|
void* Hash_Get(Hash* h, uint key1, uint key2);
|
||||||
|
|
||||||
/* Call these function to create/destroy a hash */
|
/* Call these function to create/destroy a hash */
|
||||||
|
|
||||||
/* Builds a new hash, with num_buckets buckets. Make sure that hash() always
|
/* Builds a new hash, with num_buckets buckets. Make sure that hash() always
|
||||||
* returns a hash less than num_buckets! Call delete_hash after use */
|
* returns a hash less than num_buckets! Call delete_hash after use */
|
||||||
Hash* new_Hash(Hash_HashProc* hash, int num_buckets);
|
Hash* new_Hash(Hash_HashProc* hash, int num_buckets);
|
||||||
/* Builds a new hash in an existing struct. Make sure that hash() always
|
/* Builds a new hash in an existing struct. Make sure that hash() always
|
||||||
* returns a hash less than num_buckets! Call delete_hash after use */
|
* returns a hash less than num_buckets! Call delete_hash after use */
|
||||||
void init_Hash(Hash* h, Hash_HashProc* hash, int num_buckets);
|
void init_Hash(Hash* h, Hash_HashProc* hash, int num_buckets);
|
||||||
/*
|
/*
|
||||||
* Deletes the hash and cleans up. Only cleans up memory allocated by new_Hash
|
* Deletes the hash and cleans up. Only cleans up memory allocated by new_Hash
|
||||||
* & friends. If free is true, it will call free() on all the values that
|
* & friends. If free is true, it will call free() on all the values that
|
||||||
* are left in the hash.
|
* are left in the hash.
|
||||||
*/
|
*/
|
||||||
void delete_Hash(Hash* h, bool free_values);
|
void delete_Hash(Hash* h, bool free_values);
|
||||||
/*
|
/*
|
||||||
* Cleans the hash, but keeps the memory allocated
|
* Cleans the hash, but keeps the memory allocated
|
||||||
*/
|
*/
|
||||||
void clear_Hash(Hash* h, bool free_values);
|
void clear_Hash(Hash* h, bool free_values);
|
||||||
/*
|
/*
|
||||||
* Gets the current size of the Hash
|
* Gets the current size of the Hash
|
||||||
*/
|
*/
|
||||||
uint Hash_Size(Hash* h);
|
uint Hash_Size(Hash* h);
|
||||||
|
|
||||||
#endif /* QUEUE_H */
|
#endif /* QUEUE_H */
|
||||||
|
|
Loading…
Reference in New Issue