(svn r15027) -Merge: tomatos and bananas left to be, here is NoAI for all to see.

NoAI is an API (a framework) to build your own AIs in. See:
   http://wiki.openttd.org/wiki/index.php/AI:Main_Page
 With many thanks to:
  - glx and Rubidium for their syncing, feedback and hard work
  - Yexo for his feedback, patches, and AIs which tested the system very deep
  - Morloth for his feedback and patches
  - TJIP for hosting a challenge which kept NoAI on track
  - All AI authors for testing our AI API, and all other people who helped in one way or another
-Remove: all old AIs and their cheats/hacks
pull/155/head
truebrain 16 years ago
parent ec97e1fd0d
commit c2406cd42d

@ -39,6 +39,7 @@ bundle: all
$(Q)mkdir -p "$(BUNDLE_DIR)/scenario"
$(Q)mkdir -p "$(BUNDLE_DIR)/scenario/heightmap"
$(Q)mkdir -p "$(BUNDLE_DIR)/media"
$(Q)mkdir -p "$(BUNDLE_DIR)/ai"
$(Q)mkdir -p "$(BUNDLE_DIR)/scripts"
$(Q)mkdir -p "$(TTD_DIR)"
$(Q)mkdir -p "$(DATA_DIR)"
@ -75,6 +76,10 @@ ifdef MENU_DIR
$(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/"
$(Q)cat "$(ROOT_DIR)/media/openttd.desktop" | sed s/=openttd/=$(BINARY_NAME)/g > "$(ROOT_DIR)/media/openttd.desktop.install"
endif
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/ai/\"* 2>/dev/null`"; then echo 1; fi), 1)
$(Q)cp -R "$(BIN_DIR)/ai/"* "$(BUNDLE_DIR)/ai/"
$(Q)find $(BUNDLE_DIR)/ai/ -depth -iname '*.svn' -exec rm -Rf {} \; || find $(BUNDLE_DIR)/ai/ -d -iname '*.svn' -exec rm -Rf {} \;
endif
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/scenario/\"*.scn 2> /dev/null`"; then echo 1; fi), 1)
$(Q)cp "$(BIN_DIR)/scenario/"*.scn "$(BUNDLE_DIR)/scenario/"
endif

@ -141,6 +141,9 @@ run-gdb: all
run-prof: all
$(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS) && gprof !!TTD!! | less
regression: all
$(Q)cd !!BIN_DIR!! && sh ai/regression/run.sh
%.o:
@for dir in $(SRC_DIRS); do \
$(MAKE) -C $$dir $(@:src/%=%); \

@ -15,6 +15,7 @@ LANG_DIR = !!LANG_DIR!!
SRC_OBJS_DIR = !!SRC_OBJS_DIR!!
LANG_OBJS_DIR= !!LANG_OBJS_DIR!!
SRC_DIR = !!SRC_DIR!!
SCRIPT_SRC_DIR=!!SCRIPT_SRC_DIR!!
MEDIA_DIR = !!MEDIA_DIR!!
TTD = !!TTD!!
STRGEN = !!STRGEN!!
@ -48,7 +49,7 @@ RES := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS))))
# Make sure endian_target.h is reasable as if it was in the src/ dir
CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR)
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR)
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SCRIPT_SRC_DIR)
ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK)
@ -216,10 +217,10 @@ endif
endif
# Avoid problems with deps if a .h/.hpp file is deleted without the deps
# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps
# being updated. Now the Makefile continues, the deps are recreated
# and all will be fine.
%.h %.hpp:
%.h %.hpp %.hpp.sq:
@true

@ -0,0 +1,12 @@
/* $Id$ */
class AyStar extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "AyStar"; }
function GetDescription() { return "An implementation of AyStar"; }
function GetVersion() { return 4; }
function GetDate() { return "2008-06-11"; }
function CreateInstance() { return "AyStar"; }
}
RegisterLibrary(AyStar());

@ -0,0 +1,238 @@
/* $Id$ */
/**
* An AyStar implementation.
* It solves graphs by finding the fastest route from one point to the other.
*/
class AyStar
{
_queue_class = import("queue.binary_heap", "", 1);
_cost_callback = null;
_estimate_callback = null;
_neighbours_callback = null;
_check_direction_callback = null;
_cost_callback_param = null;
_estimate_callback_param = null;
_neighbours_callback_param = null;
_check_direction_callback_param = null;
_open = null;
_closed = null;
_goals = null;
/**
* @param cost_callback A function that returns the cost of a path. It
* should accept four parameters, old_path, new_tile, new_direction and
* cost_callback_param. old_path is an instance of AyStar.Path, and
* new_node is the new node that is added to that path. It should return
* the cost of the path including new_node.
* @param estimate_callback A function that returns an estimate from a node
* to the goal node. It should accept four parameters, tile, direction,
* goal_nodes and estimate_callback_param. It should return an estimate to
* the cost from the lowest cost between node and any node out of goal_nodes.
* Note that this estimate is not allowed to be higher than the real cost
* between node and any of goal_nodes. A lower value is fine, however the
* closer it is to the real value, the better the performance.
* @param neighbours_callback A function that returns all neighbouring nodes
* from a given node. It should accept three parameters, current_path, node
* and neighbours_callback_param. It should return an array containing all
* neighbouring nodes, which are an array in the form [tile, direction].
* @param check_direction_callback A function that returns either false or
* true. It should accept four parameters, tile, existing_direction,
* new_direction and check_direction_callback_param. It should check
* if both directions can go together on a single tile.
* @param cost_callback_param This parameters will be passed to cost_callback
* as fourth parameter. Useful to send is an instance of an object.
* @param estimate_callback_param This parameters will be passed to
* estimate_callback as fourth parameter. Useful to send is an instance of an
* object.
* @param neighbours_callback_param This parameters will be passed to
* neighbours_callback as third parameter. Useful to send is an instance of
* an object.
* @param check_direction_callback_param This parameters will be passed to
* check_direction_callback as fourth parameter. Useful to send is an
* instance of an object.
*/
constructor(cost_callback, estimate_callback, neighbours_callback, check_direction_callback, cost_callback_param = null,
estimate_callback_param = null, neighbours_callback_param = null, check_direction_callback_param = null)
{
if (typeof(cost_callback) != "function") throw("'cost_callback' has to be a function-pointer.");
if (typeof(estimate_callback) != "function") throw("'estimate_callback' has to be a function-pointer.");
if (typeof(neighbours_callback) != "function") throw("'neighbours_callback' has to be a function-pointer.");
if (typeof(check_direction_callback) != "function") throw("'check_direction_callback' has to be a function-pointer.");
this._cost_callback = cost_callback;
this._estimate_callback = estimate_callback;
this._neighbours_callback = neighbours_callback;
this._check_direction_callback = check_direction_callback;
this._cost_callback_param = cost_callback_param;
this._estimate_callback_param = estimate_callback_param;
this._neighbours_callback_param = neighbours_callback_param;
this._check_direction_callback_param = check_direction_callback_param;
}
/**
* Initialize a path search between sources and goals.
* @param sources The source nodes. This can an array of either [tile, direction]-pairs or AyStar.Path-instances.
* @param goals The target tiles. This can be an array of either tiles or [tile, next_tile]-pairs.
* @param ignored_tiles An array of tiles that cannot occur in the final path.
*/
function InitializePath(sources, goals, ignored_tiles = []);
/**
* Try to find the path as indicated with InitializePath with the lowest cost.
* @param iterations After how many iterations it should abort for a moment.
* This value should either be -1 for infinite, or > 0. Any other value
* aborts immediatly and will never find a path.
* @return A route if one was found, or false if the amount of iterations was
* reached, or null if no path was found.
* You can call this function over and over as long as it returns false,
* which is an indication it is not yet done looking for a route.
*/
function FindPath(iterations);
};
function AyStar::InitializePath(sources, goals, ignored_tiles = [])
{
if (typeof(sources) != "array" || sources.len() == 0) throw("sources has be a non-empty array.");
if (typeof(goals) != "array" || goals.len() == 0) throw("goals has be a non-empty array.");
this._open = this._queue_class();
this._closed = AIList();
foreach (node in sources) {
if (typeof(node) == "array") {
if (node[1] <= 0) throw("directional value should never be zero or negative.");
local new_path = this.Path(null, node[0], node[1], this._cost_callback, this._cost_callback_param);
this._open.Insert(new_path, new_path.GetCost() + this._estimate_callback(node[0], node[1], goals, this._estimate_callback_param));
} else {
this._open.Insert(node, node.GetCost());
}
}
this._goals = goals;
foreach (tile in ignored_tiles) {
this._closed.AddItem(tile, ~0);
}
}
function AyStar::FindPath(iterations)
{
if (this._open == null) throw("can't execute over an uninitialized path");
while (this._open.Count() > 0 && (iterations == -1 || iterations-- > 0)) {
/* Get the path with the best score so far */
local path = this._open.Pop();
local cur_tile = path.GetTile();
/* Make sure we didn't already passed it */
if (this._closed.HasItem(cur_tile)) {
/* If the direction is already on the list, skip this entry */
if ((this._closed.GetValue(cur_tile) & path.GetDirection()) != 0) continue;
/* Scan the path for a possible collision */
local scan_path = path.GetParent();
local mismatch = false;
while (scan_path != null) {
if (scan_path.GetTile() == cur_tile) {
if (!this._check_direction_callback(cur_tile, scan_path.GetDirection(), path.GetDirection(), this._check_direction_callback_param)) {
mismatch = true;
break;
}
}
scan_path = scan_path.GetParent();
}
if (mismatch) continue;
/* Add the new direction */
this._closed.SetValue(cur_tile, this._closed.GetValue(cur_tile) | path.GetDirection());
} else {
/* New entry, make sure we don't check it again */
this._closed.AddItem(cur_tile, path.GetDirection());
}
/* Check if we found the end */
foreach (goal in this._goals) {
if (typeof(goal) == "array") {
if (cur_tile == goal[0]) {
local neighbours = this._neighbours_callback(path, cur_tile, this._neighbours_callback_param);
foreach (node in neighbours) {
if (node[0] == goal[1]) {
this._CleanPath();
return path;
}
}
continue;
}
} else {
if (cur_tile == goal) {
this._CleanPath();
return path;
}
}
}
/* Scan all neighbours */
local neighbours = this._neighbours_callback(path, cur_tile, this._neighbours_callback_param);
foreach (node in neighbours) {
if (node[1] <= 0) throw("directional value should never be zero or negative.");
if ((this._closed.GetValue(node[0]) & node[1]) != 0) continue;
/* Calculate the new paths and add them to the open list */
local new_path = this.Path(path, node[0], node[1], this._cost_callback, this._cost_callback_param);
this._open.Insert(new_path, new_path.GetCost() + this._estimate_callback(node[0], node[1], this._goals, this._estimate_callback_param));
}
}
if (this._open.Count() > 0) return false;
this._CleanPath();
return null;
}
function AyStar::_CleanPath()
{
this._closed = null;
this._open = null;
this._goals = null;
}
/**
* The path of the AyStar algorithm.
* It is reversed, that is, the first entry is more close to the goal-nodes
* than his GetParent(). You can walk this list to find the whole path.
* The last entry has a GetParent() of null.
*/
class AyStar.Path
{
_prev = null;
_tile = null;
_direction = null;
_cost = null;
constructor(old_path, new_tile, new_direction, cost_callback, cost_callback_param)
{
this._prev = old_path;
this._tile = new_tile;
this._direction = new_direction;
this._cost = cost_callback(old_path, new_tile, new_direction, cost_callback_param);
};
/**
* Return the tile where this (partial-)path ends.
*/
function GetTile() { return this._tile; }
/**
* Return the direction from which we entered the tile in this (partial-)path.
*/
function GetDirection() { return this._direction; }
/**
* Return an instance of this class leading to the previous node.
*/
function GetParent() { return this._prev; }
/**
* Return the cost of this (partial-)path from the beginning up to this node.
*/
function GetCost() { return this._cost; }
};

@ -0,0 +1,12 @@
/* $Id$ */
class Rail extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Rail"; }
function GetDescription() { return "An implementation of a rail pathfinder"; }
function GetVersion() { return 1; }
function GetDate() { return "2008-09-22"; }
function CreateInstance() { return "Rail"; }
}
RegisterLibrary(Rail());

@ -0,0 +1,389 @@
/* $Id$ */
/**
* A Rail Pathfinder.
*/
class Rail
{
_aystar_class = import("graph.aystar", "", 4);
_max_cost = null; ///< The maximum cost for a route.
_cost_tile = null; ///< The cost for a single tile.
_cost_diagonal_tile = null; ///< The cost for a diagonal tile.
_cost_turn = null; ///< The cost that is added to _cost_tile if the direction changes.
_cost_slope = null; ///< The extra cost if a rail tile is sloped.
_cost_bridge_per_tile = null; ///< The cost per tile of a new bridge, this is added to _cost_tile.
_cost_tunnel_per_tile = null; ///< The cost per tile of a new tunnel, this is added to _cost_tile.
_cost_coast = null; ///< The extra cost for a coast tile.
_pathfinder = null; ///< A reference to the used AyStar object.
_max_bridge_length = null; ///< The maximum length of a bridge that will be build.
_max_tunnel_length = null; ///< The maximum length of a tunnel that will be build.
cost = null; ///< Used to change the costs.
_running = null;
_goals = null;
constructor()
{
this._max_cost = 10000000;
this._cost_tile = 100;
this._cost_diagonal_tile = 70;
this._cost_turn = 50;
this._cost_slope = 100;
this._cost_bridge_per_tile = 150;
this._cost_tunnel_per_tile = 120;
this._cost_coast = 20;
this._max_bridge_length = 6;
this._max_tunnel_length = 6;
this._pathfinder = this._aystar_class(this._Cost, this._Estimate, this._Neighbours, this._CheckDirection, this, this, this, this);
this.cost = this.Cost(this);
this._running = false;
}
/**
* Initialize a path search between sources and goals.
* @param sources The source tiles.
* @param goals The target tiles.
* @param ignored_tiles An array of tiles that cannot occur in the final path.
* @see AyStar::InitializePath()
*/
function InitializePath(sources, goals, ignored_tiles = []) {
local nsources = [];
foreach (node in sources) {
local path = this._pathfinder.Path(null, node[1], 0xFF, this._Cost, this);
path = this._pathfinder.Path(path, node[0], 0xFF, this._Cost, this);
nsources.push(path);
}
this._goals = goals;
this._pathfinder.InitializePath(nsources, goals, ignored_tiles);
}
/**
* Try to find the path as indicated with InitializePath with the lowest cost.
* @param iterations After how many iterations it should abort for a moment.
* This value should either be -1 for infinite, or > 0. Any other value
* aborts immediatly and will never find a path.
* @return A route if one was found, or false if the amount of iterations was
* reached, or null if no path was found.
* You can call this function over and over as long as it returns false,
* which is an indication it is not yet done looking for a route.
* @see AyStar::FindPath()
*/
function FindPath(iterations);
};
class Rail.Cost
{
_main = null;
function _set(idx, val)
{
if (this._main._running) throw("You are not allowed to change parameters of a running pathfinder.");
switch (idx) {
case "max_cost": this._main._max_cost = val; break;
case "tile": this._main._cost_tile = val; break;
case "diagonal_tile": this._cost_diagonal_tile = val; break;
case "turn": this._main._cost_turn = val; break;
case "slope": this._main._cost_slope = val; break;
case "bridge_per_tile": this._main._cost_bridge_per_tile = val; break;
case "tunnel_per_tile": this._main._cost_tunnel_per_tile = val; break;
case "coast": this._main._cost_coast = val; break;
case "max_bridge_length": this._main._max_bridge_length = val; break;
case "max_tunnel_length": this._main._max_tunnel_length = val; break;
default: throw("the index '" + idx + "' does not exist");
}
return val;
}
function _get(idx)
{
switch (idx) {
case "max_cost": return this._main._max_cost;
case "tile": return this._main._cost_tile;
case "diagonal_tile": return this._cost_diagonal_tile;
case "turn": return this._main._cost_turn;
case "slope": return this._main._cost_slope;
case "bridge_per_tile": return this._main._cost_bridge_per_tile;
case "tunnel_per_tile": return this._main._cost_tunnel_per_tile;
case "coast": return this._main._cost_coast;
case "max_bridge_length": return this._main._max_bridge_length;
case "max_tunnel_length": return this._main._max_tunnel_length;
default: throw("the index '" + idx + "' does not exist");
}
}
constructor(main)
{
this._main = main;
}
};
function Rail::FindPath(iterations)
{
local test_mode = AITestMode();
local ret = this._pathfinder.FindPath(iterations);
this._running = (ret == false) ? true : false;
if (!this._running && ret != null) {
foreach (goal in this._goals) {
if (goal[0] == ret.GetTile()) {
return this._pathfinder.Path(ret, goal[1], 0, this._Cost, this);
}
}
}
return ret;
}
function Rail::_GetBridgeNumSlopes(end_a, end_b)
{
local slopes = 0;
local direction = (end_b - end_a) / AIMap.DistanceManhattan(end_a, end_b);
local slope = AITile.GetSlope(end_a);
if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
slopes++;
}
local slope = AITile.GetSlope(end_b);
direction = -direction;
if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
slopes++;
}
return slopes;
}
function Rail::_nonzero(a, b)
{
return a != 0 ? a : b;
}
function Rail::_Cost(path, new_tile, new_direction, self)
{
/* path == null means this is the first node of a path, so the cost is 0. */
if (path == null) return 0;
local prev_tile = path.GetTile();
/* If the new tile is a bridge / tunnel tile, check whether we came from the other
* end of the bridge / tunnel or if we just entered the bridge / tunnel. */
if (AIBridge.IsBridgeTile(new_tile)) {
if (AIBridge.GetOtherBridgeEnd(new_tile) != prev_tile) {
local cost = path.GetCost() + self._cost_tile;
if (path.GetParent() != null && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost += self._cost_turn;
return cost;
}
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
}
if (AITunnel.IsTunnelTile(new_tile)) {
if (AITunnel.GetOtherTunnelEnd(new_tile) != prev_tile) {
local cost = path.GetCost() + self._cost_tile;
if (path.GetParent() != null && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost += self._cost_turn;
return cost;
}
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile;
}
/* If the two tiles are more then 1 tile apart, the pathfinder wants a bridge or tunnel
* to be build. It isn't an existing bridge / tunnel, as that case is already handled. */
if (AIMap.DistanceManhattan(new_tile, prev_tile) > 1) {
/* Check if we should build a bridge or a tunnel. */
local cost = path.GetCost();
if (AITunnel.GetOtherTunnelEnd(new_tile) == prev_tile) {
cost += AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_tunnel_per_tile);
} else {
cost += AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_bridge_per_tile) + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
}
if (path.GetParent() != null && path.GetParent().GetParent() != null &&
path.GetParent().GetParent().GetTile() - path.GetParent().GetTile() != max(AIMap.GetTileX(prev_tile) - AIMap.GetTileX(new_tile), AIMap.GetTileY(prev_tile) - AIMap.GetTileY(new_tile)) / AIMap.DistanceManhattan(new_tile, prev_tile)) {
cost += self._cost_turn;
}
return cost;
}
/* Check for a turn. We do this by substracting the TileID of the current
* node from the TileID of the previous node and comparing that to the
* difference between the tile before the previous node and the node before
* that. */
local cost = self._cost_tile;
if (path.GetParent() != null && AIMap.DistanceManhattan(path.GetParent().GetTile(), prev_tile) == 1 && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost = self._cost_diagonal_tile;
if (path.GetParent() != null && path.GetParent().GetParent() != null &&
AIMap.DistanceManhattan(new_tile, path.GetParent().GetParent().GetTile()) == 3 &&
path.GetParent().GetParent().GetTile() - path.GetParent().GetTile() != prev_tile - new_tile) {
cost += self._cost_turn;
}
/* Check if the new tile is a coast tile. */
if (AITile.IsCoastTile(new_tile)) {
cost += self._cost_coast;
}
/* Check if the last tile was sloped. */
if (path.GetParent() != null && !AIBridge.IsBridgeTile(prev_tile) && !AITunnel.IsTunnelTile(prev_tile) &&
self._IsSlopedRail(path.GetParent().GetTile(), prev_tile, new_tile)) {
cost += self._cost_slope;
}
/* We don't use already existing rail, so the following code is unused. It
* assigns if no rail exists along the route. */
/*
if (path.GetParent() != null && !AIRail.AreTilesConnected(path.GetParent().GetTile(), prev_tile, new_tile)) {
cost += self._cost_no_existing_rail;
}
*/
return path.GetCost() + cost;
}
function Rail::_Estimate(cur_tile, cur_direction, goal_tiles, self)
{
local min_cost = self._max_cost;
/* As estimate we multiply the lowest possible cost for a single tile with
* with the minimum number of tiles we need to traverse. */
foreach (tile in goal_tiles) {
local dx = abs(AIMap.GetTileX(cur_tile) - AIMap.GetTileX(tile[0]));
local dy = abs(AIMap.GetTileY(cur_tile) - AIMap.GetTileY(tile[0]));
min_cost = min(min_cost, min(dx, dy) * self._cost_diagonal_tile * 2 + (max(dx, dy) - min(dx, dy)) * self._cost_tile);
}
return min_cost;
}
function Rail::_Neighbours(path, cur_node, self)
{
if (AITile.HasTransportType(cur_node, AITile.TRANSPORT_RAIL)) return [];
/* self._max_cost is the maximum path cost, if we go over it, the path isn't valid. */
if (path.GetCost() >= self._max_cost) return [];
local tiles = [];
local offsets = [AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1),
AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0)];
/* Check if the current tile is part of a bridge or tunnel. */
if (AIBridge.IsBridgeTile(cur_node) || AITunnel.IsTunnelTile(cur_node)) {
/* We don't use existing rails, so neither existing bridges / tunnels. */
} else if (path.GetParent() != null && AIMap.DistanceManhattan(cur_node, path.GetParent().GetTile()) > 1) {
local other_end = path.GetParent().GetTile();
local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
foreach (offset in offsets) {
if (AIRail.BuildRail(cur_node, next_tile, next_tile + offset)) {
tiles.push([next_tile, self._GetDirection(other_end, cur_node, next_tile, true)]);
}
}
} else {
/* Check all tiles adjacent to the current tile. */
foreach (offset in offsets) {
local next_tile = cur_node + offset;
/* Don't turn back */
if (path.GetParent() != null && next_tile == path.GetParent().GetTile()) continue;
/* Disallow 90 degree turns */
if (path.GetParent() != null && path.GetParent().GetParent() != null &&
next_tile - cur_node == path.GetParent().GetParent().GetTile() - path.GetParent().GetTile()) continue;
/* We add them to the to the neighbours-list if we can build a rail to
* them and no rail exists there. */
if ((path.GetParent() == null || AIRail.BuildRail(path.GetParent().GetTile(), cur_node, next_tile))) {
if (path.GetParent() != null) {
tiles.push([next_tile, self._GetDirection(path.GetParent().GetTile(), cur_node, next_tile, false)]);
} else {
tiles.push([next_tile, self._GetDirection(null, cur_node, next_tile, false)]);
}
}
}
if (path.GetParent() != null && path.GetParent().GetParent() != null) {
local bridges = self._GetTunnelsBridges(path.GetParent().GetTile(), cur_node, self._GetDirection(path.GetParent().GetParent().GetTile(), path.GetParent().GetTile(), cur_node, true));
foreach (tile in bridges) {
tiles.push(tile);
}
}
}
return tiles;
}
function Rail::_CheckDirection(tile, existing_direction, new_direction, self)
{
return false;
}
function Rail::_dir(from, to)
{
if (from - to == 1) return 0;
if (from - to == -1) return 1;
if (from - to == AIMap.GetMapSizeX()) return 2;
if (from - to == -AIMap.GetMapSizeX()) return 3;
throw("Shouldn't come here in _dir");
}
function Rail::_GetDirection(pre_from, from, to, is_bridge)
{
if (is_bridge) {
if (from - to == 1) return 1;
if (from - to == -1) return 2;
if (from - to == AIMap.GetMapSizeX()) return 4;
if (from - to == -AIMap.GetMapSizeX()) return 8;
}
return 1 << (4 + (pre_from == null ? 0 : 4 * this._dir(pre_from, from)) + this._dir(from, to));
}
/**
* Get a list of all bridges and tunnels that can be build from the
* current tile. Bridges will only be build starting on non-flat tiles
* for performance reasons. Tunnels will only be build if no terraforming
* is needed on both ends.
*/
function Rail::_GetTunnelsBridges(last_node, cur_node, bridge_dir)
{
local slope = AITile.GetSlope(cur_node);
if (slope == AITile.SLOPE_FLAT && AITile.IsBuildable(cur_node + (cur_node - last_node))) return [];
local tiles = [];
for (local i = 2; i < this._max_bridge_length; i++) {
local bridge_list = AIBridgeList_Length(i + 1);
local target = cur_node + i * (cur_node - last_node);
if (!bridge_list.IsEmpty() && AIBridge.BuildBridge(AIVehicle.VEHICLE_RAIL, bridge_list.Begin(), cur_node, target)) {
tiles.push([target, bridge_dir]);
}
}
if (slope != AITile.SLOPE_SW && slope != AITile.SLOPE_NW && slope != AITile.SLOPE_SE && slope != AITile.SLOPE_NE) return tiles;
local other_tunnel_end = AITunnel.GetOtherTunnelEnd(cur_node);
if (!AIMap.IsValidTile(other_tunnel_end)) return tiles;
local tunnel_length = AIMap.DistanceManhattan(cur_node, other_tunnel_end);
local prev_tile = cur_node + (cur_node - other_tunnel_end) / tunnel_length;
if (AITunnel.GetOtherTunnelEnd(other_tunnel_end) == cur_node && tunnel_length >= 2 &&
prev_tile == last_node && tunnel_length < _max_tunnel_length && AITunnel.BuildTunnel(AIVehicle.VEHICLE_RAIL, cur_node)) {
tiles.push([other_tunnel_end, bridge_dir]);
}
return tiles;
}
function Rail::_IsSlopedRail(start, middle, end)
{
local NW = 0; // Set to true if we want to build a rail to / from the north-west
local NE = 0; // Set to true if we want to build a rail to / from the north-east
local SW = 0; // Set to true if we want to build a rail to / from the south-west
local SE = 0; // Set to true if we want to build a rail to / from the south-east
if (middle - AIMap.GetMapSizeX() == start || middle - AIMap.GetMapSizeX() == end) NW = 1;
if (middle - 1 == start || middle - 1 == end) NE = 1;
if (middle + AIMap.GetMapSizeX() == start || middle + AIMap.GetMapSizeX() == end) SE = 1;
if (middle + 1 == start || middle + 1 == end) SW = 1;
/* If there is a turn in the current tile, it can't be sloped. */
if ((NW || SE) && (NE || SW)) return false;
local slope = AITile.GetSlope(middle);
/* A rail on a steep slope is always sloped. */
if (AITile.IsSteepSlope(slope)) return true;
/* If only one corner is raised, the rail is sloped. */
if (slope == AITile.SLOPE_N || slope == AITile.SLOPE_W) return true;
if (slope == AITile.SLOPE_S || slope == AITile.SLOPE_E) return true;
if (NW && (slope == AITile.SLOPE_NW || slope == AITile.SLOPE_SE)) return true;
if (NE && (slope == AITile.SLOPE_NE || slope == AITile.SLOPE_SW)) return true;
return false;
}

@ -0,0 +1,12 @@
/* $Id$ */
class Road extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Road"; }
function GetDescription() { return "An implementation of a road pathfinder"; }
function GetVersion() { return 3; }
function GetDate() { return "2008-06-18"; }
function CreateInstance() { return "Road"; }
}
RegisterLibrary(Road());

@ -0,0 +1,363 @@
/* $Id$ */
/**
* A Road Pathfinder.
* This road pathfinder tries to find a buildable / existing route for
* road vehicles. You can changes the costs below using for example
* roadpf.cost.turn = 30. Note that it's not allowed to change the cost
* between consecutive calls to FindPath. You can change the cost before
* the first call to FindPath and after FindPath has returned an actual
* route. To use only existing roads, set cost.no_existing_road to
* cost.max_cost.
*/
class Road
{
_aystar_class = import("graph.aystar", "", 4);
_max_cost = null; ///< The maximum cost for a route.
_cost_tile = null; ///< The cost for a single tile.
_cost_no_existing_road = null; ///< The cost that is added to _cost_tile if no road exists yet.
_cost_turn = null; ///< The cost that is added to _cost_tile if the direction changes.
_cost_slope = null; ///< The extra cost if a road tile is sloped.
_cost_bridge_per_tile = null; ///< The cost per tile of a new bridge, this is added to _cost_tile.
_cost_tunnel_per_tile = null; ///< The cost per tile of a new tunnel, this is added to _cost_tile.
_cost_coast = null; ///< The extra cost for a coast tile.
_pathfinder = null; ///< A reference to the used AyStar object.
_max_bridge_length = null; ///< The maximum length of a bridge that will be build.
_max_tunnel_length = null; ///< The maximum length of a tunnel that will be build.
cost = null; ///< Used to change the costs.
_running = null;
constructor()
{
this._max_cost = 10000000;
this._cost_tile = 100;
this._cost_no_existing_road = 40;
this._cost_turn = 100;
this._cost_slope = 200;
this._cost_bridge_per_tile = 150;
this._cost_tunnel_per_tile = 120;
this._cost_coast = 20;
this._max_bridge_length = 10;
this._max_tunnel_length = 20;
this._pathfinder = this._aystar_class(this._Cost, this._Estimate, this._Neighbours, this._CheckDirection, this, this, this, this);
this.cost = this.Cost(this);
this._running = false;
}
/**
* Initialize a path search between sources and goals.
* @param sources The source tiles.
* @param goals The target tiles.
* @see AyStar::InitializePath()
*/
function InitializePath(sources, goals) {
local nsources = [];
foreach (node in sources) {
nsources.push([node, 0xFF]);
}
this._pathfinder.InitializePath(nsources, goals);
}
/**
* Try to find the path as indicated with InitializePath with the lowest cost.
* @param iterations After how many iterations it should abort for a moment.
* This value should either be -1 for infinite, or > 0. Any other value
* aborts immediatly and will never find a path.
* @return A route if one was found, or false if the amount of iterations was
* reached, or null if no path was found.
* You can call this function over and over as long as it returns false,
* which is an indication it is not yet done looking for a route.
* @see AyStar::FindPath()
*/
function FindPath(iterations);
};
class Road.Cost
{
_main = null;
function _set(idx, val)
{
if (this._main._running) throw("You are not allowed to change parameters of a running pathfinder.");
switch (idx) {
case "max_cost": this._main._max_cost = val; break;
case "tile": this._main._cost_tile = val; break;
case "no_existing_road": this._main._cost_no_existing_road = val; break;
case "turn": this._main._cost_turn = val; break;
case "slope": this._main._cost_slope = val; break;
case "bridge_per_tile": this._main._cost_bridge_per_tile = val; break;
case "tunnel_per_tile": this._main._cost_tunnel_per_tile = val; break;
case "coast": this._main._cost_coast = val; break;
case "max_bridge_length": this._main._max_bridge_length = val; break;
case "max_tunnel_length": this._main._max_tunnel_length = val; break;
default: throw("the index '" + idx + "' does not exist");
}
return val;
}
function _get(idx)
{
switch (idx) {
case "max_cost": return this._main._max_cost;
case "tile": return this._main._cost_tile;
case "no_existing_road": return this._main._cost_no_existing_road;
case "turn": return this._main._cost_turn;
case "slope": return this._main._cost_slope;
case "bridge_per_tile": return this._main._cost_bridge_per_tile;
case "tunnel_per_tile": return this._main._cost_tunnel_per_tile;
case "coast": return this._main._cost_coast;
case "max_bridge_length": return this._main._max_bridge_length;
case "max_tunnel_length": return this._main._max_tunnel_length;
default: throw("the index '" + idx + "' does not exist");
}
}
constructor(main)
{
this._main = main;
}
};
function Road::FindPath(iterations)
{
local test_mode = AITestMode();
local ret = this._pathfinder.FindPath(iterations);
this._running = (ret == false) ? true : false;
return ret;
}
function Road::_GetBridgeNumSlopes(end_a, end_b)
{
local slopes = 0;
local direction = (end_b - end_a) / AIMap.DistanceManhattan(end_a, end_b);
local slope = AITile.GetSlope(end_a);
if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
slopes++;
}
local slope = AITile.GetSlope(end_b);
direction = -direction;
if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
slopes++;
}
return slopes;
}
function Road::_Cost(path, new_tile, new_direction, self)
{
/* path == null means this is the first node of a path, so the cost is 0. */
if (path == null) return 0;
local prev_tile = path.GetTile();
/* If the new tile is a bridge / tunnel tile, check whether we came from the other
* end of the bridge / tunnel or if we just entered the bridge / tunnel. */
if (AIBridge.IsBridgeTile(new_tile)) {
if (AIBridge.GetOtherBridgeEnd(new_tile) != prev_tile) return path.GetCost() + self._cost_tile;
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
}
if (AITunnel.IsTunnelTile(new_tile)) {
if (AITunnel.GetOtherTunnelEnd(new_tile) != prev_tile) return path.GetCost() + self._cost_tile;
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile;
}
/* If the two tiles are more then 1 tile apart, the pathfinder wants a bridge or tunnel
* to be build. It isn't an existing bridge / tunnel, as that case is already handled. */
if (AIMap.DistanceManhattan(new_tile, prev_tile) > 1) {
/* Check if we should build a bridge or a tunnel. */
if (AITunnel.GetOtherTunnelEnd(new_tile) == prev_tile) {
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_tunnel_per_tile);
} else {
return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_bridge_per_tile) + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
}
}
/* Check for a turn. We do this by substracting the TileID of the current node from
* the TileID of the previous node and comparing that to the difference between the
* previous node and the node before that. */
local cost = self._cost_tile;
if (path.GetParent() != null && (prev_tile - path.GetParent().GetTile()) != (new_tile - prev_tile) &&
AIMap.DistanceManhattan(path.GetParent().GetTile(), prev_tile) == 1) {
cost += self._cost_turn;
}
/* Check if the new tile is a coast tile. */
if (AITile.IsCoastTile(new_tile)) {
cost += self._cost_coast;
}
/* Check if the last tile was sloped. */
if (path.GetParent() != null && !AIBridge.IsBridgeTile(prev_tile) && !AITunnel.IsTunnelTile(prev_tile) &&
self._IsSlopedRoad(path.GetParent().GetTile(), prev_tile, new_tile)) {
cost += self._cost_slope;
}
if (!AIRoad.AreRoadTilesConnected(prev_tile, new_tile)) {
cost += self._cost_no_existing_road;
}
return path.GetCost() + cost;
}
function Road::_Estimate(cur_tile, cur_direction, goal_tiles, self)
{
local min_cost = self._max_cost;
/* As estimate we multiply the lowest possible cost for a single tile with
* with the minimum number of tiles we need to traverse. */
foreach (tile in goal_tiles) {
min_cost = min(AIMap.DistanceManhattan(cur_tile, tile) * self._cost_tile, min_cost);
}
return min_cost;
}
function Road::_Neighbours(path, cur_node, self)
{
/* self._max_cost is the maximum path cost, if we go over it, the path isn't valid. */
if (path.GetCost() >= self._max_cost) return [];
local tiles = [];
/* Check if the current tile is part of a bridge or tunnel. */
if ((AIBridge.IsBridgeTile(cur_node) || AITunnel.IsTunnelTile(cur_node)) &&
AITile.HasTransportType(cur_node, AITile.TRANSPORT_ROAD)) {
local other_end = AIBridge.IsBridgeTile(cur_node) ? AIBridge.GetOtherBridgeEnd(cur_node) : AITunnel.GetOtherTunnelEnd(cur_node);
local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
if (AIRoad.AreRoadTilesConnected(cur_node, next_tile) || AITile.IsBuildable(next_tile) || AIRoad.IsRoadTile(next_tile)) {
tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
}
/* The other end of the bridge / tunnel is a neighbour. */
tiles.push([other_end, self._GetDirection(next_tile, cur_node, true) << 4]);
} else if (path.GetParent() != null && AIMap.DistanceManhattan(cur_node, path.GetParent().GetTile()) > 1) {
local other_end = path.GetParent().GetTile();
local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
if (AIRoad.AreRoadTilesConnected(cur_node, next_tile) || AIRoad.BuildRoad(cur_node, next_tile)) {
tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
}
} else {
local offsets = [AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1),
AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0)];
/* Check all tiles adjacent to the current tile. */
foreach (offset in offsets) {
local next_tile = cur_node + offset;
/* We add them to the to the neighbours-list if one of the following applies:
* 1) There already is a connections between the current tile and the next tile.
* 2) We can build a road to the next tile.
* 3) The next tile is the entrance of a tunnel / bridge in the correct direction. */
if (AIRoad.AreRoadTilesConnected(cur_node, next_tile)) {
tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
} else if ((AITile.IsBuildable(next_tile) || AIRoad.IsRoadTile(next_tile)) &&
(path.GetParent() == null || AIRoad.CanBuildConnectedRoadPartsHere(cur_node, path.GetParent().GetTile(), next_tile)) &&
AIRoad.BuildRoad(cur_node, next_tile)) {
tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
} else if (self._CheckTunnelBridge(cur_node, next_tile)) {
tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
}
}
if (path.GetParent() != null) {
local bridges = self._GetTunnelsBridges(path.GetParent().GetTile(), cur_node, self._GetDirection(path.GetParent().GetTile(), cur_node, true) << 4);
foreach (tile in bridges) {
tiles.push(tile);
}
}
}
return tiles;
}
function Road::_CheckDirection(tile, existing_direction, new_direction, self)
{
return false;
}
function Road::_GetDirection(from, to, is_bridge)
{
if (!is_bridge && AITile.GetSlope(to) == AITile.SLOPE_FLAT) return 0xFF;
if (from - to == 1) return 1;
if (from - to == -1) return 2;
if (from - to == AIMap.GetMapSizeX()) return 4;
if (from - to == -AIMap.GetMapSizeX()) return 8;
}
/**
* Get a list of all bridges and tunnels that can be build from the
* current tile. Bridges will only be build starting on non-flat tiles
* for performance reasons. Tunnels will only be build if no terraforming
* is needed on both ends.
*/
function Road::_GetTunnelsBridges(last_node, cur_node, bridge_dir)
{
local slope = AITile.GetSlope(cur_node);
if (slope == AITile.SLOPE_FLAT) return [];
local tiles = [];
for (local i = 2; i < this._max_bridge_length; i++) {
local bridge_list = AIBridgeList_Length(i + 1);
local target = cur_node + i * (cur_node - last_node);
if (!bridge_list.IsEmpty() && AIBridge.BuildBridge(AIVehicle.VEHICLE_ROAD, bridge_list.Begin(), cur_node, target)) {
tiles.push([target, bridge_dir]);
}
}
if (slope != AITile.SLOPE_SW && slope != AITile.SLOPE_NW && slope != AITile.SLOPE_SE && slope != AITile.SLOPE_NE) return tiles;
local other_tunnel_end = AITunnel.GetOtherTunnelEnd(cur_node);
if (!AIMap.IsValidTile(other_tunnel_end)) return tiles;
local tunnel_length = AIMap.DistanceManhattan(cur_node, other_tunnel_end);
local prev_tile = cur_node + (cur_node - other_tunnel_end) / tunnel_length;
if (AITunnel.GetOtherTunnelEnd(other_tunnel_end) == cur_node && tunnel_length >= 2 &&
prev_tile == last_node && tunnel_length < _max_tunnel_length && AITunnel.BuildTunnel(AIVehicle.VEHICLE_ROAD, cur_node)) {
tiles.push([other_tunnel_end, bridge_dir]);
}
return tiles;
}
function Road::_IsSlopedRoad(start, middle, end)
{
local NW = 0; //Set to true if we want to build a road to / from the north-west
local NE = 0; //Set to true if we want to build a road to / from the north-east
local SW = 0; //Set to true if we want to build a road to / from the south-west
local SE = 0; //Set to true if we want to build a road to / from the south-east
if (middle - AIMap.GetMapSizeX() == start || middle - AIMap.GetMapSizeX() == end) NW = 1;
if (middle - 1 == start || middle - 1 == end) NE = 1;
if (middle + AIMap.GetMapSizeX() == start || middle + AIMap.GetMapSizeX() == end) SE = 1;
if (middle + 1 == start || middle + 1 == end) SW = 1;
/* If there is a turn in the current tile, it can't be sloped. */
if ((NW || SE) && (NE || SW)) return false;
local slope = AITile.GetSlope(middle);
/* A road on a steep slope is always sloped. */
if (AITile.IsSteepSlope(slope)) return true;
/* If only one corner is raised, the road is sloped. */
if (slope == AITile.SLOPE_N || slope == AITile.SLOPE_W) return true;
if (slope == AITile.SLOPE_S || slope == AITile.SLOPE_E) return true;
if (NW && (slope == AITile.SLOPE_NW || slope == AITile.SLOPE_SE)) return true;
if (NE && (slope == AITile.SLOPE_NE || slope == AITile.SLOPE_SW)) return true;
return false;
}
function Road::_CheckTunnelBridge(current_tile, new_tile)
{
if (!AIBridge.IsBridgeTile(new_tile) && !AITunnel.IsTunnelTile(new_tile)) return false;
local dir = new_tile - current_tile;
local other_end = AIBridge.IsBridgeTile(new_tile) ? AIBridge.GetOtherBridgeEnd(new_tile) : AITunnel.GetOtherTunnelEnd(new_tile);
local dir2 = other_end - new_tile;
if ((dir < 0 && dir2 > 0) || (dir > 0 && dir2 < 0)) return false;
dir = abs(dir);
dir2 = abs(dir2);
if ((dir >= AIMap.GetMapSizeX() && dir2 < AIMap.GetMapSizeX()) ||
(dir < AIMap.GetMapSizeX() && dir2 >= AIMap.GetMapSizeX())) return false;
return true;
}

@ -0,0 +1,12 @@
/* $Id$ */
class BinaryHeap extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Binary Heap"; }
function GetDescription() { return "An implementation of a Binary Heap"; }
function GetVersion() { return 1; }
function GetDate() { return "2008-06-10"; }
function CreateInstance() { return "BinaryHeap"; }
}
RegisterLibrary(BinaryHeap());

@ -0,0 +1,131 @@
/* $Id$ */
/**
* Binary Heap.
* Peek and Pop always return the current lowest value in the list.
* Sort is done on insertion and on deletion.
*/
class BinaryHeap
{
_queue = null;
_count = 0;
constructor()
{
_queue = [];
}
/**
* Insert a new entry in the list.
* The complexity of this operation is O(ln n).
* @param item The item to add to the list.
* @param priority The priority this item has.
*/
function Insert(item, priority);
/**
* Pop the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(ln n).
* @return The item of the entry with the lowest priority.
*/
function Pop();
/**
* Peek the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(1).
* @return The item of the entry with the lowest priority.
*/
function Peek();
/**
* Get the amount of current items in the list.
* The complexity of this operation is O(1).
* @return The amount of items currently in the list.
*/
function Count();
/**
* Check if an item exists in the list.
* The complexity of this operation is O(n).
* @param item The item to check for.
* @return True if the item is already in the list.
*/
function Exists(item);
};
function BinaryHeap::Insert(item, priority)
{
/* Append dummy entry */
_queue.append(0);
_count++;
local hole;
/* Find the point of insertion */
for (hole = _count - 1; hole > 0 && priority <= _queue[hole / 2][1]; hole /= 2)
_queue[hole] = _queue[hole / 2];
/* Insert new pair */
_queue[hole] = [item, priority];
return true;
}
function BinaryHeap::Pop()
{
if (_count == 0) return null;
local node = _queue[0];
/* Remove the item from the list by putting the last value on top */
_queue[0] = _queue[_count - 1];
_queue.pop();
_count--;
/* Bubble down the last value to correct the tree again */
_BubbleDown();
return node[0];
}
function BinaryHeap::Peek()
{
if (_count == 0) return null;
return _queue[0][0];
}
function BinaryHeap::Count()
{
return _count;
}
function BinaryHeap::Exists(item)
{
/* Brute-force find the item (there is no faster way, as we don't have the priority number) */
foreach (node in _queue) {
if (node[0] == item) return true;
}
return false;
}
function BinaryHeap::_BubbleDown()
{
if (_count == 0) return;
local hole = 1;
local tmp = _queue[0];
/* Start switching parent and child until the tree is restored */
while (hole * 2 < _count + 1) {
local child = hole * 2;
if (child != _count && _queue[child][1] <= _queue[child - 1][1]) child++;
if (_queue[child - 1][1] > tmp[1]) break;
_queue[hole - 1] = _queue[child - 1];
hole = child;
}
/* The top value is now at his new place */
_queue[hole - 1] = tmp;
}

@ -0,0 +1,12 @@
/* $Id$ */
class FibonacciHeap extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Fibonacci Heap"; }
function GetDescription() { return "An implementation of a Fibonacci Heap"; }
function GetVersion() { return 1; }
function GetDate() { return "2008-08-22"; }
function CreateInstance() { return "FibonacciHeap"; }
}
RegisterLibrary(FibonacciHeap());

@ -0,0 +1,204 @@
/* $Id$ */
/**
* Fibonacci heap.
* This heap is heavily optimized for the Insert and Pop functions.
* Peek and Pop always return the current lowest value in the list.
* Insert is implemented as a lazy insert, as it will simply add the new
* node to the root list. Sort is done on every Pop operation.
*/
class FibonacciHeap {
_min = null;
_min_index = 0;
_min_priority = 0;
_count = 0;
_root_list = null;
/**
* Create a new fibonacci heap.
* http://en.wikipedia.org/wiki/Fibonacci_heap
*/
constructor() {
_count = 0;
_min = Node();
_min.priority = 0x7FFFFFFF;
_min_index = 0;
_min_priority = 0x7FFFFFFF;
_root_list = [];
}
/**
* Insert a new entry in the heap.
* The complexity of this operation is O(1).
* @param item The item to add to the list.
* @param priority The priority this item has.
*/
function Insert(item, priority);
/**
* Pop the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(ln n).
* @return The item of the entry with the lowest priority.
*/
function Pop();
/**
* Peek the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(1).
* @return The item of the entry with the lowest priority.
*/
function Peek();
/**
* Get the amount of current items in the list.
* The complexity of this operation is O(1).
* @return The amount of items currently in the list.
*/
function Count();
/**
* Check if an item exists in the list.
* The complexity of this operation is O(n).
* @param item The item to check for.
* @return True if the item is already in the list.
*/
function Exists(item);
};
function FibonacciHeap::Insert(item, priority) {
/* Create a new node instance to add to the heap. */
local node = Node();
/* Changing params is faster than using constructor values */
node.item = item;
node.priority = priority;
/* Update the reference to the minimum node if this node has a
* smaller priority. */
if (_min_priority > priority) {
_min = node;
_min_index = _root_list.len();
_min_priority = priority;
}
_root_list.append(node);
_count++;
}
function FibonacciHeap::Pop() {
if (_count == 0) return null;
/* Bring variables from the class scope to this scope explicitly to
* optimize variable lookups by Squirrel. */
local z = _min;
local tmp_root_list = _root_list;
/* If there are any children, bring them all to the root level. */
tmp_root_list.extend(z.child);
/* Remove the minimum node from the rootList. */
tmp_root_list.remove(_min_index);
local root_cache = {};
/* Now we decrease the number of nodes on the root level by
* merging nodes which have the same degree. The node with
* the lowest priority value will become the parent. */
foreach(x in tmp_root_list) {
local y;
/* See if we encountered a node with the same degree already. */
while (y = root_cache.rawdelete(x.degree)) {
/* Check the priorities. */
if (x.priority > y.priority) {
local tmp = x;
x = y;
y = tmp;
}
/* Make y a child of x. */
x.child.append(y);
x.degree++;
}
root_cache[x.degree] <- x;
}
/* The root_cache contains all the nodes which will form the
* new rootList. We reset the priority to the maximum number
* for a 32 signed integer to find a new minumum. */
tmp_root_list.resize(root_cache.len());
local i = 0;
local tmp_min_priority = 0x7FFFFFFF;
/* Now we need to find the new minimum among the root nodes. */
foreach (val in root_cache) {
if (val.priority < tmp_min_priority) {
_min = val;
_min_index = i;
tmp_min_priority = val.priority;
}
tmp_root_list[i++] = val;
}
/* Update global variables. */
_min_priority = tmp_min_priority;
_count--;
return z.item;
}
function FibonacciHeap::Peek() {
if (_count == 0) return null;
return _min.item;
}
function FibonacciHeap::Count() {
return _count;
}
function FibonacciHeap::Exists(item) {
return ExistsIn(_root_list, item);
}
/**
* Auxilary function to search through the whole heap.
* @param list The list of nodes to look through.
* @param item The item to search for.
* @return True if the item is found, false otherwise.
*/
function FibonacciHeap::ExistsIn(list, item) {
foreach (val in list) {
if (val.item == item) {
return true;
}
foreach (c in val.child) {
if (ExistsIn(c, item)) {
return true;
}
}
}
/* No luck, item doesn't exists in the tree rooted under list. */
return false;
}
/**
* Basic class the fibonacci heap is composed of.
*/
class FibonacciHeap.Node {
degree = null;
child = null;
item = null;
priority = null;
constructor() {
child = [];
degree = 0;
}
};

@ -0,0 +1,12 @@
/* $Id$ */
class PriorityQueue extends AILibrary {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Priority Queue"; }
function GetDescription() { return "An implementation of a Priority Queue"; }
function GetVersion() { return 2; }
function GetDate() { return "2008-06-10"; }
function CreateInstance() { return "PriorityQueue"; }
}
RegisterLibrary(PriorityQueue());

@ -0,0 +1,115 @@
/* $Id$ */
/**
* Priority Queue.
* Peek and Pop always return the current lowest value in the list.
* Sort is done on insertion only.
*/
class PriorityQueue
{
_queue = null;
_count = 0;
constructor()
{
_count = 0;
_queue = [];
}
/**
* Insert a new entry in the list.
* The complexity of this operation is O(n).
* @param item The item to add to the list.
* @param priority The priority this item has.
*/
function Insert(item, priority);
/**
* Pop the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(1).
* @return The item of the entry with the lowest priority.
*/
function Pop();
/**
* Peek the first entry of the list.
* This is always the item with the lowest priority.
* The complexity of this operation is O(1).
* @return The item of the entry with the lowest priority.
*/
function Peek();
/**
* Get the amount of current items in the list.
* The complexity of this operation is O(1).
* @return The amount of items currently in the list.
*/
function Count();
/**
* Check if an item exists in the list.
* The complexity of this operation is O(n).
* @param item The item to check for.
* @return True if the item is already in the list.
*/
function Exists(item);
};
function PriorityQueue::Insert(item, priority)
{
/* Append dummy entry */
_queue.append(0);
_count++;
local i;
/* Find the point of insertion */
for (i = _count - 2; i >= 0; i--) {
if (priority > _queue[i][1]) {
/* All items bigger move one place to the right */
_queue[i + 1] = _queue[i];
} else if (item == _queue[i][0]) {
/* Same item, ignore insertion */
return false;
} else {
/* Found place to insert at */
break;
}
}
/* Insert new pair */
_queue[i + 1] = [item, priority];
return true;
}
function PriorityQueue::Pop()
{
if (_count == 0) return null;
local node = _queue.pop();
_count--;
return node[0];
}
function PriorityQueue::Peek()
{
if (_count == 0) return null;
return _queue[_count - 1][0];
}
function PriorityQueue::Count()
{
return _count;
}
function PriorityQueue::Exists(item)
{
/* Brute-force find the item (there is no faster way, as we don't have the priority number) */
foreach (node in _queue) {
if (node[0] == item) return true;
}
return false;
}

@ -0,0 +1,67 @@
#!/bin/sh
if ! [ -f ai/regression/regression.nut ]; then
echo "Make sure you are in the root of OpenTTD before starting this script."
exit 1
fi
cat ai/regression/regression.nut | tr ';' '\n' | awk '
/^function/ {
for (local in locals) {
delete locals[local]
}
if (match($0, "function Regression::Start") || match($0, "function Regression::Stop")) next
locals["this"] = "AIControllerSquirrel"
}
/local/ {
gsub(".*local", "local")
if (match($4, "^AI")) {
sub("\\(.*", "", $4)
locals[$2] = $4
}
}
/Valuate/ {
gsub(".*Valuate\\(", "")
gsub("\\).*", "")
gsub(",.*", "")
gsub("\\.", "::")
print $0
}
/\./ {
for (local in locals) {
if (match($0, local ".")) {
fname = substr($0, index($0, local "."))
sub("\\(.*", "", fname)
sub("\\.", "::", fname)
sub(local, locals[local], fname)
print fname
if (match(locals[local], "List")) {
sub(locals[local], "AIAbstractList", fname)
print fname
}
}
}
# We want to remove everything before the FIRST occurence of AI.
# If we do not remove any other occurences of AI from the string
# we will remove everything before the LAST occurence of AI, so
# do some little magic to make it work the way we want.
sub("AI", "AXXXXY")
gsub("AI", "AXXXXX")
sub(".*AXXXXY", "AI")
if (match($0, "^AI") && match($0, ".")) {
sub("\\(.*", "", $0)
sub("\\.", "::", $0)
print $0
}
}
' | sed 's/ //g' | sort | uniq > tmp.in_regression
grep 'DefSQ.*Method' ../src/ai/api/*.hpp.sq | grep -v 'AIError::' | grep -v 'AIAbstractList::Valuate' | grep -v '::GetClassName' | sed 's/^[^,]*, &//g;s/,[^,]*//g' | sort > tmp.in_api
diff -u tmp.in_regression tmp.in_api | grep -v '^+++' | grep '^+' | sed 's/^+//'
rm -f tmp.in_regression tmp.in_api

@ -0,0 +1,17 @@
[misc]
display_opt = SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|WAYPOINTS
language = english.lng
[gui]
autosave = off
[game_creation]
town_name = english
[ai_players]
none =
regression =
[vehicle]
road_side = right
plane_speed = 2

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,11 @@
class Regression extends AIInfo {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Regression"; }
function GetDescription() { return "This runs regression-tests on all commands. On the same map the result should always be the same."; }
function GetVersion() { return 1; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; }
}
RegisterAI(Regression());

@ -0,0 +1,3 @@
print(" Required this file");

@ -0,0 +1,49 @@
#!/bin/sh
if ! [ -f ai/regression/regression.nut ]; then
echo "Make sure you are in the root of OpenTTD before starting this script."
exit 1
fi
cp ai/regression/regression.nut ai/regression/main.nut
cp ai/regression/regression_info.nut ai/regression/info.nut
if [ -f scripts/game_start.scr ]; then
mv scripts/game_start.scr scripts/game_start.src.regression
fi
params=""
gdb=""
if [ "$1" != "-r" ]; then
params="-snull -mnull -vnull:ticks=30000"
fi
if [ "$1" = "-g" ]; then
gdb="gdb --ex run --args "
fi
if [ -n "$gdb" ]; then
$gdb ./openttd -x -c ai/regression/regression.cfg $params -g ai/regression/regression.sav
else
./openttd -x -c ai/regression/regression.cfg $params -g ai/regression/regression.sav -d ai=2 2>&1 | awk '{ gsub("0x\\(nil\\)", "0x00000000", $0); gsub("^dbg: \\[ai\\]", "", $0); gsub("^ ", "ERROR: ", $0); gsub("ERROR: \\[1\\] ", "", $0); gsub("\\[P\\] ", "", $0); print $0; }' > tmp.regression
fi
if [ -z "$gdb" ]; then
res="`diff -ub ai/regression/regression.txt tmp.regression`"
if [ -z "$res" ]; then
echo "Regression test passed!"
else
echo "Regression test failed! Difference:"
echo "$res"
fi
echo ""
echo "Regression test done"
fi
rm -f ai/regression/main.nut ai/regression/info.nut
if [ -f scripts/game_start.scr.regression ]; then
mv scripts/game_start.scr.regression scripts/game_start.src
fi
if [ "$1" != "-k" ]; then
rm -f tmp.regression
fi

@ -0,0 +1,15 @@
/* $Id$ */
class WrightAI extends AIInfo {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "WrightAI"; }
function GetDescription() { return "A simple AI that tries to beat you with only aircrafts"; }
function GetVersion() { return 2; }
function GetDate() { return "2008-02-24"; }
function CreateInstance() { return "WrightAI"; }
function GetSettings() {
AddSetting({name = "min_town_size", description = "The minimal size of towns to work on", min_value = 100, max_value = 1000, easy_value = 500, medium_value = 400, hard_value = 300, custom_value = 500, flags = 0});
}
}
RegisterAI(WrightAI());

@ -0,0 +1,387 @@
/* $Id$ */
class WrightAI extends AIController {
name = null;
towns_used = null;
route_1 = null;
route_2 = null;
distance_of_route = {};
vehicle_to_depot = {};
delay_build_airport_route = 1000;
passenger_cargo_id = -1;
function Start();
constructor() {
this.towns_used = AIList();
this.route_1 = AIList();
this.route_2 = AIList();
local list = AICargoList();
for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
if (AICargo.HasCargoClass(i, AICargo.CC_PASSENGERS)) {
this.passenger_cargo_id = i;
break;
}
}
}
};
/**
* Check if we have enough money (via loan and on bank).
*/
function WrightAI::HasMoney(money)
{
if (AICompany.GetBankBalance(AICompany.MY_COMPANY) + (AICompany.GetMaxLoanAmount() - AICompany.GetLoanAmount()) > money) return true;
return false;
}
/**
* Get the amount of money requested, loan if needed.
*/
function WrightAI::GetMoney(money)
{
if (!this.HasMoney(money)) return;
if (AICompany.GetBankBalance(AICompany.MY_COMPANY) > money) return;
local loan = money - AICompany.GetBankBalance(AICompany.MY_COMPANY) + AICompany.GetLoanInterval() + AICompany.GetLoanAmount();
loan = loan - loan % AICompany.GetLoanInterval();
AILog.Info("Need a loan to get " + money + ": " + loan);
AICompany.SetLoanAmount(loan);
}
/**
* Build an airport route. Find 2 cities that are big enough and try to build airport in both cities.
* Then we can build an aircraft and make some money.
*/
function WrightAI::BuildAirportRoute()
{
local airport_type = (AIAirport.AirportAvailable(AIAirport.AT_SMALL) ? AIAirport.AT_SMALL : AIAirport.AT_LARGE);
/* Get enough money to work with */
this.GetMoney(150000);
AILog.Info("Trying to build an airport route");
local tile_1 = this.FindSuitableAirportSpot(airport_type, 0);
if (tile_1 < 0) return -1;
local tile_2 = this.FindSuitableAirportSpot(airport_type, tile_1);
if (tile_2 < 0) {
this.towns_used.RemoveValue(tile_1);
return -2;
}
/* Build the airports for real */
if (!AIAirport.BuildAirport(tile_1, airport_type, true)) {
AILog.Error("Although the testing told us we could build 2 airports, it still failed on the first airport at tile " + tile_1 + ".");
this.towns_used.RemoveValue(tile_1);
this.towns_used.RemoveValue(tile_2);
return -3;
}
if (!AIAirport.BuildAirport(tile_2, airport_type, true)) {
AILog.Error("Although the testing told us we could build 2 airports, it still failed on the second airport at tile " + tile_2 + ".");
AIAirport.RemoveAirport(tile_1);
this.towns_used.RemoveValue(tile_1);
this.towns_used.RemoveValue(tile_2);
return -4;
}
local ret = this.BuildAircraft(tile_1, tile_2);
if (ret < 0) {
AIAirport.RemoveAirport(tile_1);
AIAirport.RemoveAirport(tile_2);
this.towns_used.RemoveValue(tile_1);
this.towns_used.RemoveValue(tile_2);
return ret;
}
AILog.Info("Done building a route");
return ret;
}
/**
* Build an aircraft with orders from tile_1 to tile_2.
* The best available aircraft of that time will be bought.
*/
function WrightAI::BuildAircraft(tile_1, tile_2)
{
/* Build an aircraft */
local hangar = AIAirport.GetHangarOfAirport(tile_1);
local engine = null;
local engine_list = AIEngineList(AIVehicle.VEHICLE_AIR);
/* When bank balance < 300000, buy cheaper planes */
local balance = AICompany.GetBankBalance(AICompany.MY_COMPANY);
engine_list.Valuate(AIEngine.GetPrice);
engine_list.KeepBelowValue(balance < 300000 ? 50000 : (balance < 1000000 ? 300000 : 1000000));
engine_list.Valuate(AIEngine.GetCargoType);
engine_list.KeepValue(this.passenger_cargo_id);
engine_list.Valuate(AIEngine.GetCapacity);
engine_list.KeepTop(1);
engine = engine_list.Begin();
if (!AIEngine.IsValidEngine(engine)) {
AILog.Error("Couldn't find a suitable engine");
return -5;
}
local vehicle = AIVehicle.BuildVehicle(hangar, engine);
if (!AIVehicle.IsValidVehicle(vehicle)) {
AILog.Error("Couldn't build the aircraft");
return -6;
}
/* Send him on his way */
AIOrder.AppendOrder(vehicle, tile_1, AIOrder.AIOF_NONE);
AIOrder.AppendOrder(vehicle, tile_2, AIOrder.AIOF_NONE);
AIVehicle.StartStopVehicle(vehicle);
this.distance_of_route.rawset(vehicle, AIMap.DistanceManhattan(tile_1, tile_2));
this.route_1.AddItem(vehicle, tile_1);
this.route_2.AddItem(vehicle, tile_2);
AILog.Info("Done building an aircraft");
return 0;
}
/**
* Find a suitable spot for an airport, walking all towns hoping to find one.
* When a town is used, it is marked as such and not re-used.
*/
function WrightAI::FindSuitableAirportSpot(airport_type, center_tile)
{
local airport_x, airport_y, airport_rad;
airport_x = AIAirport.GetAirportWidth(airport_type);
airport_y = AIAirport.GetAirportHeight(airport_type);
airport_rad = AIAirport.GetAirportCoverageRadius(airport_type);
local town_list = AITownList();
/* Remove all the towns we already used */
town_list.RemoveList(this.towns_used);
town_list.Valuate(AITown.GetPopulation);
town_list.KeepAboveValue(GetSetting("min_town_size"));
/* Keep the best 10, if we can't find 2 stations in there, just leave it anyway */
town_list.KeepTop(10);
town_list.Valuate(AIBase.RandItem);
/* Now find 2 suitable towns */
for (local town = town_list.Begin(); town_list.HasNext(); town = town_list.Next()) {
/* Don't make this a CPU hog */
Sleep(1);
local tile = AITown.GetLocation(town);
/* Create a 30x30 grid around the core of the town and see if we can find a spot for a small airport */
local list = AITileList();
/* XXX -- We assume we are more than 15 tiles away from the border! */
list.AddRectangle(tile - AIMap.GetTileIndex(15, 15), tile + AIMap.GetTileIndex(15, 15));
list.Valuate(AITile.IsBuildableRectangle, airport_x, airport_y);
list.KeepValue(1);
if (center_tile != 0) {
/* If we have a tile defined, we don't want to be within 25 tiles of this tile */
list.Valuate(AITile.GetDistanceSquareToTile, center_tile);
list.KeepAboveValue(625);
}
/* Sort on acceptance, remove places that don't have acceptance */
list.Valuate(AITile.GetCargoAcceptance, this.passenger_cargo_id, airport_x, airport_y, airport_rad);
list.RemoveBelowValue(10);
/* Couldn't find a suitable place for this town, skip to the next */
if (list.Count() == 0) continue;
/* Walk all the tiles and see if we can build the airport at all */
{
local test = AITestMode();
local good_tile = 0;
for (tile = list.Begin(); list.HasNext(); tile = list.Next()) {
Sleep(1);
if (!AIAirport.BuildAirport(tile, airport_type, true)) continue;
good_tile = tile;
break;
}
/* Did we found a place to build the airport on? */
if (good_tile == 0) continue;
}
AILog.Info("Found a good spot for an airport in town " + town + " at tile " + tile);
/* Make the town as used, so we don't use it again */
this.towns_used.AddItem(town, tile);
return tile;
}
AILog.Info("Couldn't find a suitable town to build an airport in");
return -1;
}
function WrightAI::ManageAirRoutes()
{
local list = AIVehicleList();
list.Valuate(AIVehicle.GetAge);
/* Give the plane at least 2 years to make a difference */
list.KeepAboveValue(365 * 2);
list.Valuate(AIVehicle.GetProfitLastYear);
for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
local profit = list.GetValue(i);
/* Profit last year and this year bad? Let's sell the vehicle */
if (profit < 10000 && AIVehicle.GetProfitThisYear(i) < 10000) {
/* Send the vehicle to depot if we didn't do so yet */
if (!vehicle_to_depot.rawin(i) || vehicle_to_depot.rawget(i) != true) {
AILog.Info("Sending " + i + " to depot as profit is: " + profit + " / " + AIVehicle.GetProfitThisYear(i));
AIVehicle.SendVehicleToDepot(i);
vehicle_to_depot.rawset(i, true);
}
}
/* Try to sell it over and over till it really is in the depot */
if (vehicle_to_depot.rawin(i) && vehicle_to_depot.rawget(i) == true) {
if (AIVehicle.SellVehicle(i)) {
AILog.Info("Selling " + i + " as it finally is in a depot.");
/* Check if we are the last one serving those airports; else sell the airports */
local list2 = AIVehicleList_Station(AIStation.GetStationID(this.route_1.GetValue(i)));
if (list2.Count() == 0) this.SellAirports(i);
vehicle_to_depot.rawdelete(i);
}
}
}
/* Don't try to add planes when we are short on cash */
if (!this.HasMoney(50000)) return;
list = AIStationList(AIStation.STATION_AIRPORT);
list.Valuate(AIStation.GetCargoWaiting, this.passenger_cargo_id);
list.KeepAboveValue(250);
for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
local list2 = AIVehicleList_Station(i);
/* No vehicles going to this station, abort and sell */
if (list2.Count() == 0) {
this.SellAirports(i);
continue;
};
/* Find the first vehicle that is going to this station */
local v = list2.Begin();
local dist = this.distance_of_route.rawget(v);
list2.Valuate(AIVehicle.GetAge);
list2.KeepBelowValue(dist);
/* Do not build a new vehicle if we bought a new one in the last DISTANCE days */
if (list2.Count() != 0) continue;
AILog.Info("Station " + i + " (" + AIStation.GetLocation(i) + ") has too many cargo, adding a new vehicle for the route.");
/* Make sure we have enough money */
this.GetMoney(50000);
return this.BuildAircraft(this.route_1.GetValue(v), this.route_2.GetValue(v));
}
}
/**
* Sells the airports from route index i
* Removes towns from towns_used list too
*/
function WrightAI::SellAirports(i) {
/* Remove the airports */
AILog.Info("Removing airports as nobody serves them anymore.");
AIAirport.RemoveAirport(this.route_1.GetValue(i));
AIAirport.RemoveAirport(this.route_2.GetValue(i));
/* Free the towns_used entries */
this.towns_used.RemoveValue(this.route_1.GetValue(i));
this.towns_used.RemoveValue(this.route_2.GetValue(i));
/* Remove the route */
this.route_1.RemoveItem(i);
this.route_2.RemoveItem(i);
}
function WrightAI::HandleEvents()
{
while (AIEventController.IsEventWaiting()) {
local e = AIEventController.GetNextEvent();
switch (e.GetEventType()) {
case AIEvent.AI_ET_VEHICLE_CRASHED: {
local ec = AIEventVehicleCrashed.Convert(e);
local v = ec.GetVehicleID();
AILog.Info("We have a crashed vehicle (" + v + "), buying a new one as replacement");
this.BuildAircraft(this.route_1.GetValue(v), this.route_2.GetValue(v));
this.route_1.RemoveItem(v);
this.route_2.RemoveItem(v);
} break;
default:
break;
}
}
}
function WrightAI::Start()
{
if (this.passenger_cargo_id == -1) {
AILog.Error("WrightAI could not find the passenger cargo");
return;
}
/* Give the boy a name */
if (!AICompany.SetName("WrightAI")) {
local i = 2;
while (!AICompany.SetName("WrightAI #" + i)) {
i++;
}
}
this.name = AICompany.GetName(AICompany.MY_COMPANY);
/* Say hello to the user */
AILog.Info("Welcome to WrightAI. I will be building airports all day long.");
AILog.Info(" - Minimum Town Size: " + GetSetting("min_town_size"));
/* We start with almost no loan, and we take a loan when we want to build something */
AICompany.SetLoanAmount(AICompany.GetLoanInterval());
/* We need our local ticker, as GetTick() will skip ticks */
local ticker = 0;
/* Determine time we may sleep */
local sleepingtime = 100;
if (this.delay_build_airport_route < sleepingtime)
sleepingtime = this.delay_build_airport_route;
/* Let's go on for ever */
while (true) {
/* Once in a while, with enough money, try to build something */
if ((ticker % this.delay_build_airport_route == 0 || ticker == 0) && this.HasMoney(100000)) {
local ret = this.BuildAirportRoute();
if (ret == -1 && ticker != 0) {
/* No more route found, delay even more before trying to find an other */
this.delay_build_airport_route = 10000;
}
else if (ret < 0 && ticker == 0) {
/* The AI failed to build a first airport and is deemed */
AICompany.SetName("Failed " + this.name);
AILog.Error("Failed to build first airport route, now giving up building. Repaying loan. Have a nice day!");
AICompany.SetLoanAmount(0);
return;
}
}
/* Manage the routes once in a while */
if (ticker % 2000 == 0) {
this.ManageAirRoutes();
}
/* Try to get ride of our loan once in a while */
if (ticker % 5000 == 0) {
AICompany.SetLoanAmount(0);
}
/* Check for events once in a while */
if (ticker % 100 == 0) {
this.HandleEvents();
}
/* Make sure we do not create infinite loops */
Sleep(sleepingtime);
ticker += sleepingtime;
}
}

@ -1228,6 +1228,14 @@ make_cflags_and_ldflags() {
CFLAGS="$CFLAGS -DWITH_ZLIB"
fi
# 64bit machines need -D_SQ64
if [ "$cpu_type" = "64" ]; then
CFLAGS="$CFLAGS -D_SQ64"
fi
SCRIPT_SRC_DIR="$ROOT_DIR/src/3rdparty/squirrel/include"
CFLAGS="$CFLAGS -I$SCRIPT_SRC_DIR"
CFLAGS="$CFLAGS -DNO_GARBAGE_COLLECTOR"
if [ -n "$png_config" ]; then
CFLAGS="$CFLAGS -DWITH_PNG"
CFLAGS="$CFLAGS `$png_config --cppflags --I_opts | tr '\n\r' ' '`"
@ -2541,6 +2549,7 @@ make_sed() {
s~!!SRC_OBJS_DIR!!~$SRC_OBJS_DIR~g;
s~!!LANG_OBJS_DIR!!~$LANG_OBJS_DIR~g;
s~!!SRC_DIR!!~$SRC_DIR~g;
s~!!SCRIPT_SRC_DIR!!~$SCRIPT_SRC_DIR~g;
s~!!OSXAPP!!~$OSXAPP~g;
s~!!LANG_DIR!!~$LANG_DIR~g;
s~!!TTD!!~$TTD~g;

@ -1,5 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs80.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}"
ProjectSection(ProjectDependencies) = postProject
{0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966}
@ -26,12 +26,10 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32
{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32
{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64
{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64
{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|Win32
{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32
{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32
{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64
{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64
{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|Win32
{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32
{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32
{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32

@ -59,8 +59,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -166,8 +166,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -268,8 +268,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -376,8 +376,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -775,10 +775,6 @@
<Filter
Name="Header Files"
>
<File
RelativePath=".\..\src\ai\ai.h"
>
</File>
<File
RelativePath=".\..\src\aircraft.h"
>
@ -923,10 +919,6 @@
RelativePath=".\..\src\video\dedicated_v.h"
>
</File>
<File
RelativePath=".\..\src\ai\default\default.h"
>
</File>
<File
RelativePath=".\..\src\depot_base.h"
>
@ -1543,10 +1535,6 @@
RelativePath=".\..\src\transport_type.h"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\trolly.h"
>
</File>
<File
RelativePath=".\..\src\tunnelbridge.h"
>
@ -2241,30 +2229,642 @@
</File>
</Filter>
<Filter
Name="AI Files"
Name="Script"
>
<File
RelativePath=".\..\src\script\squirrel.cpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_class.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_helper.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_helper_type.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_std.cpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_std.hpp"
>
</File>
</Filter>
<Filter
Name="Squirrel"
>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqapi.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqbaselib.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclass.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqcompiler.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqdebug.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncstate.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqlexer.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqmem.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqobject.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstate.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdaux.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqtable.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqvm.cpp"
>
</File>
</Filter>
<Filter
Name="Squirrel headers"
>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqarray.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclass.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclosure.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqcompiler.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncproto.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncstate.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqlexer.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqobject.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqopcodes.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqpcheader.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstate.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdaux.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdblob.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdblobimpl.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdio.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdmath.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdstream.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdstring.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdsystem.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstring.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqtable.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\squirrel.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\squserdata.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\squtils.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqvm.h"
>
</File>
</Filter>
<Filter
Name="AI Core"
>
<File
RelativePath=".\..\src\ai\ai.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_config.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_config.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_core.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_gui.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_gui.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info_dummy.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_instance.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_instance.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_scanner.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_scanner.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_storage.hpp"
>
</File>
</Filter>
<Filter
Name="AI API"
>
<File
RelativePath=".\..\src\ai\api\ai_abstractlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_accounting.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_airport.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_base.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridge.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridgelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargo.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargolist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_company.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_controller.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_date.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_depotlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_engine.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_enginelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_error.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event_types.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_execmode.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_gamesettings.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_group.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_grouplist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industry.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrylist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytype.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytypelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_list.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_log.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_map.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_marine.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_object.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_order.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_rail.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_railtypelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_road.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_sign.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_station.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_stationlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidy.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidylist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_testmode.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tile.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tilelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_town.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_townlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tunnel.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_types.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_vehicle.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_vehiclelist.hpp"
>
</File>
</Filter>
<Filter
Name="AI API Implementation"
>
<File
RelativePath=".\..\src\ai\ai.cpp"
RelativePath=".\..\src\ai\api\ai_abstractlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_accounting.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_airport.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_base.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridge.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridgelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargo.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargolist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_company.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_controller.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_date.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_depotlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_engine.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_enginelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_error.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event_types.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_execmode.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_gamesettings.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_group.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_grouplist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industry.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrylist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytype.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytypelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_list.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_log.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_map.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_marine.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_object.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_order.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_rail.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_railtypelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_road.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_sign.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_station.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_stationlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidy.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidylist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_testmode.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tile.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tilelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\build.cpp"
RelativePath=".\..\src\ai\api\ai_town.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\default\default.cpp"
RelativePath=".\..\src\ai\api\ai_townlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\pathfinder.cpp"
RelativePath=".\..\src\ai\api\ai_tunnel.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\shared.cpp"
RelativePath=".\..\src\ai\api\ai_vehicle.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\trolly.cpp"
RelativePath=".\..\src\ai\api\ai_vehiclelist.cpp"
>
</File>
</Filter>

@ -59,8 +59,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -166,8 +166,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -268,8 +268,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -376,8 +376,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"

@ -60,8 +60,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -165,8 +165,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -266,8 +266,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -373,8 +373,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -772,10 +772,6 @@
<Filter
Name="Header Files"
>
<File
RelativePath=".\..\src\ai\ai.h"
>
</File>
<File
RelativePath=".\..\src\aircraft.h"
>
@ -920,10 +916,6 @@
RelativePath=".\..\src\video\dedicated_v.h"
>
</File>
<File
RelativePath=".\..\src\ai\default\default.h"
>
</File>
<File
RelativePath=".\..\src\depot_base.h"
>
@ -1540,10 +1532,6 @@
RelativePath=".\..\src\transport_type.h"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\trolly.h"
>
</File>
<File
RelativePath=".\..\src\tunnelbridge.h"
>
@ -2238,30 +2226,642 @@
</File>
</Filter>
<Filter
Name="AI Files"
Name="Script"
>
<File
RelativePath=".\..\src\script\squirrel.cpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_class.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_helper.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_helper_type.hpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_std.cpp"
>
</File>
<File
RelativePath=".\..\src\script\squirrel_std.hpp"
>
</File>
</Filter>
<Filter
Name="Squirrel"
>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqapi.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqbaselib.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclass.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqcompiler.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqdebug.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncstate.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqlexer.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqmem.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqobject.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstate.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdaux.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqtable.cpp"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqvm.cpp"
>
</File>
</Filter>
<Filter
Name="Squirrel headers"
>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqarray.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclass.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqclosure.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqcompiler.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncproto.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqfuncstate.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqlexer.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqobject.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqopcodes.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqpcheader.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstate.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdaux.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdblob.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdblobimpl.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdio.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdmath.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\sqstdlib\sqstdstream.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdstring.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\sqstdsystem.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqstring.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqtable.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\include\squirrel.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\squserdata.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\squtils.h"
>
</File>
<File
RelativePath=".\..\src\3rdparty\squirrel\squirrel\sqvm.h"
>
</File>
</Filter>
<Filter
Name="AI Core"
>
<File
RelativePath=".\..\src\ai\ai.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_config.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_config.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_core.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_gui.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_gui.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_info_dummy.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_instance.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_instance.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_scanner.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_scanner.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\ai_storage.hpp"
>
</File>
</Filter>
<Filter
Name="AI API"
>
<File
RelativePath=".\..\src\ai\api\ai_abstractlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_accounting.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_airport.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_base.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridge.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridgelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargo.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargolist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_company.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_controller.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_date.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_depotlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_engine.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_enginelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_error.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event_types.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_execmode.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_gamesettings.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_group.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_grouplist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industry.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrylist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytype.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytypelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_list.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_log.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_map.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_marine.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_object.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_order.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_rail.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_railtypelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_road.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_sign.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_station.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_stationlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidy.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidylist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_testmode.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tile.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tilelist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_town.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_townlist.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tunnel.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_types.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_vehicle.hpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_vehiclelist.hpp"
>
</File>
</Filter>
<Filter
Name="AI API Implementation"
>
<File
RelativePath=".\..\src\ai\ai.cpp"
RelativePath=".\..\src\ai\api\ai_abstractlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_accounting.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_airport.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_base.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridge.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_bridgelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargo.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_cargolist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_company.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_controller.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_date.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_depotlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_engine.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_enginelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_error.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_event_types.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_execmode.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_gamesettings.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_group.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_grouplist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industry.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrylist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytype.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_industrytypelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_list.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_log.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_map.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_marine.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_object.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_order.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_rail.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_railtypelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_road.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_sign.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_station.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_stationlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidy.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_subsidylist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_testmode.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tile.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\api\ai_tilelist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\build.cpp"
RelativePath=".\..\src\ai\api\ai_town.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\default\default.cpp"
RelativePath=".\..\src\ai\api\ai_townlist.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\pathfinder.cpp"
RelativePath=".\..\src\ai\api\ai_tunnel.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\shared.cpp"
RelativePath=".\..\src\ai\api\ai_vehicle.cpp"
>
</File>
<File
RelativePath=".\..\src\ai\trolly\trolly.cpp"
RelativePath=".\..\src\ai\api\ai_vehiclelist.cpp"
>
</File>
</Filter>

@ -60,8 +60,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -165,8 +165,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
@ -266,8 +266,8 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;WITH_ASSERT"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_EXCEPTION_TRACKER;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64;WITH_ASSERT"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -373,8 +373,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\objs\langs"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;"
AdditionalIncludeDirectories="..\objs\langs;..\src\3rdparty\squirrel\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_ZLIB;WITH_PNG;WITH_FREETYPE;WITH_ICU;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR=\&quot;OpenTTD\&quot;;NO_GARBAGE_COLLECTOR;_SQ64"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"

@ -124,7 +124,6 @@ window.cpp
sound/allegro_s.h
video/allegro_v.h
#end
ai/ai.h
aircraft.h
airport.h
airport_movement.h
@ -161,7 +160,6 @@ date_func.h
date_type.h
debug.h
video/dedicated_v.h
ai/default/default.h
depot_base.h
depot_func.h
depot_map.h
@ -316,7 +314,6 @@ train.h
transparency.h
transparency_gui.h
transport_type.h
ai/trolly/trolly.h
tunnelbridge.h
unmovable.h
variables.h
@ -511,13 +508,173 @@ table/unicode.h
table/unmovable_land.h
table/water_land.h
# AI Files
ai/ai.cpp
ai/trolly/build.cpp
ai/default/default.cpp
ai/trolly/pathfinder.cpp
ai/trolly/shared.cpp
ai/trolly/trolly.cpp
# Script
script/squirrel.cpp
script/squirrel.hpp
script/squirrel_class.hpp
script/squirrel_helper.hpp
script/squirrel_helper_type.hpp
script/squirrel_std.cpp
script/squirrel_std.hpp
# Squirrel
3rdparty/squirrel/squirrel/sqapi.cpp
3rdparty/squirrel/squirrel/sqbaselib.cpp
3rdparty/squirrel/squirrel/sqclass.cpp
3rdparty/squirrel/squirrel/sqcompiler.cpp
3rdparty/squirrel/squirrel/sqdebug.cpp
3rdparty/squirrel/squirrel/sqfuncstate.cpp
3rdparty/squirrel/squirrel/sqlexer.cpp
3rdparty/squirrel/squirrel/sqmem.cpp
3rdparty/squirrel/squirrel/sqobject.cpp
3rdparty/squirrel/squirrel/sqstate.cpp
3rdparty/squirrel/sqstdlib/sqstdaux.cpp
3rdparty/squirrel/squirrel/sqtable.cpp
3rdparty/squirrel/squirrel/sqvm.cpp
# Squirrel headers
3rdparty/squirrel/squirrel/sqarray.h
3rdparty/squirrel/squirrel/sqclass.h
3rdparty/squirrel/squirrel/sqclosure.h
3rdparty/squirrel/squirrel/sqcompiler.h
3rdparty/squirrel/squirrel/sqfuncproto.h
3rdparty/squirrel/squirrel/sqfuncstate.h
3rdparty/squirrel/squirrel/sqlexer.h
3rdparty/squirrel/squirrel/sqobject.h
3rdparty/squirrel/squirrel/sqopcodes.h
3rdparty/squirrel/squirrel/sqpcheader.h
3rdparty/squirrel/squirrel/sqstate.h
3rdparty/squirrel/include/sqstdaux.h
3rdparty/squirrel/include/sqstdblob.h
3rdparty/squirrel/sqstdlib/sqstdblobimpl.h
3rdparty/squirrel/include/sqstdio.h
3rdparty/squirrel/include/sqstdmath.h
3rdparty/squirrel/sqstdlib/sqstdstream.h
3rdparty/squirrel/include/sqstdstring.h
3rdparty/squirrel/include/sqstdsystem.h
3rdparty/squirrel/squirrel/sqstring.h
3rdparty/squirrel/squirrel/sqtable.h
3rdparty/squirrel/include/squirrel.h
3rdparty/squirrel/squirrel/squserdata.h
3rdparty/squirrel/squirrel/squtils.h
3rdparty/squirrel/squirrel/sqvm.h
# AI Core
ai/ai.hpp
#if HAVE_THREAD
ai/ai_config.cpp
ai/ai_config.hpp
ai/ai_core.cpp
ai/ai_gui.cpp
ai/ai_gui.hpp
ai/ai_info.cpp
ai/ai_info.hpp
ai/ai_info_dummy.cpp
ai/ai_instance.cpp
ai/ai_instance.hpp
ai/ai_scanner.cpp
ai/ai_scanner.hpp
ai/ai_storage.hpp
# AI API
ai/api/ai_abstractlist.hpp
ai/api/ai_accounting.hpp
ai/api/ai_airport.hpp
ai/api/ai_base.hpp
ai/api/ai_bridge.hpp
ai/api/ai_bridgelist.hpp
ai/api/ai_cargo.hpp
ai/api/ai_cargolist.hpp
ai/api/ai_company.hpp
ai/api/ai_controller.hpp
ai/api/ai_date.hpp
ai/api/ai_depotlist.hpp
ai/api/ai_engine.hpp
ai/api/ai_enginelist.hpp
ai/api/ai_error.hpp
ai/api/ai_event.hpp
ai/api/ai_event_types.hpp
ai/api/ai_execmode.hpp
ai/api/ai_gamesettings.hpp
ai/api/ai_group.hpp
ai/api/ai_grouplist.hpp
ai/api/ai_industry.hpp
ai/api/ai_industrylist.hpp
ai/api/ai_industrytype.hpp
ai/api/ai_industrytypelist.hpp
ai/api/ai_list.hpp
ai/api/ai_log.hpp
ai/api/ai_map.hpp
ai/api/ai_marine.hpp
ai/api/ai_object.hpp
ai/api/ai_order.hpp
ai/api/ai_rail.hpp
ai/api/ai_railtypelist.hpp
ai/api/ai_road.hpp
ai/api/ai_sign.hpp
ai/api/ai_station.hpp
ai/api/ai_stationlist.hpp
ai/api/ai_subsidy.hpp
ai/api/ai_subsidylist.hpp
ai/api/ai_testmode.hpp
ai/api/ai_tile.hpp
ai/api/ai_tilelist.hpp
ai/api/ai_town.hpp
ai/api/ai_townlist.hpp
ai/api/ai_tunnel.hpp
ai/api/ai_types.hpp
ai/api/ai_vehicle.hpp
ai/api/ai_vehiclelist.hpp
# AI API Implementation
ai/api/ai_abstractlist.cpp
ai/api/ai_accounting.cpp
ai/api/ai_airport.cpp
ai/api/ai_base.cpp
ai/api/ai_bridge.cpp
ai/api/ai_bridgelist.cpp
ai/api/ai_cargo.cpp
ai/api/ai_cargolist.cpp
ai/api/ai_company.cpp
ai/api/ai_controller.cpp
ai/api/ai_date.cpp
ai/api/ai_depotlist.cpp
ai/api/ai_engine.cpp
ai/api/ai_enginelist.cpp
ai/api/ai_error.cpp
ai/api/ai_event.cpp
ai/api/ai_event_types.cpp
ai/api/ai_execmode.cpp
ai/api/ai_gamesettings.cpp
ai/api/ai_group.cpp
ai/api/ai_grouplist.cpp
ai/api/ai_industry.cpp
ai/api/ai_industrylist.cpp
ai/api/ai_industrytype.cpp
ai/api/ai_industrytypelist.cpp
ai/api/ai_list.cpp
ai/api/ai_log.cpp
ai/api/ai_map.cpp
ai/api/ai_marine.cpp
ai/api/ai_object.cpp
ai/api/ai_order.cpp
ai/api/ai_rail.cpp
ai/api/ai_railtypelist.cpp
ai/api/ai_road.cpp
ai/api/ai_sign.cpp
ai/api/ai_station.cpp
ai/api/ai_stationlist.cpp
ai/api/ai_subsidy.cpp
ai/api/ai_subsidylist.cpp
ai/api/ai_testmode.cpp
ai/api/ai_tile.cpp
ai/api/ai_tilelist.cpp
ai/api/ai_town.cpp
ai/api/ai_townlist.cpp
ai/api/ai_tunnel.cpp
ai/api/ai_vehicle.cpp
ai/api/ai_vehiclelist.cpp
#end
# Blitters
#if DEDICATED

@ -1,244 +0,0 @@
/* $Id$ */
/** @file ai.cpp Base for all AIs. */
#include "../stdafx.h"
#include "../openttd.h"
#include "../variables.h"
#include "../command_func.h"
#include "../network/network.h"
#include "../core/alloc_func.hpp"
#include "../company_func.h"
#include "../company_base.h"
#include "ai.h"
#include "default/default.h"
#include "trolly/trolly.h"
#include "../signal_func.h"
AIStruct _ai;
AICompany _ai_company[MAX_COMPANIES];
/**
* Dequeues commands put in the queue via AI_PutCommandInQueue.
*/
static void AI_DequeueCommands(CompanyID company)
{
AICommand *com, *entry_com;
entry_com = _ai_company[company].queue;
/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
* to this very same queue (don't argue about this, if it currently doesn't
* happen I can tell you it will happen with AIScript -- TrueLight). If we
* do not make the queue NULL, that commands will be dequeued immediatly.
* Therefor we safe the entry-point to entry_com, and make the queue NULL, so
* the new queue can be safely built up. */
_ai_company[company].queue = NULL;
_ai_company[company].queue_tail = NULL;
/* Dequeue all commands */
while ((com = entry_com) != NULL) {
_current_company = company;
DoCommandP(com->tile, com->p1, com->p2, com->cmd, com->callback, com->text);
/* Free item */
entry_com = com->next;
free(com->text);
free(com);
}
}
/**
* Needed for SP; we need to delay DoCommand with 1 tick, because else events
* will make infinite loops (AIScript).
*/
static void AI_PutCommandInQueue(CompanyID company, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text = NULL)
{
AICommand *com;
if (_ai_company[company].queue_tail == NULL) {
/* There is no item in the queue yet, create the queue */
_ai_company[company].queue = MallocT<AICommand>(1);
_ai_company[company].queue_tail = _ai_company[company].queue;
} else {
/* Add an item at the end */
_ai_company[company].queue_tail->next = MallocT<AICommand>(1);
_ai_company[company].queue_tail = _ai_company[company].queue_tail->next;
}
/* This is our new item */
com = _ai_company[company].queue_tail;
/* Assign the info */
com->tile = tile;
com->p1 = p1;
com->p2 = p2;
com->cmd = cmd;
com->callback = callback;
com->next = NULL;
com->text = text == NULL ? NULL : strdup(text);
}
/**
* Executes a raw DoCommand for the AI.
*/
CommandCost AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint32 cmd, CommandCallback *callback, const char *text)
{
CompanyID old_local_company;
CommandCost res;
/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
* person.. should we check for those funny jokes?
*/
/* First, do a test-run to see if we can do this */
res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, cmd, text);
/* The command failed, or you didn't want to execute, or you are quering, return */
if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
return res;
}
/* NetworkSend_Command needs _local_company to be set correctly, so
* adjust it, and put it back right after the function */
old_local_company = _local_company;
_local_company = _current_company;
#ifdef ENABLE_NETWORK
/* Send the command */
if (_networking) {
/* Network is easy, send it to his handler */
NetworkSend_Command(tile, p1, p2, cmd, callback, text);
} else {
#else
{
#endif
/* If we execute BuildCommands directly in SP, we have a big problem with events
* so we need to delay is for 1 tick */
AI_PutCommandInQueue(_current_company, tile, p1, p2, cmd, callback, text);
}
/* Set _local_company back */
_local_company = old_local_company;
return res;
}
CommandCost AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint32 cmd, const char *text)
{
return AI_DoCommandCc(tile, p1, p2, flags, cmd, NULL, text);
}
/**
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
*/
static void AI_RunTick(CompanyID company)
{
extern void AiNewDoGameLoop(Company *c);
Company *c = GetCompany(company);
_current_company = company;
if (_settings_game.ai.ainew_active) {
AiNewDoGameLoop(c);
} else {
/* Enable all kind of cheats the old AI needs in order to operate correctly... */
_is_old_ai_company = true;
AiDoGameLoop(c);
_is_old_ai_company = false;
}
/* AI could change some track, so update signals */
UpdateSignalsInBuffer();
}
/**
* The gameloop for AIs.
* Handles one tick for all the AIs.
*/
void AI_RunGameLoop()
{
/* Don't do anything if ai is disabled */
if (!_ai.enabled) return;
/* Don't do anything if we are a network-client, or the AI has been disabled */
if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return;
/* New tick */
_ai.tick++;
/* Make sure the AI follows the difficulty rule.. */
assert(_settings_game.difficulty.competitor_speed <= 4);
if ((_ai.tick & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
/* Check for AI-client (so joining a network with an AI) */
if (!_networking || _network_server) {
/* Check if we want to run AIs (server or SP only) */
const Company *c;
FOR_ALL_COMPANIES(c) {
if (c->is_ai) {
/* This should always be true, else something went wrong... */
assert(_ai_company[c->index].active);
/* Run the script */
AI_DequeueCommands(c->index);
AI_RunTick(c->index);
}
}
}
_current_company = OWNER_NONE;
}
/**
* A new AI sees the day of light. You can do here what ever you think is needed.
*/
void AI_StartNewAI(CompanyID company)
{
assert(IsValidCompanyID(company));
/* Called if a new AI is booted */
_ai_company[company].active = true;
}
/**
* This AI company died. Give it some chance to make a final puf.
*/
void AI_CompanyDied(CompanyID company)
{
/* Called if this AI died */
_ai_company[company].active = false;
if (_companies_ainew[company].pathfinder == NULL) return;
AyStarMain_Free(_companies_ainew[company].pathfinder);
delete _companies_ainew[company].pathfinder;
_companies_ainew[company].pathfinder = NULL;
}
/**
* Initialize some AI-related stuff.
*/
void AI_Initialize()
{
/* First, make sure all AIs are DEAD! */
AI_Uninitialize();
memset(&_ai, 0, sizeof(_ai));
memset(&_ai_company, 0, sizeof(_ai_company));
_ai.enabled = true;
}
/**
* Deinitializer for AI-related stuff.
*/
void AI_Uninitialize()
{
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) AI_CompanyDied(c);
}

@ -1,115 +0,0 @@
/* $Id$ */
/** @file ai.h Base functions for all AIs. */
#ifndef AI_H
#define AI_H
#include "../network/network.h"
#include "../command_type.h"
#include "../core/random_func.hpp"
#include "../settings_type.h"
/* How DoCommands look like for an AI */
struct AICommand {
uint32 tile;
uint32 p1;
uint32 p2;
uint32 cmd;
CommandCallback *callback;
char *text;
uint uid;
AICommand *next;
};
/* The struct for an AIScript Company */
struct AICompany {
bool active; ///< Is this AI active?
AICommand *queue; ///< The commands that he has in his queue
AICommand *queue_tail; ///< The tail of this queue
};
/* The struct to keep some data about the AI in general */
struct AIStruct {
/* General */
bool enabled; ///< Is AI enabled?
uint tick; ///< The current tick (something like _frame_counter, only for AIs)
};
extern AIStruct _ai;
extern AICompany _ai_company[MAX_COMPANIES];
// ai.c
void AI_StartNewAI(CompanyID company);
void AI_CompanyDied(CompanyID company);
void AI_RunGameLoop();
void AI_Initialize();
void AI_Uninitialize();
CommandCost AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, const char *text = NULL);
CommandCost AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback *callback, const char *text = NULL);
/** Is it allowed to start a new AI.
* This function checks some boundries to see if we should launch a new AI.
* @return True if we can start a new AI.
*/
static inline bool AI_AllowNewAI()
{
/* If disabled, no AI */
if (!_ai.enabled)
return false;
/* If in network, but no server, no AI */
if (_networking && !_network_server)
return false;
/* If in network, and server, possible AI */
if (_networking && _network_server) {
/* Do we want AIs in multiplayer? */
if (!_settings_game.ai.ai_in_multiplayer)
return false;
/* Only the NewAI is allowed... sadly enough the old AI just doesn't support this
* system, because all commands are delayed by at least 1 tick, which causes
* a big problem, because it uses variables that are only set AFTER the command
* is really executed... */
if (!_settings_game.ai.ainew_active)
return false;
}
return true;
}
#define AI_CHANCE16(a, b) ((uint16) AI_Random() <= (uint16)((65536 * a) / b))
#define AI_CHANCE16R(a, b, r) ((uint16)(r = AI_Random()) <= (uint16)((65536 * a) / b))
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint AI_RandomRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandomRange(max);
else
return RandomRange(max);
}
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint32 AI_Random()
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandom();
else
return Random();
}
#endif /* AI_H */

@ -0,0 +1,102 @@
/* $Id$ */
/** @file ai.hpp Base functions for all AIs. */
#ifndef AI_HPP
#define AI_HPP
#include "api/ai_event_types.hpp"
#ifndef AI_CONFIG_HPP
struct ltstr { bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; } };
#endif /* AI_CONFIG_HPP */
typedef std::map<const char *, class AIInfo *, ltstr> AIInfoList;
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2);
class AI {
public:
/**
* Is it possible to start a new AI company?
* @return True if a new AI company can be started.
*/
static bool CanStartNew();
/**
* Start a new AI company.
* @param company At which slot the AI company should start.
*/
static void StartNew(CompanyID company);
/**
* Called every game-tick to let AIs do something.
*/
static void GameLoop();
/**
* Get the current AI tick.
*/
static uint GetTick();
/**
* Stop a company to be controlled by an AI.
* @param company The company from which the AI needs to detach.
* @pre !IsHumanCompany(company).
*/
static void Stop(CompanyID company);
/**
* Kill any and all AIs we manage.
*/
static void KillAll();
/**
* Initialize the AI system.
*/
static void Initialize();
/**
* Uninitialize the AI system
* @param keepConfig Should we keep AIConfigs, or can we free that memory?
*/
static void Uninitialize(bool keepConfig);
/**
* Reset all AIConfigs, and make them reload their AIInfo.
* If the AIInfo could no longer be found, an error is reported to the user.
*/
static void ResetConfig();
/**
* Queue a new event for an AI.
*/
static void NewEvent(CompanyID company, AIEvent *event);
/**
* Broadcast a new event to all active AIs.
*/
static void BroadcastNewEvent(AIEvent *event, CompanyID skip_company = MAX_COMPANIES);
/**
* Save data from an AI to a savegame.
*/
static void Save(CompanyID company);
/**
* Load data for an AI from a savegame.
*/
static void Load(CompanyID company);
static char *GetConsoleList(char *p, const char *last);
static const AIInfoList *GetInfoList();
static AIInfo *GetCompanyInfo(const char *name);
static bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
static void Rescan();
private:
static uint frame_counter;
static class AIScanner *ai_scanner;
};
#endif /* AI_HPP */

@ -0,0 +1,143 @@
/* $Id$ */
/** @file ai_config.cpp Implementation of AIConfig. */
#include "../stdafx.h"
#include "../openttd.h"
#include "../settings_type.h"
#include "ai.hpp"
#include "ai_config.hpp"
#include "ai_info.hpp"
void AIConfig::ChangeAI(const char *name)
{
free((void *)this->name);
this->name = (name == NULL) ? NULL : strdup(name);
this->info = (name == NULL) ? NULL : AI::GetCompanyInfo(this->name);
for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
free((void*)(*it).first);
}
this->settings.clear();
}
AIConfig::AIConfig(const AIConfig *config) :
name(NULL),
info(NULL)
{
this->name = (config->name == NULL) ? NULL : strdup(config->name);
this->info = config->info;
for (SettingValueList::const_iterator it = config->settings.begin(); it != config->settings.end(); it++) {
this->settings[strdup((*it).first)] = (*it).second;
}
}
AIConfig::~AIConfig()
{
this->ChangeAI(NULL);
}
AIInfo *AIConfig::GetInfo()
{
return this->info;
}
bool AIConfig::ResetInfo()
{
this->info = AI::GetCompanyInfo(this->name);
return this->info != NULL;
}
AIConfig *AIConfig::GetConfig(CompanyID company, bool forceNewgameSetting)
{
AIConfig **config;
if (!forceNewgameSetting) {
config = (_game_mode == GM_MENU) ? &_settings_newgame.ai_config[company] : &_settings_game.ai_config[company];
} else {
config = &_settings_newgame.ai_config[company];
}
if (*config == NULL) *config = new AIConfig();
return *config;
}
int AIConfig::GetSetting(const char *name)
{
assert(this->info != NULL);
SettingValueList::iterator it = this->settings.find(name);
/* Return the default value if the setting is not set, or if we are in a not-custom difficult level */
if (it == this->settings.end() || ((_game_mode == GM_MENU) ? _settings_newgame.difficulty.diff_level : _settings_game.difficulty.diff_level) != 3) {
return this->info->GetSettingDefaultValue(name);
}
return (*it).second;
}
void AIConfig::SetSetting(const char *name, int value)
{
/* You can only set ai specific settings if an AI is selected. */
assert(strcmp(name, "start_date") == 0 || this->info != NULL);
SettingValueList::iterator it = this->settings.find(name);
if (it != this->settings.end()) {
(*it).second = value;
} else {
this->settings[strdup(name)] = value;
}
}
bool AIConfig::HasAI()
{
return this->info != NULL;
}
const char *AIConfig::GetName()
{
return this->name;
}
void AIConfig::StringToSettings(const char *value)
{
char *value_copy = strdup(value);
char *s = value_copy;
while (s != NULL) {
/* Analyze the string ('name=value,name=value\0') */
char *item_name = s;
s = strchr(s, '=');
if (s == NULL) break;
if (*s == '\0') break;
*s = '\0';
s++;
char *item_value = s;
s = strchr(s, ',');
if (s != NULL) {
*s = '\0';
s++;
}
this->SetSetting(item_name, atoi(item_value));
}
free(value_copy);
}
void AIConfig::SettingsToString(char *string, int size)
{
string[0] = '\0';
for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
char no[10];
snprintf(no, sizeof(no), "%d", (*it).second);
/* Check if the string would fit in the destination */
size -= strlen((*it).first) - 1 - strlen(no) - 1;
/* If it doesn't fit, skip the next settings */
if (size <= 0) return;
strcat(string, (*it).first);
strcat(string, "=");
strcat(string, no);
strcat(string, ",");
}
string[strlen(string) - 1] = '\0';
}

@ -0,0 +1,91 @@
/* $Id$ */
/** @file ai_config.hpp AIConfig stores the configuration settings of every AI. */
#ifndef AI_CONFIG_HPP
#define AI_CONFIG_HPP
#include <map>
#ifndef AI_HPP
struct ltstr { bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; } };
#endif /* AI_HPP */
class AIConfig {
private:
typedef std::map<const char *, int, ltstr> SettingValueList;
public:
AIConfig() :
name(NULL),
info(NULL)
{}
AIConfig(const AIConfig *config);
~AIConfig();
/**
* Set another AI to be loaded in this slot.
*/
void ChangeAI(const char *name);
/**
* When ever the AI Scanner is reloaded, all infos become invalid. This
* function tells AIConfig about this.
* @return True if the reset was successfull, false if the AI was no longer
* found.
*/
bool ResetInfo();
/**
* Get the AIInfo linked to this AIConfig.
*/
class AIInfo *GetInfo();
/**
* Get the config of a company.
*/
static AIConfig *GetConfig(CompanyID company, bool forceNewgameSetting = false);
/**
* Get the value of a setting for this config. It might fallback to his
* 'info' to find the default value (if not set or if not-custom difficulty
* level).
* @return The (default) value of the setting, or -1 if the setting was not
* found.
*/
int GetSetting(const char *name);
/**
* Set the value of a setting for this config.
*/
void SetSetting(const char *name, int value);
/**
* Is this config attached to an AI?
*/
bool HasAI();
/**
* Get the name of the AI.
*/
const char *GetName();
/**
* Convert a string which is stored in the config file or savegames to
* custom settings of this AI.
*/
void StringToSettings(const char *value);
/**
* Convert the custom settings to a string that can be stored in the config
* file or savegames.
*/
void SettingsToString(char *string, int size);
private:
const char *name;
class AIInfo *info;
SettingValueList settings;
};
#endif /* AI_CONFIG_HPP */

@ -0,0 +1,254 @@
/* $Id$ */
/** @file ai_core.cpp Implementation of AI. */
#include "../stdafx.h"
#include "../openttd.h"
#include "../company_type.h"
#include "../company_base.h"
#include "../company_func.h"
#include "../debug.h"
#include "../network/network.h"
#include "../settings_type.h"
#include "../window_type.h"
#include "../window_func.h"
#include "../command_func.h"
#include "ai.hpp"
#include "ai_info.hpp"
#include "ai_scanner.hpp"
#include "ai_instance.hpp"
#include "ai_config.hpp"
/* static */ uint AI::frame_counter = 0;
/* static */ AIScanner *AI::ai_scanner = NULL;
/* static */ bool AI::CanStartNew()
{
/* Only allow new AIs on the server and only when that is allowed in multiplayer */
return !_networking || (_network_server && _settings_game.ai.ai_in_multiplayer);
}
/* static */ void AI::StartNew(CompanyID company)
{
assert(IsValidCompanyID(company));
/* Clients shouldn't start AIs */
if (_networking && !_network_server) return;
AIInfo *info = AIConfig::GetConfig(company)->GetInfo();
if (info == NULL) {
info = AI::ai_scanner->SelectRandomAI();
assert(info != NULL);
/* Load default data and store the name in the settings */
AIConfig::GetConfig(company)->ChangeAI(info->GetDirName());
}
_current_company = company;
Company *c = GetCompany(company);
c->ai_info = info;
c->ai_instance = new AIInstance(info);
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
return;
}
/* static */ void AI::GameLoop()
{
/* If we are in networking, only servers run this function, and that only if it is allowed */
if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return;
/* The speed with which AIs go, is limited by the 'competitor_speed' */
AI::frame_counter++;
assert(_settings_game.difficulty.competitor_speed <= 4);
if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
const Company *c;
FOR_ALL_COMPANIES(c) {
if (!IsHumanCompany(c->index)) {
_current_company = c->index;
c->ai_instance->GameLoop();
}
}
_current_company = OWNER_NONE;
}
/* static */ uint AI::GetTick()
{
return AI::frame_counter;
}
/* static */ void AI::Stop(CompanyID company)
{
if (_networking && !_network_server) return;
_current_company = company;
Company *c = GetCompany(company);
delete c->ai_instance;
c->ai_instance = NULL;
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
}
/* static */ void AI::KillAll()
{
/* It might happen there are no companies .. than we have nothing to loop */
if (GetCompanyPoolSize() == 0) return;
const Company *c;
FOR_ALL_COMPANIES(c) {
if (!IsHumanCompany(c->index)) AI::Stop(c->index);
}
}
/* static */ void AI::Initialize()
{
if (AI::ai_scanner != NULL) AI::Uninitialize(true);
AI::frame_counter = 0;
if (AI::ai_scanner == NULL) AI::ai_scanner = new AIScanner();
}
/* static */ void AI::Uninitialize(bool keepConfig)
{
AI::KillAll();
if (keepConfig) {
/* Run a rescan, which indexes all AIInfos again, and check if we can
* still load all the AIS, while keeping the configs in place */
Rescan();
} else {
delete AI::ai_scanner;
AI::ai_scanner = NULL;
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (_settings_game.ai_config[c] != NULL) {
delete _settings_game.ai_config[c];
_settings_game.ai_config[c] = NULL;
}
if (_settings_newgame.ai_config[c] != NULL) {
delete _settings_newgame.ai_config[c];
_settings_newgame.ai_config[c] = NULL;
}
}
}
}
/* static */ void AI::ResetConfig()
{
/* Check for both newgame as current game if we can reload the AIInfo insde
* the AIConfig. If not, remove the AI from the list (which will assign
* a random new AI on reload). */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasAI()) {
if (!_settings_game.ai_config[c]->ResetInfo()) {
DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName());
_settings_game.ai_config[c]->ChangeAI(NULL);
}
}
if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasAI()) {
if (!_settings_newgame.ai_config[c]->ResetInfo()) {
DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName());
_settings_newgame.ai_config[c]->ChangeAI(NULL);
}
}
}
}
/* static */ void AI::NewEvent(CompanyID company, AIEvent *event)
{
/* Clients should ignore events */
if (_networking && !_network_server) return;
/* Only AIs can have an event-queue */
if (!IsValidCompanyID(company) || IsHumanCompany(company)) return;
/* Queue the event */
CompanyID old_company = _current_company;
_current_company = company;
AIEventController::InsertEvent(event);
_current_company = old_company;
}
/* static */ void AI::BroadcastNewEvent(AIEvent *event, CompanyID skip_company)
{
/* Clients should ignore events */
if (_networking && !_network_server) return;
/* Try to send the event to all AIs */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (c != skip_company) AI::NewEvent(c, event);
}
}
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
AIObject::SetLastCommandRes(success);
if (!success) {
AIObject::SetLastError(AIError::StringToError(_error_message));
} else {
AIObject::IncreaseDoCommandCosts(AIObject::GetLastCost());
}
GetCompany(_current_company)->ai_instance->Continue();
}
/* static */ void AI::Save(CompanyID company)
{
if (!_networking || _network_server) {
assert(IsValidCompanyID(company));
assert(GetCompany(company)->ai_instance != NULL);
CompanyID old_company = _current_company;
_current_company = company;
GetCompany(company)->ai_instance->Save();
_current_company = old_company;
} else {
AIInstance::SaveEmpty();
}
}
/* static */ void AI::Load(CompanyID company)
{
if (!_networking || _network_server) {
assert(IsValidCompanyID(company));
assert(GetCompany(company)->ai_instance != NULL);
CompanyID old_company = _current_company;
_current_company = company;
GetCompany(company)->ai_instance->Load();
_current_company = old_company;
} else {
/* Read, but ignore, the load data */
AIInstance::LoadEmpty();
}
}
/* static */ char *AI::GetConsoleList(char *p, const char *last)
{
return AI::ai_scanner->GetAIConsoleList(p, last);
}
/* static */ const AIInfoList *AI::GetInfoList()
{
return AI::ai_scanner->GetAIInfoList();
}
/* static */ AIInfo *AI::GetCompanyInfo(const char *name)
{
return AI::ai_scanner->FindAI(name);
}
/* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
{
return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, GetCompany(_current_company)->ai_instance->GetController());
}
/* static */ void AI::Rescan()
{
AI::ai_scanner->RescanAIDir();
ResetConfig();
}

@ -0,0 +1,257 @@
/* $Id$ */
/** @file ai_gui.cpp Window for configuring the AIs */
#include "../stdafx.h"
#include "../openttd.h"
#include "../gui.h"
#include "../window_gui.h"
#include "../company_func.h"
#include "../company_base.h"
#include "../company_gui.h"
#include "../economy_func.h"
#include "../variables.h"
#include "../cargotype.h"
#include "../strings_func.h"
#include "../core/alloc_func.hpp"
#include "../window_func.h"
#include "../date_func.h"
#include "../gfx_func.h"
#include "../debug.h"
#include "../command_func.h"
#include "../network/network.h"
#include "ai.hpp"
#include "api/ai_types.hpp"
#include "api/ai_controller.hpp"
#include "api/ai_object.hpp"
#include "api/ai_log.hpp"
#include "ai_info.hpp"
#include "table/strings.h"
#include "../table/sprites.h"
struct AIDebugWindow : public Window {
enum AIDebugWindowWidgets {
AID_WIDGET_CLOSEBOX = 0,
AID_WIDGET_CAPTION,
AID_WIDGET_VIEW,
AID_WIDGET_NAME_TEXT,
AID_WIDGET_RELOAD_TOGGLE,
AID_WIDGET_LOG_PANEL,
AID_WIDGET_SCROLLBAR,
AID_WIDGET_UNUSED_1,
AID_WIDGET_UNUSED_2,
AID_WIDGET_UNUSED_3,
AID_WIDGET_UNUSED_4,
AID_WIDGET_UNUSED_5,
AID_WIDGET_UNUSED_6,
AID_WIDGET_UNUSED_7,
AID_WIDGET_COMPANY_BUTTON_START,
AID_WIDGET_COMPANY_BUTTON_END = AID_WIDGET_COMPANY_BUTTON_START + 14,
};
static CompanyID ai_debug_company;
int redraw_timer;
AIDebugWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
{
/* Disable the companies who are not active or not an AI */
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
this->SetWidgetDisabledState(i + AID_WIDGET_COMPANY_BUTTON_START, !IsValidCompanyID(i) || !GetCompany(i)->is_ai);
}
this->DisableWidget(AID_WIDGET_RELOAD_TOGGLE);
this->vscroll.cap = 14;
this->vscroll.pos = 0;
this->resize.step_height = 12;
if (ai_debug_company != INVALID_COMPANY) this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
this->FindWindowPlacementAndResize(desc);
}
virtual void OnPaint()
{
/* Check if the currently selected company is still active. */
if (ai_debug_company == INVALID_COMPANY || !IsValidCompanyID(ai_debug_company)) {
if (ai_debug_company != INVALID_COMPANY) {
/* Raise and disable the widget for the previous selection. */
this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
this->DisableWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
ai_debug_company = INVALID_COMPANY;
}
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
if (IsValidCompanyID(i) && GetCompany(i)->is_ai) {
/* Lower the widget corresponding to this company. */
this->LowerWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
ai_debug_company = i;
break;
}
}
}
/* Update "Reload AI" button */
this->SetWidgetDisabledState(AID_WIDGET_RELOAD_TOGGLE, ai_debug_company == INVALID_COMPANY);
/* Draw standard stuff */
this->DrawWidgets();
/* If there are no active companies, don't display anything else. */
if (ai_debug_company == INVALID_COMPANY) return;
/* Paint the company icons */
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
if (!IsValidCompanyID(i) || !GetCompany(i)->is_ai) {
/* Check if we have the company as an active company */
if (!this->IsWidgetDisabled(i + AID_WIDGET_COMPANY_BUTTON_START)) {
/* Bah, company gone :( */
this->DisableWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
/* We need a repaint */
this->SetDirty();
}
continue;
}
/* Check if we have the company marked as inactive */
if (this->IsWidgetDisabled(i + AID_WIDGET_COMPANY_BUTTON_START)) {
/* New AI! Yippie :p */
this->EnableWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
/* We need a repaint */
this->SetDirty();
}
byte x = (i == ai_debug_company) ? 1 : 0;
DrawCompanyIcon(i, (i % 8) * 37 + 13 + x, (i < 8 ? 0 : 13) + 16 + x);
}
/* Draw the AI name */
AIInfo *info = GetCompany(ai_debug_company)->ai_info;
assert(info != NULL);
DoDrawString(info->GetName(), 7, 47, TC_BLACK);
CompanyID old_company = _current_company;
_current_company = ai_debug_company;
AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
_current_company = old_company;
SetVScrollCount(this, (log == NULL) ? 0 : log->used);
this->InvalidateWidget(AID_WIDGET_SCROLLBAR);
if (log == NULL) return;
int y = 6;
for (int i = this->vscroll.pos; i < (this->vscroll.cap + this->vscroll.pos); i++) {
uint pos = (log->count + log->pos - i) % log->count;
if (log->lines[pos] == NULL) break;
uint colour;
switch (log->type[pos]) {
case AILog::LOG_SQ_INFO: colour = TC_BLACK; break;
case AILog::LOG_SQ_ERROR: colour = TC_RED; break;
case AILog::LOG_INFO: colour = TC_BLACK; break;
case AILog::LOG_WARNING: colour = TC_YELLOW; break;
case AILog::LOG_ERROR: colour = TC_RED; break;
default: colour = TC_BLACK; break;
}
DoDrawStringTruncated(log->lines[pos], 7, this->widget[AID_WIDGET_LOG_PANEL].top + y, colour, this->widget[AID_WIDGET_LOG_PANEL].right - this->widget[AID_WIDGET_LOG_PANEL].left - 14);
y += 12;
}
}
virtual void OnClick(Point pt, int widget)
{
/* Check which button is clicked */
if (IsInsideMM(widget, AID_WIDGET_COMPANY_BUTTON_START, AID_WIDGET_COMPANY_BUTTON_END + 1)) {
/* Is it no on disable? */
if (!this->IsWidgetDisabled(widget)) {
this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
ai_debug_company = (CompanyID)(widget - AID_WIDGET_COMPANY_BUTTON_START);
this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
this->SetDirty();
}
}
if (widget == AID_WIDGET_RELOAD_TOGGLE && !this->IsWidgetDisabled(widget)) {
/* First kill the company of the AI, then start a new one. This should start the current AI again */
DoCommandP(0, 2, ai_debug_company, CMD_COMPANY_CTRL);
DoCommandP(0, 1, 0, CMD_COMPANY_CTRL);
}
}
virtual void OnTimeout()
{
this->RaiseWidget(AID_WIDGET_RELOAD_TOGGLE);
this->SetDirty();
}
virtual void OnInvalidateData(int data = 0)
{
if (data == -1 || ai_debug_company == data) this->SetDirty();
}
virtual void OnResize(Point new_size, Point delta)
{
this->vscroll.cap += delta.y / (int)this->resize.step_height;
}
};
CompanyID AIDebugWindow::ai_debug_company = INVALID_COMPANY;
static const Widget _ai_debug_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // AID_WIDGET_CLOSEBOX
{ WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 298, 0, 13, STR_AI_DEBUG, STR_018C_WINDOW_TITLE_DRAG_THIS}, // AID_WIDGET_CAPTION
{ WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 0, 298, 14, 40, 0x0, STR_NULL}, // AID_WIDGET_VIEW
{ WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 0, 149, 41, 60, 0x0, STR_AI_DEBUG_NAME_TIP}, // AID_WIDGET_NAME_TEXT
{ WWT_PUSHTXTBTN, RESIZE_LR, COLOUR_GREY, 150, 298, 41, 60, STR_AI_DEBUG_RELOAD, STR_AI_DEBUG_RELOAD_TIP}, // AID_WIDGET_RELOAD_TOGGLE
{ WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 286, 61, 240, 0x0, STR_NULL}, // AID_WIDGET_LOG_PANEL
{ WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 287, 298, 61, 228, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // AID_WIDGET_SCROLLBAR
/* As this is WIP, leave the next few so we can work a bit with the GUI */
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 101, 120, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_1
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 121, 140, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_2
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 141, 160, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_3
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 161, 180, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_4
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 181, 200, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_5
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 201, 220, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_6
{ WWT_EMPTY, RESIZE_NONE, COLOUR_GREY, 0, 298, 221, 240, 0x0, STR_NULL}, // AID_WIDGET_UNUSED_7
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 38, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, // AID_WIDGET_COMPANY_BUTTON_START
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 39, 75, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 76, 112, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 113, 149, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 150, 186, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 187, 223, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 224, 260, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 261, 297, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 38, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 39, 75, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 76, 112, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 113, 149, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 150, 186, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 187, 223, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 224, 260, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, // AID_WIDGET_COMPANY_BUTTON_END
{ WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 287, 298, 229, 240, STR_NULL, STR_RESIZE_BUTTON},
{ WIDGETS_END},
};
static const WindowDesc _ai_debug_desc = {
WDP_AUTO, WDP_AUTO, 299, 241, 299, 241,
WC_AI_DEBUG, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
_ai_debug_widgets
};
void ShowAIDebugWindow()
{
if (!_networking || _network_server) {
AllocateWindowDescFront<AIDebugWindow>(&_ai_debug_desc, 0);
} else {
ShowErrorMessage(INVALID_STRING_ID, STR_AI_DEBUG_SERVER_ONLY, 0, 0);
}
}

@ -0,0 +1,10 @@
/* $Id$ */
/** @file ai_gui.hpp Window for configuring the AIs */
#ifndef AI_GUI_HPP
#define AI_GUI_HPP
void ShowAIDebugWindow();
#endif /* AI_GUI_HPP */

@ -0,0 +1,319 @@
/* $Id$ */
/** @file ai_info.cpp Implementation of AIFileInfo */
#include "../stdafx.h"
#include "../core/alloc_func.hpp"
#include <squirrel.h>
#include "../script/squirrel.hpp"
#include "../script/squirrel_helper.hpp"
#include "../script/squirrel_class.hpp"
#include "../script/squirrel_std.hpp"
#include "ai.hpp"
#include "ai_info.hpp"
#include "ai_scanner.hpp"
#include "api/ai_controller.hpp"
#include "../settings_type.h"
#include "../openttd.h"
AIFileInfo::~AIFileInfo()
{
this->engine->ReleaseObject(this->SQ_instance);
free((void *)this->author);
free((void *)this->name);
free((void *)this->description);
free((void *)this->date);
free((void *)this->instance_name);
free(this->script_name);
free(this->dir_name);
free(this->SQ_instance);
}
const char *AIFileInfo::GetAuthor()
{
if (this->author == NULL) this->author = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetAuthor");
return this->author;
}
const char *AIFileInfo::GetName()
{
if (this->name == NULL) this->name = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetName");
return this->name;
}
const char *AIFileInfo::GetDescription()
{
if (this->description == NULL) this->description = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetDescription");
return this->description;
}
int AIFileInfo::GetVersion()
{
return this->engine->CallIntegerMethod(*this->SQ_instance, "GetVersion");
}
void AIFileInfo::GetSettings()
{
this->engine->CallMethod(*this->SQ_instance, "GetSettings", NULL, -1);
}
const char *AIFileInfo::GetDate()
{
if (this->date == NULL) this->date = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetDate");
return this->date;
}
const char *AIFileInfo::GetInstanceName()
{
if (this->instance_name == NULL) this->instance_name = this->engine->CallStringMethodStrdup(*this->SQ_instance, "CreateInstance");
return this->instance_name;
}
bool AIFileInfo::AllowStartup()
{
return true;
}
const char *AIFileInfo::GetDirName()
{
return this->dir_name;
}
const char *AIFileInfo::GetScriptName()
{
return this->script_name;
}
void AIFileInfo::CheckMethods(SQInteger *res, const char *name)
{
if (!this->engine->MethodExists(*this->SQ_instance, name)) {
char error[1024];
snprintf(error, sizeof(error), "your AIFileInfo doesn't have the method '%s'", name);
this->engine->ThrowError(error);
*res = SQ_ERROR;
}
}
/* static */ SQInteger AIFileInfo::Constructor(HSQUIRRELVM vm, AIFileInfo *info)
{
SQInteger res = 0;
/* Set some basic info from the parent */
info->SQ_instance = MallocT<SQObject>(1);
Squirrel::GetInstance(vm, info->SQ_instance, 2);
/* Make sure the instance stays alive over time */
sq_addref(vm, info->SQ_instance);
info->base = ((AIScanner *)Squirrel::GetGlobalPointer(vm));
info->engine = info->base->GetEngine();
/* Check if all needed fields are there */
info->CheckMethods(&res, "GetAuthor");
info->CheckMethods(&res, "GetName");
info->CheckMethods(&res, "GetDescription");
info->CheckMethods(&res, "GetVersion");
info->CheckMethods(&res, "GetDate");
info->CheckMethods(&res, "CreateInstance");
/* Abort if one method was missing */
if (res != 0) return res;
info->script_name = strdup(info->base->GetCurrentScript());
info->dir_name = strdup(info->base->GetCurrentDirName());
return 0;
}
/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
{
/* Get the AIInfo */
SQUserPointer instance;
sq_getinstanceup(vm, 2, &instance, 0);
AIInfo *info = (AIInfo *)instance;
SQInteger res = AIFileInfo::Constructor(vm, info);
if (res != 0) return res;
AIConfigItem config;
config.name = strdup("start_date");
config.description = strdup("The amount of months after the start of the last AI, this AI will start (give or take).");
config.min_value = 0;
config.max_value = 120;
config.easy_value = 48;
config.medium_value = 24;
config.hard_value = 12;
config.custom_value = 24;
config.flags = AICONFIG_NONE;
info->config_list.push_back(config);
/* Check if we have settings */
if (info->engine->MethodExists(*info->SQ_instance, "GetSettings")) {
info->GetSettings();
}
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup(vm, 2, NULL);
/* Register the AI to the base system */
info->base->RegisterAI(info);
return 0;
}
/* static */ SQInteger AIInfo::DummyConstructor(HSQUIRRELVM vm)
{
/* Get the AIInfo */
SQUserPointer instance;
sq_getinstanceup(vm, 2, &instance, 0);
AIInfo *info = (AIInfo *)instance;
SQInteger res = AIFileInfo::Constructor(vm, info);
if (res != 0) return res;
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup(vm, 2, NULL);
/* Register the AI to the base system */
info->base->SetDummyAI(info);
return 0;
}
AIInfo::~AIInfo()
{
/* Free all allocated strings */
for (AIConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) {
free((char *)(*it).name);
}
this->config_list.clear();
}
SQInteger AIInfo::AddSetting(HSQUIRRELVM vm)
{
AIConfigItem config;
memset(&config, 0, sizeof(config));
int items = 0;
/* Read the table, and find all properties we care about */
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
const SQChar *sqkey;
sq_getstring(vm, -2, &sqkey);
const char *key = FS2OTTD(sqkey);
if (strcmp(key, "name") == 0) {
const SQChar *sqvalue;
sq_getstring(vm, -1, &sqvalue);
config.name = strdup(FS2OTTD(sqvalue));
char *s;
/* Don't allow '=' and ',' in configure setting names, as we need those
* 2 chars to nicely store the settings as a string. */
while ((s = (char *)strchr(config.name, '=')) != NULL) *s = '_';
while ((s = (char *)strchr(config.name, ',')) != NULL) *s = '_';
items |= 0x001;
} else if (strcmp(key, "description") == 0) {
const SQChar *sqdescription;
sq_getstring(vm, -1, &sqdescription);
config.description = strdup(FS2OTTD(sqdescription));
items |= 0x002;
} else if (strcmp(key, "min_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.min_value = res;
items |= 0x004;
} else if (strcmp(key, "max_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.max_value = res;
items |= 0x008;
} else if (strcmp(key, "easy_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.easy_value = res;
items |= 0x010;
} else if (strcmp(key, "medium_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.medium_value = res;
items |= 0x020;
} else if (strcmp(key, "hard_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.hard_value = res;
items |= 0x040;
} else if (strcmp(key, "custom_value") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.custom_value = res;
items |= 0x080;
} else if (strcmp(key, "flags") == 0) {
SQInteger res;
sq_getinteger(vm, -1, &res);
config.flags = (AIConfigFlags)res;
items |= 0x100;
} else {
char error[1024];
snprintf(error, sizeof(error), "unknown setting property '%s'", key);
this->engine->ThrowError(error);
return SQ_ERROR;
}
sq_pop(vm, 2);
}
sq_pop(vm, 1);
/* Make sure all properties are defined */
if (items != 0x1FF) {
char error[1024];
snprintf(error, sizeof(error), "please define all properties of a setting");
this->engine->ThrowError(error);
return SQ_ERROR;
}
this->config_list.push_back(config);
return 0;
}
const AIConfigItemList *AIInfo::GetConfigList()
{
return &this->config_list;
}
int AIInfo::GetSettingDefaultValue(const char *name)
{
for (AIConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) {
if (strcmp((*it).name, name) != 0) continue;
/* The default value depends on the difficulty level */
switch ((_game_mode == GM_MENU) ? _settings_newgame.difficulty.diff_level : _settings_game.difficulty.diff_level) {
case 0: return (*it).easy_value;
case 1: return (*it).medium_value;
case 2: return (*it).hard_value;
case 3: return (*it).custom_value;
default: NOT_REACHED();
}
}
/* There is no such setting */
return -1;
}
/* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm)
{
/* Create a new AIFileInfo */
AILibrary *library = new AILibrary();
SQInteger res = AIFileInfo::Constructor(vm, library);
if (res != 0) return res;
/* Register the Library to the base system */
library->base->RegisterLibrary(library);
return 0;
}
/* static */ SQInteger AILibrary::Import(HSQUIRRELVM vm)
{
SQConvert::SQAutoFreePointers ptr;
const char *library = GetParam(SQConvert::ForceType<const char *>(), vm, 2, &ptr);
const char *class_name = GetParam(SQConvert::ForceType<const char *>(), vm, 3, &ptr);
int version = GetParam(SQConvert::ForceType<int>(), vm, 4, &ptr);
if (!AI::ImportLibrary(library, class_name, version, vm)) return -1;
return 1;
}

@ -0,0 +1,153 @@
/* $Id$ */
/** @file ai_info.hpp AIInfo keeps track of all information of an AI, like Author, Description, ... */
#ifndef AI_INFO
#define AI_INFO
#include <list>
#include "api/ai_object.hpp"
enum AIConfigFlags {
AICONFIG_NONE = 0x0,
AICONFIG_RANDOM = 0x1, //!< When randomizing the AI, pick any value between min_value and max_value when on custom difficulty setting.
AICONFIG_BOOLEAN = 0x2, //!< This value is a boolean (either 0 (false) or 1 (true) ).
};
struct AIConfigItem {
const char *name; //!< The name of the configuration setting.
const char *description; //!< The description of the configuration setting.
int min_value; //!< The minimal value this configuration setting can have.
int max_value; //!< The maximal value this configuration setting can have.
int custom_value; //!< The default value on custom difficulty setting.
int easy_value; //!< The default value on easy difficulty setting.
int medium_value; //!< The default value on medium difficulty setting.
int hard_value; //!< The default value on hard difficulty setting.
AIConfigFlags flags; //!< Flags for the configuration setting.
};
typedef std::list<AIConfigItem> AIConfigItemList;
class AIFileInfo : public AIObject {
public:
friend class AIInfo;
friend class AILibrary;
AIFileInfo() : author(NULL), name(NULL), description(NULL), date(NULL), instance_name(NULL) {};
~AIFileInfo();
/**
* Get the Author of the AI.
*/
const char *GetAuthor();
/**
* Get the Name of the AI.
*/
const char *GetName();
/**
* Get the description of the AI.
*/
const char *GetDescription();
/**
* Get the version of the AI.
*/
int GetVersion();
/**
* Get the settings of the AI.
*/
void GetSettings();
/**
* Get the date of the AI.
*/
const char *GetDate();
/**
* Get the name of the instance of the AI to create.
*/
const char *GetInstanceName();
/**
* Check if we can start this AI.
*/
bool AllowStartup();
/**
* Get the name of the dir this AI is in.
*/
const char *GetDirName();
/**
* Get the complete script name of this AI.
*/
const char *GetScriptName();
/**
* Check if a given method exists.
*/
void CheckMethods(SQInteger *res, const char *name);
/**
* Process the creation of a FileInfo object.
*/
static SQInteger Constructor(HSQUIRRELVM vm, AIFileInfo *info);
private:
class Squirrel *engine;
HSQOBJECT *SQ_instance;
char *script_name;
char *dir_name;
class AIScanner *base;
const char *author;
const char *name;
const char *description;
const char *date;
const char *instance_name;
};
class AIInfo : public AIFileInfo {
public:
static const char *GetClassName() { return "AIInfo"; }
~AIInfo();
/**
* Create an AI, using this AIInfo as start-template.
*/
static SQInteger Constructor(HSQUIRRELVM vm);
static SQInteger DummyConstructor(HSQUIRRELVM vm);
/**
* Get the config list for this AI.
*/
const AIConfigItemList *GetConfigList();
/**
* Set a setting.
*/
SQInteger AddSetting(HSQUIRRELVM vm);
/**
* Get the default value for a setting.
*/
int GetSettingDefaultValue(const char *name);
private:
AIConfigItemList config_list;
};
class AILibrary : public AIFileInfo {
public:
/**
* Create an AI, using this AIInfo as start-template.
*/
static SQInteger Constructor(HSQUIRRELVM vm);
static SQInteger Import(HSQUIRRELVM vm);
};
#endif /* AI_INFO */

@ -0,0 +1,66 @@
/* $Id$ */
#include <squirrel.h>
#include "../stdafx.h"
/* The reason this exists in C++, is that a user can trash his ai/ dir,
* leaving no AIs available. The complexity to solve this is insane, and
* therefor the alternative is used, and make sure there is always an AI
* available, no matter what the situation is. By defining it in C++, there
* is simply now way a user can delete it, and therefor safe to use. It has
* to be noted that this AI is complete invisible for the user, and impossible
* to select manual. It is a fail-over in case no AIs are available.
*/
const SQChar dummy_script_info[] = _SC(" \n\
class DummyAI extends AIInfo { \n\
function GetAuthor() { return \"OpenTTD NoAI Developers Team\"; } \n\
function GetName() { return \"DummyAI\"; } \n\
function GetDescription() { return \"A Dummy AI that is loaded when your ai/ dir is empty\"; }\n\
function GetVersion() { return 1; } \n\
function GetDate() { return \"2008-07-26\"; } \n\
function CreateInstance() { return \"DummyAI\"; } \n\
} \n\
\n\
RegisterDummyAI(DummyAI()); \n\
");
const SQChar dummy_script[] = _SC(" \n\
class DummyAI extends AIController { \n\
function Start() { \n\
AILog.Error(\"No suitable AI found to load.\"); \n\
AILog.Error(\"This AI is a dummy AI and won't do anything.\"); \n\
AILog.Error(\"Please add one or several AIs in your ai/ directory.\"); \n\
} \n\
} \n\
");
void AI_CreateAIInfoDummy(HSQUIRRELVM vm)
{
sq_pushroottable(vm);
/* Load and run the script */
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script_info, scstrlen(dummy_script_info), _SC("dummy"), SQTrue))) {
sq_push(vm, -2);
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
sq_pop(vm, 1);
return;
}
}
NOT_REACHED();
}
void AI_CreateAIDummy(HSQUIRRELVM vm)
{
sq_pushroottable(vm);
/* Load and run the script */
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script, scstrlen(dummy_script), _SC("dummy"), SQTrue))) {
sq_push(vm, -2);
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
sq_pop(vm, 1);
return;
}
}
NOT_REACHED();
}

@ -0,0 +1,628 @@
/* $Id$ */
/** @file ai_instance.cpp Implementation of AIInstance. */
#include "../stdafx.h"
#include "../openttd.h"
#include "../debug.h"
#include "../company_func.h"
#include "../core/alloc_func.hpp"
#include "../string_func.h"
#include "../settings_type.h"
#include "../company_base.h"
#include "../saveload/saveload.h"
#include "table/strings.h"
#include <squirrel.h>
#include "../script/squirrel.hpp"
#include "../script/squirrel_helper.hpp"
#include "../script/squirrel_class.hpp"
#include "../script/squirrel_std.hpp"
#include "ai.hpp"
#include "api/ai_controller.hpp"
#include "ai_info.hpp"
#include "ai_storage.hpp"
#include "ai_instance.hpp"
/* Convert all AI related classes to Squirrel data.
* Note: this line a marker in squirrel_export.sh. Do not change! */
#include "api/ai_abstractlist.hpp.sq"
#include "api/ai_accounting.hpp.sq"
#include "api/ai_airport.hpp.sq"
#include "api/ai_base.hpp.sq"
#include "api/ai_bridge.hpp.sq"
#include "api/ai_bridgelist.hpp.sq"
#include "api/ai_cargo.hpp.sq"
#include "api/ai_cargolist.hpp.sq"
#include "api/ai_company.hpp.sq"
#include "api/ai_controller.hpp.sq"
#include "api/ai_date.hpp.sq"
#include "api/ai_depotlist.hpp.sq"
#include "api/ai_engine.hpp.sq"
#include "api/ai_enginelist.hpp.sq"
#include "api/ai_error.hpp.sq"
#include "api/ai_event.hpp.sq"
#include "api/ai_event_types.hpp.sq"
#include "api/ai_execmode.hpp.sq"
#include "api/ai_gamesettings.hpp.sq"
#include "api/ai_group.hpp.sq"
#include "api/ai_grouplist.hpp.sq"
#include "api/ai_industry.hpp.sq"
#include "api/ai_industrylist.hpp.sq"
#include "api/ai_industrytype.hpp.sq"
#include "api/ai_industrytypelist.hpp.sq"
#include "api/ai_list.hpp.sq"
#include "api/ai_log.hpp.sq"
#include "api/ai_map.hpp.sq"
#include "api/ai_marine.hpp.sq"
#include "api/ai_order.hpp.sq"
#include "api/ai_rail.hpp.sq"
#include "api/ai_railtypelist.hpp.sq"
#include "api/ai_road.hpp.sq"
#include "api/ai_sign.hpp.sq"
#include "api/ai_station.hpp.sq"
#include "api/ai_stationlist.hpp.sq"
#include "api/ai_subsidy.hpp.sq"
#include "api/ai_subsidylist.hpp.sq"
#include "api/ai_testmode.hpp.sq"
#include "api/ai_tile.hpp.sq"
#include "api/ai_tilelist.hpp.sq"
#include "api/ai_town.hpp.sq"
#include "api/ai_townlist.hpp.sq"
#include "api/ai_tunnel.hpp.sq"
#include "api/ai_vehicle.hpp.sq"
#include "api/ai_vehiclelist.hpp.sq"
/* static */ AIInstance *AIInstance::current_instance = NULL;
AIStorage::~AIStorage()
{
/* Free our pointers */
if (event_data != NULL) AIEventController::FreeEventPointer();
if (log_data != NULL) AILog::FreeLogPointer();
}
static void PrintFunc(bool error_msg, const SQChar *message)
{
/* Convert to OpenTTD internal capable string */
AIController::Print(error_msg, FS2OTTD(message));
}
AIInstance::AIInstance(AIInfo *info) :
controller(NULL),
storage(NULL),
engine(NULL),
instance(NULL),
is_started(false),
is_dead(false),
suspend(0),
callback(NULL)
{
/* Set the instance already, so we can use AIObject::Set commands */
GetCompany(_current_company)->ai_instance = this;
AIInstance::current_instance = this;
this->controller = new AIController();
this->storage = new AIStorage();
this->engine = new Squirrel();
this->engine->SetPrintFunction(&PrintFunc);
/* The import method is available at a very early stage */
this->engine->AddMethod("import", &AILibrary::Import, 4, "?ssi");
/* Register the AIController */
SQAIController_Register(this->engine);
/* Load and execute the script for this AI */
const char *script_name = info->GetScriptName();
if (strcmp(script_name, "%_dummy") == 0) {
extern void AI_CreateAIDummy(HSQUIRRELVM vm);
AI_CreateAIDummy(this->engine->GetVM());
} else if (!this->engine->LoadScript(script_name)) {
this->Died();
return;
}
/* Create the main-class */
this->instance = MallocT<SQObject>(1);
if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
this->Died();
return;
}
/* Register the API functions and classes */
this->RegisterAPI();
/* Run the constructor if it exists. Don't allow any DoCommands in it. */
if (this->engine->MethodExists(*this->instance, "constructor")) {
AIObject::SetAllowDoCommand(false);
this->engine->CallMethod(*this->instance, "constructor");
AIObject::SetAllowDoCommand(true);
}
}
AIInstance::~AIInstance()
{
if (engine != NULL) delete this->engine;
delete this->storage;
delete this->controller;
free(this->instance);
}
void AIInstance::RegisterAPI()
{
/* Register all classes */
squirrel_register_std(this->engine);
SQAIAbstractList_Register(this->engine);
SQAIAccounting_Register(this->engine);
SQAIAirport_Register(this->engine);
SQAIBase_Register(this->engine);
SQAIBridge_Register(this->engine);
SQAIBridgeList_Register(this->engine);
SQAIBridgeList_Length_Register(this->engine);
SQAICargo_Register(this->engine);
SQAICargoList_Register(this->engine);
SQAICargoList_IndustryAccepting_Register(this->engine);
SQAICargoList_IndustryProducing_Register(this->engine);
SQAICompany_Register(this->engine);
SQAIDate_Register(this->engine);
SQAIDepotList_Register(this->engine);
SQAIEngine_Register(this->engine);
SQAIEngineList_Register(this->engine);
SQAIError_Register(this->engine);
SQAIEvent_Register(this->engine);
SQAIEventCompanyBankrupt_Register(this->engine);
SQAIEventCompanyInTrouble_Register(this->engine);
SQAIEventCompanyMerger_Register(this->engine);
SQAIEventCompanyNew_Register(this->engine);
SQAIEventController_Register(this->engine);
SQAIEventEngineAvailable_Register(this->engine);
SQAIEventEnginePreview_Register(this->engine);
SQAIEventIndustryClose_Register(this->engine);
SQAIEventIndustryOpen_Register(this->engine);
SQAIEventStationFirstVehicle_Register(this->engine);
SQAIEventSubsidyAwarded_Register(this->engine);
SQAIEventSubsidyExpired_Register(this->engine);
SQAIEventSubsidyOffer_Register(this->engine);
SQAIEventSubsidyOfferExpired_Register(this->engine);
SQAIEventTest_Register(this->engine);
SQAIEventVehicleCrashed_Register(this->engine);
SQAIEventVehicleLost_Register(this->engine);
SQAIEventVehicleUnprofitable_Register(this->engine);
SQAIEventVehicleWaitingInDepot_Register(this->engine);
SQAIExecMode_Register(this->engine);
SQAIGameSettings_Register(this->engine);
SQAIGroup_Register(this->engine);
SQAIGroupList_Register(this->engine);
SQAIIndustry_Register(this->engine);
SQAIIndustryList_Register(this->engine);
SQAIIndustryList_CargoAccepting_Register(this->engine);
SQAIIndustryList_CargoProducing_Register(this->engine);
SQAIIndustryType_Register(this->engine);
SQAIIndustryTypeList_Register(this->engine);
SQAIList_Register(this->engine);
SQAILog_Register(this->engine);
SQAIMap_Register(this->engine);
SQAIMarine_Register(this->engine);
SQAIOrder_Register(this->engine);
SQAIRail_Register(this->engine);
SQAIRailTypeList_Register(this->engine);
SQAIRoad_Register(this->engine);
SQAISign_Register(this->engine);
SQAIStation_Register(this->engine);
SQAIStationList_Register(this->engine);
SQAIStationList_Vehicle_Register(this->engine);
SQAISubsidy_Register(this->engine);
SQAISubsidyList_Register(this->engine);
SQAITestMode_Register(this->engine);
SQAITile_Register(this->engine);
SQAITileList_Register(this->engine);
SQAITileList_IndustryAccepting_Register(this->engine);
SQAITileList_IndustryProducing_Register(this->engine);
SQAITileList_StationType_Register(this->engine);
SQAITown_Register(this->engine);
SQAITownList_Register(this->engine);
SQAITunnel_Register(this->engine);
SQAIVehicle_Register(this->engine);
SQAIVehicleList_Register(this->engine);
SQAIVehicleList_Station_Register(this->engine);
this->engine->SetGlobalPointer(this->engine);
}
void AIInstance::Continue()
{
assert(this->suspend < 0);
this->suspend = -this->suspend - 1;
}
void AIInstance::Died()
{
DEBUG(ai, 0, "The AI died unexpectedly.");
this->is_dead = true;
delete this->engine;
this->engine = NULL;
}
void AIInstance::GameLoop()
{
if (this->is_dead) return;
this->controller->ticks++;
if (this->suspend < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
if (this->suspend < 0) return; // Multiplayer suspend, wait for Continue().
if (--this->suspend > 0) return; // Singleplayer suspend, decrease to 0.
/* If there is a callback to call, call that first */
if (this->callback != NULL) {
try {
this->callback(this);
} catch (AI_VMSuspend e) {
this->suspend = e.GetSuspendTime();
this->callback = e.GetSuspendCallback();
return;
}
}
this->suspend = 0;
this->callback = NULL;
if (!this->is_started) {
/* Start the AI by calling Start() */
try {
if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
} catch (AI_VMSuspend e) {
this->suspend = e.GetSuspendTime();
this->callback = e.GetSuspendCallback();
}
this->is_started = true;
return;
}
/* Continue the VM */
try {
if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
} catch (AI_VMSuspend e) {
this->suspend = e.GetSuspendTime();
this->callback = e.GetSuspendCallback();
}
}
/* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
{
instance->engine->InsertResult(AIObject::GetLastCommandRes());
}
/* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
{
instance->engine->InsertResult(AIObject::GetNewVehicleID());
}
/* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
{
instance->engine->InsertResult(AIObject::GetNewSignID());
}
/* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
{
instance->engine->InsertResult(AIObject::GetNewGroupID());
}
/* static */ AIStorage *AIInstance::GetStorage()
{
assert(IsValidCompanyID(_current_company) && !IsHumanCompany(_current_company));
return GetCompany(_current_company)->ai_instance->storage;
}
/*
* All data is stored in the following format:
* First 1 byte indicating if there is a data blob at all.
* 1 byte indicating the type of data.
* The data itself, this differs per type:
* - integer: a binary representation of the integer (int32).
* - string: First one byte with the string length, then a 0-terminated char
* array. The string can't be longer then 255 bytes (including
* terminating '\0').
* - array: All data-elements of the array are saved recursive in this
* format, and ended with an element of the type
* SQSL_ARRAY_TABLE_END.
* - table: All key/value pairs are saved in this format (first key 1, then
* value 1, then key 2, etc.). All keys and values can have an
* arbitrary type (as long as it is supported by the save function
* of course). The table is ended with an element of the type
* SQSL_ARRAY_TABLE_END.
* - bool: A single byte with value 1 representing true and 0 false.
* - null: No data.
*/
/** The type of the data that follows in the savegame. */
enum SQSaveLoadType {
SQSL_INT = 0x00, ///< The following data is an integer.
SQSL_STRING = 0x01, ///< The following data is an string.
SQSL_ARRAY = 0x02, ///< The following data is an array.
SQSL_TABLE = 0x03, ///< The following data is an table.
SQSL_BOOL = 0x04, ///< The following data is a boolean.
SQSL_NULL = 0x05, ///< A null variable.
SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
};
static byte _ai_sl_byte;
static const SaveLoad _ai_byte[] = {
SLEG_VAR(_ai_sl_byte, SLE_UINT8),
SLE_END()
};
enum {
AISAVE_MAX_DEPTH = 25, ///< The maximum recursive depth for items stored in the savegame.
};
/* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
{
if (max_depth == 0) {
AILog::Error("Savedata can only be nested to 5 deep. No data saved.");
return false;
}
switch (sq_gettype(vm, index)) {
case OT_INTEGER: {
if (!test) {
_ai_sl_byte = SQSL_INT;
SlObject(NULL, _ai_byte);
}
SQInteger res;
sq_getinteger(vm, index, &res);
if (!test) {
int value = (int)res;
SlArray(&value, 1, SLE_INT32);
}
return true;
}
case OT_STRING: {
if (!test) {
_ai_sl_byte = SQSL_STRING;
SlObject(NULL, _ai_byte);
}
const SQChar *res;
sq_getstring(vm, index, &res);
/* @bug if a string longer than 512 characters is given to FS2OTTD, the
* internal buffer overflows. */
const char *buf = FS2OTTD(res);
size_t len = strlen(buf) + 1;
if (len >= 255) {
AILog::Error("Maximum string length is 254 chars. No data saved.");
return false;
}
if (!test) {
_ai_sl_byte = (byte)len;
SlObject(NULL, _ai_byte);
SlArray((void*)buf, len, SLE_CHAR);
}
return true;
}
case OT_ARRAY: {
if (!test) {
_ai_sl_byte = SQSL_ARRAY;
SlObject(NULL, _ai_byte);
}
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
/* Store the value */
bool res = SaveObject(vm, -1, max_depth - 1, test);
sq_pop(vm, 2);
if (!res) {
sq_pop(vm, 1);
return false;
}
}
sq_pop(vm, 1);
if (!test) {
_ai_sl_byte = SQSL_ARRAY_TABLE_END;
SlObject(NULL, _ai_byte);
}
return true;
}
case OT_TABLE: {
if (!test) {
_ai_sl_byte = SQSL_TABLE;
SlObject(NULL, _ai_byte);
}
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
/* Store the key + value */
bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
sq_pop(vm, 2);
if (!res) {
sq_pop(vm, 1);
return false;
}
}
sq_pop(vm, 1);
if (!test) {
_ai_sl_byte = SQSL_ARRAY_TABLE_END;
SlObject(NULL, _ai_byte);
}
return true;
}
case OT_BOOL: {
if (!test) {
_ai_sl_byte = SQSL_BOOL;
SlObject(NULL, _ai_byte);
}
SQBool res;
sq_getbool(vm, index, &res);
if (!test) {
_ai_sl_byte = res ? 1 : 0;
SlObject(NULL, _ai_byte);
}
return true;
}
case OT_NULL: {
if (!test) {
_ai_sl_byte = SQSL_NULL;
SlObject(NULL, _ai_byte);
}
return true;
}
default:
AILog::Error("You tried to save unsupported type. No data saved.");
return false;
}
}
/* static */ void AIInstance::SaveEmpty()
{
_ai_sl_byte = 0;
SlObject(NULL, _ai_byte);
}
void AIInstance::Save()
{
/* Don't save data if the AI didn't start yet. */
if (this->engine == NULL) {
SaveEmpty();
return;
}
/* We don't want to be interrupted during the save function. */
AIObject::SetAllowDoCommand(false);
HSQOBJECT savedata;
if (this->engine->MethodExists(*this->instance, "Save")) {
this->engine->CallMethod(*this->instance, "Save", &savedata);
if (!sq_istable(savedata)) {
AILog::Error("Save function should return a table.");
_ai_sl_byte = 0;
SlObject(NULL, _ai_byte);
AIObject::SetAllowDoCommand(true);
return;
}
HSQUIRRELVM vm = this->engine->GetVM();
sq_pushobject(vm, savedata);
if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
_ai_sl_byte = 1;
SlObject(NULL, _ai_byte);
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
} else {
_ai_sl_byte = 0;
SlObject(NULL, _ai_byte);
}
sq_pop(vm, 1);
} else {
AILog::Warning("Save function is not implemented");
_ai_sl_byte = 0;
SlObject(NULL, _ai_byte);
}
AIObject::SetAllowDoCommand(true);
}
/* static */ bool AIInstance::LoadObjects(HSQUIRRELVM vm)
{
SlObject(NULL, _ai_byte);
switch (_ai_sl_byte) {
case SQSL_INT: {
int value;
SlArray(&value, 1, SLE_INT32);
if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
return true;
}
case SQSL_STRING: {
SlObject(NULL, _ai_byte);
static char buf[256];
SlArray(buf, _ai_sl_byte, SLE_CHAR);
if (vm != NULL) sq_pushstring(vm, OTTD2FS(buf), -1);
return true;
}
case SQSL_ARRAY: {
if (vm != NULL) sq_newarray(vm, 0);
while (LoadObjects(vm)) {
if (vm != NULL) sq_arrayappend(vm, -2);
/* The value is popped from the stack by squirrel. */
}
return true;
}
case SQSL_TABLE: {
if (vm != NULL) sq_newtable(vm);
while (LoadObjects(vm)) {
LoadObjects(vm);
if (vm != NULL) sq_rawset(vm, -3);
/* The key (-2) and value (-1) are popped from the stack by squirrel. */
}
return true;
}
case SQSL_BOOL: {
SlObject(NULL, _ai_byte);
if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
return true;
}
case SQSL_NULL: {
if (vm != NULL) sq_pushnull(vm);
return true;
}
case SQSL_ARRAY_TABLE_END: {
return false;
}
default: NOT_REACHED();
}
}
/* static */ void AIInstance::LoadEmpty()
{
SlObject(NULL, _ai_byte);
/* Check if there was anything saved at all. */
if (_ai_sl_byte == 0) return;
LoadObjects(NULL);
}
bool AIInstance::Load()
{
HSQUIRRELVM vm = (this->engine == NULL) ? NULL : this->engine->GetVM();
SlObject(NULL, _ai_byte);
/* Check if there was anything saved at all. */
if (_ai_sl_byte == 0) return true;
AIObject::SetAllowDoCommand(false);
if (vm != NULL) {
/* Go to the instance-root */
sq_pushobject(vm, *this->instance);
/* Find the function-name inside the script */
sq_pushstring(vm, OTTD2FS("Load"), -1);
if (SQ_FAILED(sq_get(vm, -2))) sq_pushnull(vm);
sq_pushobject(vm, *this->instance);
}
LoadObjects(vm);
if (this->engine != NULL) {
if (this->engine->MethodExists(*this->instance, "Load")) {
sq_call(vm, 2, SQFalse, SQFalse);
} else {
AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
}
}
/* Pop 1) the object instance, 2) the function name, 3) the instance again, 4) the table. */
if (vm != NULL) sq_pop(vm, 4);
AIObject::SetAllowDoCommand(true);
return true;
}

@ -0,0 +1,140 @@
/* $Id$ */
/** @file ai_instance.hpp The AIInstance tracks an AI. */
#ifndef AI_INSTANCE_HPP
#define AI_INSTANCE_HPP
/**
* The callback function when an AI suspends.
*/
typedef void (AISuspendCallbackProc)(class AIInstance *instance);
/**
* A throw-class that is given when the VM wants to suspend.
*/
class AI_VMSuspend {
public:
AI_VMSuspend(int time, AISuspendCallbackProc *callback) :
time(time),
callback(callback)
{}
int GetSuspendTime() { return time; }
AISuspendCallbackProc *GetSuspendCallback() { return callback; }
private:
int time;
AISuspendCallbackProc *callback;
};
class AIInstance {
public:
AIInstance(class AIInfo *info);
~AIInstance();
/**
* An AI in multiplayer waits for the server to handle his DoCommand.
* It keeps waiting for this until this function is called.
*/
void Continue();
/**
* Run the GameLoop of an AI.
*/
void GameLoop();
/**
* Get the storage of this AI.
*/
static class AIStorage *GetStorage();
/**
* Return a true/false reply for a DoCommand.
*/
static void DoCommandReturn(AIInstance *instance);
/**
* Return a VehicleID reply for a DoCommand.
*/
static void DoCommandReturnVehicleID(AIInstance *instance);
/**
* Return a SignID reply for a DoCommand.
*/
static void DoCommandReturnSignID(AIInstance *instance);
/**
* Return a GroupID reply for a DoCommand.
*/
static void DoCommandReturnGroupID(AIInstance *instance);
/**
* Get the controller attached to the instance.
*/
class AIController *GetController() { return controller; }
/**
* Call the AI Save function and save all data in the savegame.
*/
void Save();
/**
* Don't save any data in the savegame.
*/
static void SaveEmpty();
/**
* Load data from a savegame and call the AI Load function if it
* exists.
* @return True if the loading was successfull.
*/
bool Load();
/**
* Load and discard data from a savegame.
*/
static void LoadEmpty();
private:
static class AIInstance *current_instance; //!< Static current AIInstance, so we can register AIs.
class AIController *controller;
class AIStorage *storage;
class Squirrel *engine;
SQObject *instance;
bool is_started;
bool is_dead;
int suspend;
AISuspendCallbackProc *callback;
/**
* Register all API functions to the VM.
*/
void RegisterAPI();
/**
* Tell the AI it died.
*/
void Died();
/**
* Save one object (int / string / arrray / table) to the savegame.
* @param index The index on the squirrel stack of the element to save.
* @param max_depth The maximum depth recursive arrays / tables will be stored
* with before an error is returned.
* @param test If true, don't really store the data but only check if it is
* valid.
* @return True if the saving was successfull.
*/
static bool SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test);
/**
* Load all objects from a savegame.
* @return True if the loading was successfull.
*/
static bool LoadObjects(HSQUIRRELVM vm);
};
#endif /* AI_INSTANCE_HPP */

@ -0,0 +1,395 @@
/* $Id$ */
/** @file ai_scanner.cpp allows scanning AI scripts */
#include "../stdafx.h"
#include "../debug.h"
#include "../openttd.h"
#include "../string_func.h"
#include "../fileio_func.h"
#include "../fios.h"
#include "../network/network.h"
#include "../core/random_func.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <squirrel.h>
#include "../script/squirrel.hpp"
#include "../script/squirrel_helper.hpp"
#include "../script/squirrel_class.hpp"
#include "ai.hpp"
#include "ai_info.hpp"
#include "ai_scanner.hpp"
#include "api/ai_controller.hpp"
void AIScanner::ScanDir(const char *dirname, bool library_dir, char *library_depth)
{
extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
extern bool FiosIsHiddenFile(const struct dirent *ent);
struct stat sb;
struct dirent *dirent;
DIR *dir;
char d_name[MAX_PATH];
char script_name[MAX_PATH];
dir = ttd_opendir(dirname);
/* Dir not found, so do nothing */
if (dir == NULL) return;
/* Walk all dirs trying to find a dir in which 'main.nut' exists */
while ((dirent = readdir(dir)) != NULL) {
ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
/* Valid file, not '.' or '..', not hidden */
if (!FiosIsValidFile(dirname, dirent, &sb)) continue;
if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
if (FiosIsHiddenFile(dirent) && strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) != 0) continue;
if (S_ISDIR(sb.st_mode)) {
/* Create the full-length script-name */
ttd_strlcpy(script_name, dirname, sizeof(script_name));
ttd_strlcat(script_name, d_name, sizeof(script_name));
ttd_strlcat(script_name, PATHSEP, sizeof(script_name));
if (library_dir && library_depth == NULL) {
ScanDir(script_name, library_dir, d_name);
continue;
}
}
if (S_ISREG(sb.st_mode)) {
if (library_dir) continue;
char *ext = strrchr(d_name, '.');
if (ext == NULL || strcasecmp(ext, ".tar") != 0) continue;
/* Create the full path to the tarfile */
char tarname[MAX_PATH];
ttd_strlcpy(tarname, dirname, sizeof(tarname));
ttd_strlcat(tarname, d_name, sizeof(tarname));
/* Now the script-name starts with the first dir in the tar */
if (FioTarFirstDir(tarname) == NULL) continue;
ttd_strlcpy(script_name, "%aitar%", sizeof(tarname));
ttd_strlcat(script_name, FioTarFirstDir(tarname), sizeof(script_name));
FioTarAddLink(script_name, FioTarFirstDir(tarname));
/* The name of the AI is the name of the tar minus the .tar */
*ext = '\0';
}
if (!library_dir) {
/* We look for the file 'info.nut' inside the AI dir.. if it doesn't exists, it isn't an AI */
ttd_strlcat(script_name, "info.nut", sizeof(script_name));
if (FioCheckFileExists(script_name, AI_DIR)) {
char load_script[MAX_PATH];
ttd_strlcpy(load_script, script_name, sizeof(load_script));
/* Remove the 'info.nut' part and replace it with 'main.nut' */
script_name[strlen(script_name) - 8] = '\0';
ttd_strlcat(script_name, "main.nut", sizeof(script_name));
DEBUG(ai, 6, "[script] Loading script '%s' for AI handling", load_script);
this->current_script = script_name;
this->current_dir = d_name;
this->engine->LoadScript(load_script);
}
} else {
/* We look for the file 'library.nut' inside the library dir.. */
ttd_strlcat(script_name, "library.nut", sizeof(script_name));
if (FioCheckFileExists(script_name, AI_DIR)) {
char load_script[MAX_PATH];
char dir_name[MAX_PATH];
char d_name_2[MAX_PATH];
/* In case the directory has a dot in it, ignore it, as that is the
* indicator for multiple versions of the same library */
ttd_strlcpy(d_name_2, d_name, sizeof(d_name_2));
char *e = strrchr(d_name_2, '.');
if (e != NULL) *e = '\0';
ttd_strlcpy(load_script, script_name, sizeof(load_script));
ttd_strlcpy(dir_name, library_depth, sizeof(dir_name));
ttd_strlcat(dir_name, ".", sizeof(dir_name));
ttd_strlcat(dir_name, d_name_2, sizeof(dir_name));
/* Remove the 'library.nut' part and replace it with 'main.nut' */
script_name[strlen(script_name) - 11] = '\0';
ttd_strlcat(script_name, "main.nut", sizeof(script_name));
DEBUG(ai, 6, "[script] Loading script '%s' for Squirrel library", load_script);
this->current_script = script_name;
this->current_dir = dir_name;
this->engine->LoadScript(load_script);
}
}
}
closedir(dir);
}
void AIScanner::ScanAIDir()
{
char buf[MAX_PATH];
Searchpath sp;
FOR_ALL_SEARCHPATHS(sp) {
FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
if (FileExists(buf)) this->ScanDir(buf, false);
ttd_strlcat(buf, "library" PATHSEP, MAX_PATH);
if (FileExists(buf)) this->ScanDir(buf, true);
}
}
void AIScanner::RescanAIDir()
{
extern void ScanForTarFiles();
ScanForTarFiles();
this->ScanAIDir();
}
AIScanner::AIScanner()
{
this->engine = new Squirrel();
/* Create the AIInfo class, and add the RegisterAI function */
DefSQClass <AIInfo> SQAIInfo("AIInfo");
SQAIInfo.PreRegister(engine);
SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
SQAIInfo.DefSQAdvancedMethod(this->engine, &AIInfo::AddSetting, "AddSetting");
SQAIInfo.PostRegister(engine);
this->engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx");
/* Create the AILibrary class, and add the RegisterLibrary function */
this->engine->AddClassBegin("AILibrary");
this->engine->AddClassEnd();
this->engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx");
/* Mark this class as global pointer */
this->engine->SetGlobalPointer(this);
/* Scan the AI dir for scripts */
this->ScanAIDir();
/* Create the dummy AI */
this->engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx");
this->current_script = (char *)"%_dummy";
this->current_dir = (char *)"%_dummy";
extern void AI_CreateAIInfoDummy(HSQUIRRELVM vm);
AI_CreateAIInfoDummy(this->engine->GetVM());
}
AIScanner::~AIScanner()
{
AIInfoList::iterator it = this->info_list.begin();
for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second;
delete i;
}
delete this->engine;
}
bool AIScanner::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, AIController *controller)
{
/* Internally we store libraries as 'library.version' */
char library_name[1024];
snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
/* Check if the library + version exists */
AILibraryList::iterator iter = this->library_list.find(library_name);
if (iter == this->library_list.end()) {
char error[1024];
/* Now see if the version doesn't exist, or the library */
iter = this->library_list.find(library);
if (iter == this->library_list.end()) {
snprintf(error, sizeof(error), "couldn't find library '%s'", library);
} else {
snprintf(error, sizeof(error), "this AI is expecting library '%s' to be version %d, but the latest available is version %d", library, version, (*iter).second->GetVersion());
}
sq_throwerror(vm, OTTD2FS(error));
return false;
}
/* Get the current table/class we belong to */
HSQOBJECT parent;
sq_getstackobj(vm, 1, &parent);
char fake_class[1024];
int next_number;
/* Check if we already have this library loaded.. if so, fill fake_class
* with the class-name it is nested in */
if (!controller->LoadedLibrary(library_name, &next_number, &fake_class[0], sizeof(fake_class))) {
/* Create a new fake internal name */
snprintf(fake_class, sizeof(fake_class), "_internalNA%d", next_number);
/* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
sq_pushroottable(vm);
sq_pushstring(vm, OTTD2FS(fake_class), -1);
sq_newclass(vm, SQFalse);
/* Load the library */
if (!Squirrel::LoadScript(vm, (*iter).second->GetScriptName(), false)) {
char error[1024];
snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version);
sq_throwerror(vm, OTTD2FS(error));
return false;
}
/* Create the fake class */
sq_newslot(vm, -3, SQFalse);
sq_pop(vm, 1);
controller->AddLoadedLibrary(library_name, fake_class);
}
/* Find the real class inside the fake class (like 'sets.Vector') */
sq_pushroottable(vm);
sq_pushstring(vm, OTTD2FS(fake_class), -1);
if (SQ_FAILED(sq_get(vm, -2))) {
sq_throwerror(vm, _SC("internal error assigning library class"));
return false;
}
sq_pushstring(vm, OTTD2FS((*iter).second->GetInstanceName()), -1);
if (SQ_FAILED(sq_get(vm, -2))) {
char error[1024];
snprintf(error, sizeof(error), "unable to find class '%s' in the library '%s' version %d", (*iter).second->GetInstanceName(), library, version);
sq_throwerror(vm, OTTD2FS(error));
return false;
}
HSQOBJECT obj;
sq_getstackobj(vm, -1, &obj);
sq_pop(vm, 3);
if (StrEmpty(class_name)) {
sq_pushobject(vm, obj);
return true;
}
/* Now link the name the user wanted to our 'fake' class */
sq_pushobject(vm, parent);
sq_pushstring(vm, OTTD2FS(class_name), -1);
sq_pushobject(vm, obj);
sq_newclass(vm, SQTrue);
sq_newslot(vm, -3, SQFalse);
sq_pop(vm, 1);
sq_pushobject(vm, obj);
return true;
}
void AIScanner::RegisterLibrary(AILibrary *library)
{
const char *ai_name_without_version = library->GetDirName();
char ai_name[1024];
snprintf(ai_name, sizeof(ai_name), "%s.%d", library->GetDirName(), library->GetVersion());
/* Check if we register twice; than the first always wins */
if (this->library_list.find(ai_name) != this->library_list.end()) {
/* In case they are not the same dir, give a warning */
if (strcasecmp(library->GetScriptName(), this->library_list[ai_name]->GetScriptName()) != 0) {
DEBUG(ai, 0, "Registering two libraries with the same name");
DEBUG(ai, 0, " 1: %s", this->library_list[ai_name]->GetScriptName());
DEBUG(ai, 0, " 2: %s", library->GetScriptName());
DEBUG(ai, 0, "The first is taking precedence");
}
/* Delete the new AILibrary, as we will be using the old one */
delete library;
return;
}
this->library_list[strdup(ai_name)] = library;
/* Insert the global name too, so we if the library is known at all */
if (this->library_list.find(ai_name_without_version) == this->library_list.end()) {
this->library_list[strdup(ai_name_without_version)] = library;
} else if (this->library_list[ai_name_without_version]->GetVersion() < library->GetVersion()) {
this->library_list[ai_name_without_version] = library;
}
}
void AIScanner::RegisterAI(AIInfo *info)
{
const char *ai_name = info->GetDirName();
/* Check if we register twice; than the first always wins */
if (this->info_list.find(ai_name) != this->info_list.end()) {
/* In case they are not the same dir, give a warning */
if (strcasecmp(info->GetScriptName(), this->info_list[ai_name]->GetScriptName()) != 0) {
DEBUG(ai, 0, "Registering two AIs with the same name");
DEBUG(ai, 0, " 1: %s", this->info_list[ai_name]->GetScriptName());
DEBUG(ai, 0, " 2: %s", info->GetScriptName());
DEBUG(ai, 0, "The first is taking precedence");
}
/* Delete the new AIInfo, as we will be using the old one */
delete info;
return;
}
this->info_list[strdup(ai_name)] = info;
}
void AIScanner::UnregisterAI(AIInfo *info)
{
this->info_list.erase(info->GetDirName());
}
AIInfo *AIScanner::SelectRandomAI()
{
if (this->info_list.size() == 0) {
DEBUG(ai, 0, "No suitable AI found, loading 'dummy' AI.");
return this->info_dummy;
}
/* Find a random AI */
uint pos;
if (_networking) pos = InteractiveRandomRange((uint16)this->info_list.size());
else pos = RandomRange((uint16)this->info_list.size());
/* Find the Nth item from the array */
AIInfoList::iterator it = this->info_list.begin();
for (; pos > 0; pos--) it++;
AIInfoList::iterator first_it = it;
AIInfo *i = (*it).second;
if (!i->AllowStartup()) {
/* We can't start this AI, try to find the next best */
do {
it++;
if (it == this->info_list.end()) it = this->info_list.begin();
/* Back at the beginning? We can't start an AI. */
if (first_it == it) {
DEBUG(ai, 0, "No suitable AI found, loading 'dummy' AI.");
return this->info_dummy;
}
i = (*it).second;
} while (!i->AllowStartup());
}
return i;
}
AIInfo *AIScanner::FindAI(const char *name)
{
if (this->info_list.size() == 0) return NULL;
if (name == NULL) return NULL;
AIInfoList::iterator it = this->info_list.begin();
for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second;
if (strcasecmp(name, (*it).first) == 0 && i->AllowStartup()) {
return i;
}
}
return NULL;
}
char *AIScanner::GetAIConsoleList(char *p, const char *last)
{
p += seprintf(p, last, "List of AIs:\n");
AIInfoList::iterator it = this->info_list.begin();
for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second;
if (!i->AllowStartup()) continue;
p += seprintf(p, last, "%10s: %s\n", (*it).first, i->GetDescription());
}
p += seprintf(p, last, "\n");
return p;
}

@ -0,0 +1,102 @@
/* $Id$ */
/** @file ai_scanner.hpp declarations of the class for AI scanner */
#ifndef AI_SCANNER_HPP
#define AI_SCANNER_HPP
#include <map>
class AIScanner {
public:
AIScanner();
~AIScanner();
/**
* Import a library inside the Squirrel VM.
*/
bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, class AIController *controller);
/**
* Register a library to be put in the available list.
*/
void RegisterLibrary(class AILibrary *library);
/**
* Register an AI to be put in the available list.
*/
void RegisterAI(class AIInfo *info);
void SetDummyAI(class AIInfo *info) { this->info_dummy = info; }
/**
* Remove an AI from the available list.
*/
void UnregisterAI(class AIInfo *info);
/**
* Select a Random AI.
*/
class AIInfo *SelectRandomAI();
/**
* Find an AI by name.
*/
class AIInfo *FindAI(const char *name);
/**
* Get the list of available AIs for the console.
*/
char *GetAIConsoleList(char *p, const char *last);
/**
* Get the list of all registered AIs.
*/
const AIInfoList *GetAIInfoList() { return &this->info_list; }
/**
* Get the engine of the main squirrel handler (it indexes all avialable squirrels).
*/
class Squirrel *GetEngine() { return this->engine; }
/**
* Get the current script the ScanDir is looking at.
*/
const char *GetCurrentScript() { return this->current_script; }
/**
* Get the directory of the current script the ScanDir is looking at.
*/
const char *GetCurrentDirName() { return this->current_dir; }
/**
* Rescan the AI dir for scripts.
*/
void RescanAIDir();
private:
typedef std::map<const char *, class AILibrary *, ltstr> AILibraryList;
/**
* Scan the AI dir for scripts.
*/
void ScanAIDir();
/**
* Scan a dir for AIs.
* For non-library-scan, if an AI is found, AIInfo is created, and the AI
* is registered to the central system.
* For library-scan, if a library is found, AILibrary is created, and the
* library is registered to the central system.
*/
void ScanDir(const char *dirname, bool library_dir, char *library_depth = NULL);
AIInfoList info_list;
AIInfo *info_dummy;
AILibraryList library_list;
class Squirrel *engine;
char *current_script;
char *current_dir;
};
#endif /* AI_SCANNER_HPP */

@ -0,0 +1,78 @@
/* $Id$ */
/** @file ai_storage.hpp Defines AIStorage and includes all files required for it. */
#ifndef AI_STORAGE_HPP
#define AI_STORAGE_HPP
#include "../command_func.h"
#include "../map_func.h"
#include "../network/network.h"
#include "../company_func.h"
#include "../signs_func.h"
#include "../tunnelbridge.h"
#include "../vehicle_func.h"
#include "../group.h"
#include <vector>
/**
* The callback function for Mode-classes.
*/
typedef bool (AIModeProc)(TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCost costs);
/**
* The storage for each AI. It keeps track of important information.
*/
class AIStorage {
friend class AIObject;
private:
AIModeProc *mode; //!< The current build mode we are int.
class AIObject *mode_instance; //!< The instance belonging to the current build mode.
uint delay; //!< The ticks of delay each DoCommand has.
bool allow_do_command; //!< Is the usage of DoCommands restricted?
CommandCost costs; //!< The costs the AI is tracking.
Money last_cost; //!< The last cost of the command.
uint last_error; //!< The last error of the command.
bool last_command_res; //!< The last result of the command.
VehicleID new_vehicle_id; //!< The ID of the new Vehicle.
SignID new_sign_id; //!< The ID of the new Sign.
TileIndex new_tunnel_endtile; //!< The TileIndex of the new Tunnel.
GroupID new_group_id; //!< The ID of the new Group.
std::vector<int> callback_value; //!< The values which need to survive a callback.
RoadType road_type; //!< The current roadtype we build.
RailType rail_type; //!< The current railtype we build.
void *event_data; //!< Pointer to the event data storage.
void *log_data; //!< Pointer to the log data storage.
public:
AIStorage() :
mode (NULL),
mode_instance (NULL),
delay (1),
allow_do_command (true),
/* costs (can't be set) */
last_cost (0),
last_error (STR_NULL),
last_command_res (true),
new_vehicle_id (0),
new_sign_id (0),
new_tunnel_endtile(INVALID_TILE),
new_group_id (0),
/* calback_value (can't be set) */
road_type (INVALID_ROADTYPE),
rail_type (INVALID_RAILTYPE),
event_data (NULL),
log_data (NULL)
{ }
~AIStorage();
};
#endif /* AI_STORAGE_HPP */

@ -0,0 +1,244 @@
# Doxyfile 1.5.4
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "OpenTTD NoAI API "
PROJECT_NUMBER =
OUTPUT_DIRECTORY = ../../../docs/aidocs/
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class " \
"The $name widget " \
"The $name file " \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = ./
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 2
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = YES
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = NO
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text "
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = .
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h \
*.hpp
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS = GetClassName DECLARE_ENUM_AS_BIT_SET DECLARE_POSTFIX_INCREMENT
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 1
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = DOXYGEN_SKIP
EXPAND_AS_DEFINED = DEF_COMMAND
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = openttd.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = NO
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

@ -0,0 +1,818 @@
/* $Id$ */
/** @file ai_abstractlist.cpp Implementation of AIAbstractList. */
#include <squirrel.h>
#include "ai_abstractlist.hpp"
#include "../../debug.h"
#include "../../core/alloc_func.hpp"
/**
* Base class for any AIAbstractList sorter.
*/
class AIAbstractListSorter {
protected:
AIAbstractList *list;
public:
/**
* Virtual dtor, needed to mute warnings.
*/
virtual ~AIAbstractListSorter() { }
/**
* Get the first item of the sorter.
*/
virtual int32 Begin() = 0;
/**
* Stop iterating a sorter.
*/
virtual void End() = 0;
/**
* Get the next item of the sorter.
*/
virtual int32 Next() = 0;
/**
* See if there is a next item of the sorter.
*/
virtual bool HasNext() = 0;
/**
* Callback from the list if an item gets removed.
*/
virtual void Remove(int item) = 0;
};
/**
* Sort by value, ascending.
*/
class AIAbstractListSorterValueAscending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
AIAbstractList::AIItemList *bucket_list;
AIAbstractList::AIItemList::iterator bucket_list_iter;
bool has_no_more_items;
int32 item_next;
public:
AIAbstractListSorterValueAscending(AIAbstractList *list)
{
this->list = list;
this->End();
}
int32 Begin()
{
if (this->list->buckets.empty()) return 0;
this->has_no_more_items = false;
this->bucket_iter = this->list->buckets.begin();
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->begin();
this->item_next = *this->bucket_list_iter;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void End()
{
this->bucket_list = NULL;
this->has_no_more_items = true;
this->item_next = 0;
}
void FindNext()
{
if (this->bucket_list == NULL) {
this->has_no_more_items = true;
return;
}
this->bucket_list_iter++;
if (this->bucket_list_iter == this->bucket_list->end()) {
this->bucket_iter++;
if (this->bucket_iter == this->list->buckets.end()) {
this->bucket_list = NULL;
return;
}
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->begin();
}
this->item_next = *this->bucket_list_iter;
}
int32 Next()
{
if (!this->HasNext()) return 0;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
{
if (!this->HasNext()) return;
/* If we remove the 'next' item, skip to the next */
if (item == this->item_next) {
FindNext();
return;
}
}
bool HasNext()
{
return !(this->list->buckets.empty() || this->has_no_more_items);
}
};
/**
* Sort by value, descending.
*/
class AIAbstractListSorterValueDescending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
AIAbstractList::AIItemList *bucket_list;
AIAbstractList::AIItemList::iterator bucket_list_iter;
bool has_no_more_items;
int32 item_next;
public:
AIAbstractListSorterValueDescending(AIAbstractList *list)
{
this->list = list;
this->End();
}
int32 Begin()
{
if (this->list->buckets.empty()) return 0;
this->has_no_more_items = false;
/* Go to the end of the bucket-list */
this->bucket_iter = this->list->buckets.begin();
for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
this->bucket_list = &(*this->bucket_iter).second;
/* Go to the end of the items in the bucket */
this->bucket_list_iter = this->bucket_list->begin();
for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
this->item_next = *this->bucket_list_iter;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void End() {
this->bucket_list = NULL;
this->has_no_more_items = true;
this->item_next = 0;
}
void FindNext()
{
if (this->bucket_list == NULL) {
this->has_no_more_items = true;
return;
}
if (this->bucket_list_iter == this->bucket_list->begin()) {
if (this->bucket_iter == this->list->buckets.begin()) {
this->bucket_list = NULL;
return;
}
this->bucket_iter--;
this->bucket_list = &(*this->bucket_iter).second;
/* Go to the end of the items in the bucket */
this->bucket_list_iter = this->bucket_list->begin();
for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
} else {
this->bucket_list_iter--;
}
this->item_next = *this->bucket_list_iter;
}
int32 Next()
{
if (!this->HasNext()) return 0;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
{
if (!this->HasNext()) return;
/* If we remove the 'next' item, skip to the next */
if (item == this->item_next) {
FindNext();
return;
}
}
bool HasNext()
{
return !(this->list->buckets.empty() || this->has_no_more_items);
}
};
/**
* Sort by item, ascending.
*/
class AIAbstractListSorterItemAscending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListMap::iterator item_iter;
bool has_no_more_items;
int32 item_next;
public:
AIAbstractListSorterItemAscending(AIAbstractList *list)
{
this->list = list;
this->End();
}
int32 Begin()
{
if (this->list->items.empty()) return 0;
this->has_no_more_items = false;
this->item_iter = this->list->items.begin();
this->item_next = (*this->item_iter).first;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void End()
{
this->has_no_more_items = true;
}
void FindNext()
{
if (this->item_iter == this->list->items.end()) {
this->has_no_more_items = true;
return;
}
this->item_iter++;
if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
}
int32 Next()
{
if (!this->HasNext()) return 0;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item) {
if (!this->HasNext()) return;
/* If we remove the 'next' item, skip to the next */
if (item == this->item_next) {
FindNext();
return;
}
}
bool HasNext()
{
return !(this->list->items.empty() || this->has_no_more_items);
}
};
/**
* Sort by item, descending.
*/
class AIAbstractListSorterItemDescending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListMap::iterator item_iter;
bool has_no_more_items;
int32 item_next;
public:
AIAbstractListSorterItemDescending(AIAbstractList *list)
{
this->list = list;
this->End();
}
int32 Begin()
{
if (this->list->items.empty()) return 0;
this->has_no_more_items = false;
this->item_iter = this->list->items.begin();
for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
this->item_next = (*this->item_iter).first;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void End()
{
this->has_no_more_items = true;
}
void FindNext()
{
if (this->item_iter == this->list->items.end()) {
this->has_no_more_items = true;
return;
}
this->item_iter--;
if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
}
int32 Next()
{
if (!this->HasNext()) return 0;
int32 item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
{
if (!this->HasNext()) return;
/* If we remove the 'next' item, skip to the next */
if (item == this->item_next) {
FindNext();
return;
}
}
bool HasNext()
{
return !(this->list->items.empty() || this->has_no_more_items);
}
};
AIAbstractList::AIAbstractList()
{
/* Default sorter */
this->sorter = new AIAbstractListSorterValueDescending(this);
this->sorter_type = SORT_BY_VALUE;
this->sort_ascending = false;
this->initialized = false;
}
AIAbstractList::~AIAbstractList()
{
delete this->sorter;
}
bool AIAbstractList::HasItem(int32 item)
{
return this->items.count(item) == 1;
}
void AIAbstractList::Clear()
{
this->items.clear();
this->buckets.clear();
this->sorter->End();
}
void AIAbstractList::AddItem(int32 item)
{
if (this->HasItem(item)) return;
this->items[item] = 0;
this->buckets[0].insert(item);
}
void AIAbstractList::RemoveItem(int32 item)
{
if (!this->HasItem(item)) return;
int32 value = this->GetValue(item);
this->sorter->Remove(item);
this->buckets[value].erase(item);
if (this->buckets[value].empty()) this->buckets.erase(value);
this->items.erase(item);
}
int32 AIAbstractList::Begin()
{
this->initialized = true;
return this->sorter->Begin();
}
int32 AIAbstractList::Next()
{
if (this->initialized == false) {
DEBUG(ai, 0, "ERROR: Next() is invalid as Begin() is never called");
return false;
}
return this->sorter->Next();
}
bool AIAbstractList::IsEmpty()
{
return this->items.empty();
}
bool AIAbstractList::HasNext()
{
if (this->initialized == false) {
DEBUG(ai, 0, "ERROR: HasNext() is invalid as Begin() is never called");
return false;
}
return this->sorter->HasNext();
}
int32 AIAbstractList::Count()
{
return (int32)this->items.size();
}
int32 AIAbstractList::GetValue(int32 item)
{
if (!this->HasItem(item)) return 0;
return this->items[item];
}
bool AIAbstractList::SetValue(int32 item, int32 value)
{
if (!this->HasItem(item)) return false;
int32 value_old = this->GetValue(item);
this->sorter->Remove(item);
this->buckets[value_old].erase(item);
if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
this->items[item] = value;
this->buckets[value].insert(item);
return true;
}
void AIAbstractList::Sort(SorterType sorter, bool ascending)
{
if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
delete this->sorter;
switch (sorter) {
case SORT_BY_ITEM:
if (ascending) this->sorter = new AIAbstractListSorterItemAscending(this);
else this->sorter = new AIAbstractListSorterItemDescending(this);
break;
case SORT_BY_VALUE:
if (ascending) this->sorter = new AIAbstractListSorterValueAscending(this);
else this->sorter = new AIAbstractListSorterValueDescending(this);
break;
default:
this->Sort(SORT_BY_ITEM, false);
return;
}
this->sorter_type = sorter;
this->sort_ascending = ascending;
}
void AIAbstractList::AddList(AIAbstractList *list)
{
AIAbstractListMap *list_items = &list->items;
for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
this->AddItem((*iter).first);
this->SetValue((*iter).first, (*iter).second);
}
}
void AIAbstractList::RemoveAboveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second > value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first > value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveBelowValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second < value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first < value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveBetweenValue(int32 start, int32 end)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second > start && (*iter).second < end) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second == value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first == value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveTop(int32 count)
{
if (!this->sort_ascending) {
this->Sort(this->sorter_type, !this->sort_ascending);
this->RemoveBottom(count);
this->Sort(this->sorter_type, !this->sort_ascending);
return;
}
switch (this->sorter_type) {
default: NOT_REACHED();
case SORT_BY_VALUE:
for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
AIItemList *items = &(*iter).second;
size_t size = items->size();
for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
if (--count < 0) return;
this->RemoveItem(*iter);
/* When the last item is removed from the bucket, the bucket itself is removed.
* This means that the iterators can be invalid after a call to RemoveItem.
*/
if (--size == 0) break;
}
}
break;
case SORT_BY_ITEM:
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
if (--count < 0) return;
this->RemoveItem((*iter).first);
}
break;
}
}
void AIAbstractList::RemoveBottom(int32 count)
{
if (!this->sort_ascending) {
this->Sort(this->sorter_type, !this->sort_ascending);
this->RemoveTop(count);
this->Sort(this->sorter_type, !this->sort_ascending);
return;
}
switch (this->sorter_type) {
default: NOT_REACHED();
case SORT_BY_VALUE:
for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
AIItemList *items = &(*iter).second;
size_t size = items->size();
for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
if (--count < 0) return;
this->RemoveItem(*iter);
/* When the last item is removed from the bucket, the bucket itself is removed.
* This means that the iterators can be invalid after a call to RemoveItem.
*/
if (--size == 0) break;
}
}
case SORT_BY_ITEM:
for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
if (--count < 0) return;
this->RemoveItem((*iter).first);
}
break;
}
}
void AIAbstractList::RemoveList(AIAbstractList *list)
{
AIAbstractListMap *list_items = &list->items;
for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
this->RemoveItem((*iter).first);
}
}
void AIAbstractList::KeepAboveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second <= value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first <= value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepBelowValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second >= value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first >= value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepBetweenValue(int32 start, int32 end)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second != value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first != value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepTop(int32 count)
{
this->RemoveBottom(this->Count() - count);
}
void AIAbstractList::KeepBottom(int32 count)
{
this->RemoveTop(this->Count() - count);
}
void AIAbstractList::KeepList(AIAbstractList *list)
{
AIAbstractList tmp;
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
tmp.AddItem((*iter).first);
tmp.SetValue((*iter).first, (*iter).second);
}
tmp.RemoveList(list);
this->RemoveList(&tmp);
}
SQInteger AIAbstractList::_get(HSQUIRRELVM vm) {
if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
SQInteger idx;
sq_getinteger(vm, 2, &idx);
if (!this->HasItem(idx)) return SQ_ERROR;
sq_pushinteger(vm, this->GetValue(idx));
return 1;
}
SQInteger AIAbstractList::_nexti(HSQUIRRELVM vm) {
if (sq_gettype(vm, 2) == OT_NULL) {
if (this->IsEmpty()) {
sq_pushnull(vm);
return 1;
}
sq_pushinteger(vm, this->Begin());
return 1;
}
SQInteger idx;
sq_getinteger(vm, 2, &idx);
int val = this->Next();
if (!this->HasNext()) {
sq_pushnull(vm);
return 1;
}
sq_pushinteger(vm, val);
return 1;
}
SQInteger AIAbstractList::Valuate(HSQUIRRELVM vm) {
int nparam = sq_gettop(vm) - 2;
/* Get the list instance and the function to call */
HSQOBJECT obj_list, obj_func;
sq_getstackobj(vm, 1, &obj_list);
sq_getstackobj(vm, 2, &obj_func);
if (sq_isclass(obj_list)) {
return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected instance)"));
}
if (sq_isfunction(obj_func)) {
return sq_throwerror(vm, _SC("parameter 2 has an invalid type (expected function)"));
}
sq_addref(vm, &obj_func);
/* Read the params */
HSQOBJECT *obj_params = AllocaM(HSQOBJECT, nparam);
for (int i = 0; i < nparam; i++) {
sq_getstackobj(vm, i + 3, &obj_params[i]);
sq_addref(vm, &obj_params[i]);
}
/* Remove all unneeded stuff */
sq_pop(vm, nparam + 1);
/* Walk all items, and query the result */
this->buckets.clear();
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
/* The function to call */
sq_pushobject(vm, obj_func);
/* The 'list' instance; this is most likely wrong, but we need to send something ;) */
sq_pushobject(vm, obj_list);
/* Now send the params */
sq_pushinteger(vm, (*iter).first);
for (int i = 0; i < nparam; i++) {
sq_pushobject(vm, obj_params[i]);
}
/* Call the function */
if (SQ_FAILED(sq_call(vm, nparam + 2, SQTrue, SQTrue))) return SQ_ERROR;
/* Retreive the return value */
SQInteger value;
switch (sq_gettype(vm, -1)) {
case OT_INTEGER: {
sq_getinteger(vm, -1, &value);
} break;
case OT_BOOL: {
SQBool v;
sq_getbool(vm, -1, &v);
value = v ? 1 : 0;
} break;
default: {
sq_pop(vm, 3);
sq_release(vm, &obj_func);
for (int i = 0; i < nparam; i++) sq_release(vm, &obj_params[i]);
return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
}
}
/* Remove junk */
sq_pop(vm, 2);
(*iter).second = (int32)value;
this->buckets[(int32)value].insert((*iter).first);
}
sq_release(vm, &obj_func);
for (int i = 0; i < nparam; i++) sq_release(vm, &obj_params[i]);
return 0;
}

@ -0,0 +1,263 @@
/* $Id$ */
/** @file ai_abstractlist.hpp A list which can keep item/value pairs, which you can walk. */
/** @defgroup AIList Classes that create a list of items. */
#ifndef AI_ABSTRACTLIST_HPP
#define AI_ABSTRACTLIST_HPP
#include "ai_object.hpp"
#include <map>
#include <set>
class AIAbstractListSorter;
/**
* Class that creates a list which can keep item/value pairs, which you can walk.
*/
class AIAbstractList : public AIObject {
public:
static const char *GetClassName() { return "AIAbstractList"; }
/** Type of sorter */
enum SorterType {
SORT_BY_VALUE, ///< Sort the list based on the value of the item.
SORT_BY_ITEM, ///< Sort the list based on the item itself.
};
private:
AIAbstractListSorter *sorter;
SorterType sorter_type;
bool sort_ascending;
bool initialized;
public:
typedef std::set<int32> AIItemList; //!< The list of items inside the bucket
typedef std::map<int32, AIItemList> AIAbstractListBucket; //!< The bucket list per value
typedef std::map<int32, int32> AIAbstractListMap; //!< List per item
AIAbstractListMap items; //!< The items in the list
AIAbstractListBucket buckets; //!< The items in the list, sorted by value
protected:
/**
* Add a single item to the list.
* @param item the item to add. Should be unique, otherwise it is ignored.
* @note the value is set to 0 by default.
*/
void AddItem(int32 item);
/**
* Remove a single item from the list.
* @param item the item to remove. If not existing, it is ignored.
*/
void RemoveItem(int32 item);
public:
AIAbstractList();
~AIAbstractList();
/**
* Clear the list, making Count() returning 0 and IsEmpty() returning true.
*/
void Clear();
/**
* Check if an item is in the list.
* @param item the item to check for.
* @return true if the item is in the list.
*/
bool HasItem(int32 item);
/**
* Go to the beginning of the list.
* @return the item value of the first item.
*/
int32 Begin();
/**
* Go to the next item in the list.
* @return the item value of the next item.
* @note returns 0 if beyond end-of-list. Use HasNext() to check for end-of-list.
*/
int32 Next();
/**
* Check if a list is empty.
* @return true if the list is empty.
*/
bool IsEmpty();
/**
* Check if there is a next element. In other words, if this is true,
* Next() will return a valid item.
* @return true if there is a next item.
*/
bool HasNext();
/**
* Returns the amount of items in the list.
* @return amount of items in the list.
*/
int32 Count();
/**
* Get the value that belongs to this item.
* @param item the item to get the value from
* @return the value that belongs to this item.
*/
int32 GetValue(int32 item);
/**
* Set a value of an item directly.
* @param item the item to set the value for.
* @param value the value to give to the item
* @return true if we could set the item to value, false otherwise.
* @note Changing values of items while looping through a list might cause
* entries to be skipped. Be very careful with such operations.
*/
bool SetValue(int32 item, int32 value);
/**
* Sort this list by the given sorter and direction.
* @param sorter the type of sorter to use
* @param ascending if true, lowest value is on top, else at bottom.
* @note the current item stays at the same place.
*/
void Sort(SorterType sorter, bool ascending);
/**
* Add one list to an other one.
* @param list The list that will be added to the caller.
* @post The list to be added ('list') stays unmodified.
* @note All added items keep their value as it was in 'list'.
* @note If the item already exists inside the caller, the value of the
* list that is added is set on the item.
*/
void AddList(AIAbstractList *list);
/**
* Removes all items with a higher value than 'value'.
* @param value the value above which all items are removed.
*/
void RemoveAboveValue(int32 value);
/**
* Removes all items with a lower value than 'value'.
* @param value the value below which all items are removed.
*/
void RemoveBelowValue(int32 value);
/**
* Removes all items with a value above start and below end.
* @param start the lower bound of the to be removed values (exclusive).
* @param end the upper bound of the to be removed valuens (exclusive).
*/
void RemoveBetweenValue(int32 start, int32 end);
/**
* Remove all items with this value.
* @param value the value to remove.
*/
void RemoveValue(int32 value);
/**
* Remove the first count items.
* @param count the amount of items to remove.
*/
void RemoveTop(int32 count);
/**
* Remove the last count items.
* @param count the amount of items to remove.
*/
void RemoveBottom(int32 count);
/**
* Remove everything that is in the given list from this list (same item index that is).
* @param list the list of items to remove.
* @pre list != NULL
*/
void RemoveList(AIAbstractList *list);
/**
* Keep all items with a higher value than 'value'.
* @param value the value above which all items are kept.
*/
void KeepAboveValue(int32 value);
/**
* Keep all items with a lower value than 'value'.
* @param value the value below which all items are kept.
*/
void KeepBelowValue(int32 value);
/**
* Keep all items with a value above start and below end.
* @param start the lower bound of the to be kept values (exclusive).
* @param end the upper bound of the to be kept values (exclusive).
*/
void KeepBetweenValue(int32 start, int32 end);
/**
* Keep all items with this value.
* @param value the value to keep.
**/
void KeepValue(int32 value);
/**
* Keep the first count items, i.e. remove everything except the first count items.
* @param count the amount of items to keep.
*/
void KeepTop(int32 count);
/**
* Keep the last count items, i.e. remove everything except the last count items.
* @param count the amount of items to keep.
*/
void KeepBottom(int32 count);
/**
* Keeps everything that is in the given list from this list (same item index that is).
* @param list the list of items to keep.
* @pre list != NULL
*/
void KeepList(AIAbstractList *list);
#ifndef DOXYGEN_SKIP
/**
* Used for 'foreach()' and [] get from Squirrel.
*/
SQInteger _get(HSQUIRRELVM vm);
/**
* Used for 'foreach()' from Squirrel.
*/
SQInteger _nexti(HSQUIRRELVM vm);
/**
* The Valuate() wrapper from Squirrel.
*/
SQInteger Valuate(HSQUIRRELVM vm);
#else
/**
* Give all items a value defined by the valuator you give.
* @param valuator_function The function which will be doing the valuation.
* @param params The params to give to the valuators (minus the first param,
* which is always the index-value we are valuating).
* @note You can write your own valuators and use them. Just remember that
* the first parameter should be the index-value, and it should return
* an integer.
* @note Example:
* list.Valuate(AIBridge.GetPrice, 5);
* list.Valuate(AIBridge.GetMaxLength);
* function MyVal(bridge_id, myparam) {
* return myparam * bridge_id; // This is silly
* }
* list.Valuate(MyVal, 12);
*/
void Valuate(void *valuator_function, int params, ...);
#endif /* DOXYGEN_SKIP */
};
#endif /* AI_LIST_HPP */

@ -0,0 +1,59 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_abstractlist.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AIAbstractList::SorterType GetParam(ForceType<AIAbstractList::SorterType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIAbstractList::SorterType)tmp; }
template <> int Return<AIAbstractList::SorterType>(HSQUIRRELVM vm, AIAbstractList::SorterType res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AIAbstractList to be used as Squirrel parameter */
template <> AIAbstractList *GetParam(ForceType<AIAbstractList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAbstractList *)instance; }
template <> AIAbstractList &GetParam(ForceType<AIAbstractList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAbstractList *)instance; }
template <> const AIAbstractList *GetParam(ForceType<const AIAbstractList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAbstractList *)instance; }
template <> const AIAbstractList &GetParam(ForceType<const AIAbstractList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAbstractList *)instance; }
template <> int Return<AIAbstractList *>(HSQUIRRELVM vm, AIAbstractList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIAbstractList", res, NULL, DefSQDestructorCallback<AIAbstractList>); return 1; }
}; // namespace SQConvert
void SQAIAbstractList_Register(Squirrel *engine) {
DefSQClass <AIAbstractList> SQAIAbstractList("AIAbstractList");
SQAIAbstractList.PreRegister(engine);
SQAIAbstractList.AddConstructor<void (AIAbstractList::*)(), 1>(engine, "x");
SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_BY_VALUE, "SORT_BY_VALUE");
SQAIAbstractList.DefSQConst(engine, AIAbstractList::SORT_BY_ITEM, "SORT_BY_ITEM");
SQAIAbstractList.DefSQStaticMethod(engine, &AIAbstractList::GetClassName, "GetClassName", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Clear, "Clear", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::HasItem, "HasItem", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Begin, "Begin", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Next, "Next", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::IsEmpty, "IsEmpty", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::HasNext, "HasNext", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Count, "Count", 1, "x");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::GetValue, "GetValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::SetValue, "SetValue", 3, "xii");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::Sort, "Sort", 3, "xib");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::AddList, "AddList", 2, "xx");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveAboveValue, "RemoveAboveValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBelowValue, "RemoveBelowValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBetweenValue, "RemoveBetweenValue", 3, "xii");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveValue, "RemoveValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveTop, "RemoveTop", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveBottom, "RemoveBottom", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::RemoveList, "RemoveList", 2, "xx");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepAboveValue, "KeepAboveValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBelowValue, "KeepBelowValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBetweenValue, "KeepBetweenValue", 3, "xii");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepValue, "KeepValue", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepTop, "KeepTop", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepBottom, "KeepBottom", 2, "xi");
SQAIAbstractList.DefSQMethod(engine, &AIAbstractList::KeepList, "KeepList", 2, "xx");
SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::_get, "_get");
SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::_nexti, "_nexti");
SQAIAbstractList.DefSQAdvancedMethod(engine, &AIAbstractList::Valuate, "Valuate");
SQAIAbstractList.PostRegister(engine);
}

@ -0,0 +1,26 @@
/* $Id$ */
/** @file ai_accounting.cpp Implementation of AIAccounting. */
#include "ai_accounting.hpp"
Money AIAccounting::GetCosts()
{
return this->GetDoCommandCosts();
}
void AIAccounting::ResetCosts()
{
this->SetDoCommandCosts(0);
}
AIAccounting::AIAccounting()
{
this->last_costs = this->GetDoCommandCosts();
this->SetDoCommandCosts(0);
}
AIAccounting::~AIAccounting()
{
this->SetDoCommandCosts(this->last_costs);
}

@ -0,0 +1,54 @@
/* $Id$ */
/** @file ai_accounting.hpp Everything to handle AI accounting things. */
#ifndef AI_ACCOUNTING_HPP
#define AI_ACCOUNTING_HPP
#include "ai_object.hpp"
/**
* Class that keeps track of the costs, so you can request how much a block of
* commands did cost in total. Works in both Execute as in Test mode.
* Example:
* {
* local costs = AIAccounting();
* BuildRoad(from_here, to_here);
* BuildRoad(from_there, to_there);
* print("Costs for route is: " + costs.GetCosts());
* }
*/
class AIAccounting : public AIObject {
public:
static const char *GetClassName() { return "AIAccounting"; }
/**
* Creating instance of this class starts counting the costs of commands
* from zero.
* @note when the instance is destroyed, he restores the costs that was
* current when the instance was created!
*/
AIAccounting();
/**
* Destroying this instance reset the costs to the value it was
* in when the instance was created.
*/
~AIAccounting();
/**
* Get the current value of the costs.
* @return The current costs.
*/
Money GetCosts();
/**
* Reset the costs to zero.
*/
void ResetCosts();
private:
Money last_costs;
};
#endif /* AI_ACCOUNTING_HPP */

@ -0,0 +1,26 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_accounting.hpp"
namespace SQConvert {
/* Allow AIAccounting to be used as Squirrel parameter */
template <> AIAccounting *GetParam(ForceType<AIAccounting *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAccounting *)instance; }
template <> AIAccounting &GetParam(ForceType<AIAccounting &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAccounting *)instance; }
template <> const AIAccounting *GetParam(ForceType<const AIAccounting *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAccounting *)instance; }
template <> const AIAccounting &GetParam(ForceType<const AIAccounting &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAccounting *)instance; }
template <> int Return<AIAccounting *>(HSQUIRRELVM vm, AIAccounting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIAccounting", res, NULL, DefSQDestructorCallback<AIAccounting>); return 1; }
}; // namespace SQConvert
void SQAIAccounting_Register(Squirrel *engine) {
DefSQClass <AIAccounting> SQAIAccounting("AIAccounting");
SQAIAccounting.PreRegister(engine);
SQAIAccounting.AddConstructor<void (AIAccounting::*)(), 1>(engine, "x");
SQAIAccounting.DefSQStaticMethod(engine, &AIAccounting::GetClassName, "GetClassName", 1, "x");
SQAIAccounting.DefSQMethod(engine, &AIAccounting::GetCosts, "GetCosts", 1, "x");
SQAIAccounting.DefSQMethod(engine, &AIAccounting::ResetCosts, "ResetCosts", 1, "x");
SQAIAccounting.PostRegister(engine);
}

@ -0,0 +1,130 @@
/* $Id$ */
/** @file ai_airport.cpp Implementation of AIAirport. */
#include "ai_airport.hpp"
#include "ai_station.hpp"
#include "ai_error.hpp"
#include "../../openttd.h"
#include "../../variables.h"
#include "../../station_map.h"
#include "../../company_func.h"
#include "../../settings_type.h"
#include "../../command_type.h"
#include "../../town.h"
/* static */ bool AIAirport::IsValidAirportType(AirportType type)
{
return type >= AT_SMALL && type <= AT_HELISTATION;
}
/* static */ bool AIAirport::IsHangarTile(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
return ::IsTileType(tile, MP_STATION) && ::IsHangar(tile);
}
/* static */ bool AIAirport::IsAirportTile(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
return ::IsTileType(tile, MP_STATION) && ::IsAirport(tile);
}
/* static */ bool AIAirport::AirportAvailable(AirportType type)
{
if (!IsValidAirportType(type)) return false;
return HasBit(::GetValidAirports(), type);
}
/* static */ int32 AIAirport::GetAirportWidth(AirportType type)
{
if (!IsValidAirportType(type)) return -1;
return ::GetAirport(type)->size_x;
}
/* static */ int32 AIAirport::GetAirportHeight(AirportType type)
{
if (!IsValidAirportType(type)) return -1;
return ::GetAirport(type)->size_y;
}
/* static */ int32 AIAirport::GetAirportCoverageRadius(AirportType type)
{
if (!IsValidAirportType(type)) return -1;
return _settings_game.station.modified_catchment ? ::GetAirport(type)->catchment : (uint)CA_UNMODIFIED;
}
/* static */ bool AIAirport::BuildAirport(TileIndex tile, AirportType type, bool join_adjacent)
{
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsValidAirportType(type));
return AIObject::DoCommand(tile, type, (INVALID_STATION << 16) | (join_adjacent ? 0 : 1), CMD_BUILD_AIRPORT);
}
/* static */ bool AIAirport::RemoveAirport(TileIndex tile)
{
EnforcePrecondition(false, ::IsValidTile(tile))
EnforcePrecondition(false, IsAirportTile(tile) || IsHangarTile(tile));
return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
}
/* static */ int32 AIAirport::GetNumHangars(TileIndex tile)
{
if (!::IsValidTile(tile)) return -1;
if (!::IsTileType(tile, MP_STATION)) return -1;
const Station *st = ::GetStationByTile(tile);
if (st->owner != _current_company) return -1;
if ((st->facilities & FACIL_AIRPORT) == 0) return -1;
return st->Airport()->nof_depots;
}
/* static */ TileIndex AIAirport::GetHangarOfAirport(TileIndex tile)
{
if (!::IsValidTile(tile)) return INVALID_TILE;
if (!::IsTileType(tile, MP_STATION)) return INVALID_TILE;
if (GetNumHangars(tile) < 1) return INVALID_TILE;
const Station *st = ::GetStationByTile(tile);
if (st->owner != _current_company) return INVALID_TILE;
if ((st->facilities & FACIL_AIRPORT) == 0) return INVALID_TILE;
return ::ToTileIndexDiff(st->Airport()->airport_depots[0]) + st->xy;
}
/* static */ AIAirport::AirportType AIAirport::GetAirportType(TileIndex tile)
{
if (!AITile::IsStationTile(tile)) return AT_INVALID;
StationID station_id = ::GetStationIndex(tile);
if (!AIStation::HasStationType(station_id, AIStation::STATION_AIRPORT)) return AT_INVALID;
return (AirportType)::GetStation(station_id)->airport_type;
}
/* static */ int AIAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type)
{
extern uint8 GetAirportNoiseLevelForTown(const AirportFTAClass *afc, TileIndex town_tile, TileIndex tile);
if (!::IsValidTile(tile)) return -1;
if (!IsValidAirportType(type)) return -1;
if (_settings_game.economy.station_noise_level) {
const AirportFTAClass *afc = ::GetAirport(type);
const Town *t = ::ClosestTownFromTile(tile, UINT_MAX);
return GetAirportNoiseLevelForTown(afc, t->xy, tile);
}
return 1;
}

@ -0,0 +1,164 @@
/* $Id$ */
/** @file ai_airport.hpp Everything to query and build airports. */
#ifndef AI_AIRPORT_HPP
#define AI_AIRPORT_HPP
#include "ai_object.hpp"
/**
* Class that handles all airport related functions.
*/
class AIAirport : public AIObject {
public:
static const char *GetClassName() { return "AIAirport"; }
/**
* The types of airports available in the game.
*/
enum AirportType {
/* Note: the values _are_ important as they represent an in-game value */
AT_SMALL = 0, //!< The small airport.
AT_LARGE = 1, //!< The large airport.
AT_METROPOLITAN = 3, //!< The metropolitan airport.
AT_INTERNATIONAL = 4, //!< The international airport.
AT_COMMUTER = 5, //!< The commuter airport.
AT_INTERCON = 7, //!< The intercontinental airport.
/* Next are the airports which only have helicopter platforms */
AT_HELIPORT = 2, //!< The heliport.
AT_HELISTATION = 8, //!< The helistation.
AT_HELIDEPOT = 6, //!< The helidepot.
AT_INVALID = 255, //!< Invalid airport.
};
/**
* All plane types available.
*/
enum PlaneType {
/* Note: the values _are_ important as they represent an in-game value */
PT_HELICOPTER = 0, //!< A helicopter.
PT_SMALL_PLANE = 1, //!< A small plane.
PT_BIG_PLANE = 3, //!< A big plane.
PT_INVALID = -1, //!< An invalid PlaneType
};
/**
* Checks whether the given AirportType is valid.
* @param type The AirportType to check.
* @return True if and only if the AirportTypeis valid.
*/
static bool IsValidAirportType(AirportType type);
/**
* Checks whether the given tile is actually a tile with a hangar.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has a hangar.
*/
static bool IsHangarTile(TileIndex tile);
/**
* Checks whether the given tile is actually a tile with a airport.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has a airport.
*/
static bool IsAirportTile(TileIndex tile);
/**
* Check if a certain airport type is already available.
* @param type The type of airport to check.
*/
static bool AirportAvailable(AirportType type);
/**
* Get the width of this type of airport.
* @param type The type of airport.
* @return The width in tiles.
*/
static int32 GetAirportWidth(AirportType type);
/**
* Get the height of this type of airport.
* @param type The type of airport.
* @return The height in tiles.
*/
static int32 GetAirportHeight(AirportType type);
/**
* Get the coverage radius of this type of airport.
* @param type The type of airport.
* @return The radius in tiles.
*/
static int32 GetAirportCoverageRadius(AirportType type);
/**
* Get the number of hangars of the airport.
* @param tile Any tile of the airport.
* @pre AIMap::IsValidTile(tile).
* @return The number of hangars of the airport.
*/
static int32 GetNumHangars(TileIndex tile);
/**
* Get the first hanger tile of the airport.
* @param tile Any tile of the airport.
* @pre AIMap::IsValidTile(tile).
* @pre GetNumHangars(tile) > 0.
* @return The first hanger tile of the airport.
* @note Possible there are more hangars, but you won't be able to find them
* without walking over all the tiles of the airport and using
* IsHangarTile() on them.
*/
static TileIndex GetHangarOfAirport(TileIndex tile);
/**
* Builds a airport with tile at the topleft corner.
* @param tile The topleft corner of the airport.
* @param type The type of airport to build.
* @param join_adjacent When building next to an other station, don't create a new station when this flag is true.
* @pre AIMap::IsValidTile(tile).
* @pre AirportAvailable(type).
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @exception AIError::ERR_LOCAL_AUTHORITY_REFUSES
* @exception AIStation::ERR_STATION_TOO_LARGE
* @exception AIStation::ERR_STATION_TOO_CLOSE_TO_OTHER_STATION
* @return Whether the airport has been/can be build or not.
*/
static bool BuildAirport(TileIndex tile, AirportType type, bool join_adjacent);
/**
* Removes a airport.
* @param tile Any tile of the airport.
* @pre AIMap::IsValidTile(tile).
* @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the airport has been/can be removed or not.
*/
static bool RemoveAirport(TileIndex tile);
/**
* Get the AirportType of an existing airport.
* @param tile Any tile of the airport.
* @pre AITile::IsStationTile(tile).
* @pre AIStation::HasStationType(AIStation.GetStationID(tile), AIStation::STATION_AIRPORT).
* @return The AirportType of the airport.
*/
static AirportType GetAirportType(TileIndex tile);
/**
* Get the noise that will be added to the nearest town if an airport was
* built at this tile.
* @param tile The tile to check.
* @param type The AirportType to check.
* @return The TownID of the town closest to the tile.
* @note The noise will be added to the town with TownID AITile.GetClosestTown(tile).
*/
static int GetNoiseLevelIncrease(TileIndex tile, AirportType type);
};
#endif /* AI_AIRPORT_HPP */

@ -0,0 +1,57 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_airport.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AIAirport::AirportType GetParam(ForceType<AIAirport::AirportType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIAirport::AirportType)tmp; }
template <> int Return<AIAirport::AirportType>(HSQUIRRELVM vm, AIAirport::AirportType res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> AIAirport::PlaneType GetParam(ForceType<AIAirport::PlaneType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIAirport::PlaneType)tmp; }
template <> int Return<AIAirport::PlaneType>(HSQUIRRELVM vm, AIAirport::PlaneType res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AIAirport to be used as Squirrel parameter */
template <> AIAirport *GetParam(ForceType<AIAirport *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAirport *)instance; }
template <> AIAirport &GetParam(ForceType<AIAirport &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAirport *)instance; }
template <> const AIAirport *GetParam(ForceType<const AIAirport *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIAirport *)instance; }
template <> const AIAirport &GetParam(ForceType<const AIAirport &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIAirport *)instance; }
template <> int Return<AIAirport *>(HSQUIRRELVM vm, AIAirport *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIAirport", res, NULL, DefSQDestructorCallback<AIAirport>); return 1; }
}; // namespace SQConvert
void SQAIAirport_Register(Squirrel *engine) {
DefSQClass <AIAirport> SQAIAirport("AIAirport");
SQAIAirport.PreRegister(engine);
SQAIAirport.AddConstructor<void (AIAirport::*)(), 1>(engine, "x");
SQAIAirport.DefSQConst(engine, AIAirport::AT_SMALL, "AT_SMALL");
SQAIAirport.DefSQConst(engine, AIAirport::AT_LARGE, "AT_LARGE");
SQAIAirport.DefSQConst(engine, AIAirport::AT_METROPOLITAN, "AT_METROPOLITAN");
SQAIAirport.DefSQConst(engine, AIAirport::AT_INTERNATIONAL, "AT_INTERNATIONAL");
SQAIAirport.DefSQConst(engine, AIAirport::AT_COMMUTER, "AT_COMMUTER");
SQAIAirport.DefSQConst(engine, AIAirport::AT_INTERCON, "AT_INTERCON");
SQAIAirport.DefSQConst(engine, AIAirport::AT_HELIPORT, "AT_HELIPORT");
SQAIAirport.DefSQConst(engine, AIAirport::AT_HELISTATION, "AT_HELISTATION");
SQAIAirport.DefSQConst(engine, AIAirport::AT_HELIDEPOT, "AT_HELIDEPOT");
SQAIAirport.DefSQConst(engine, AIAirport::AT_INVALID, "AT_INVALID");
SQAIAirport.DefSQConst(engine, AIAirport::PT_HELICOPTER, "PT_HELICOPTER");
SQAIAirport.DefSQConst(engine, AIAirport::PT_SMALL_PLANE, "PT_SMALL_PLANE");
SQAIAirport.DefSQConst(engine, AIAirport::PT_BIG_PLANE, "PT_BIG_PLANE");
SQAIAirport.DefSQConst(engine, AIAirport::PT_INVALID, "PT_INVALID");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetClassName, "GetClassName", 1, "x");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::IsValidAirportType, "IsValidAirportType", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::IsHangarTile, "IsHangarTile", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::IsAirportTile, "IsAirportTile", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::AirportAvailable, "AirportAvailable", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetAirportWidth, "GetAirportWidth", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetAirportHeight, "GetAirportHeight", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetAirportCoverageRadius, "GetAirportCoverageRadius", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetNumHangars, "GetNumHangars", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetHangarOfAirport, "GetHangarOfAirport", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::BuildAirport, "BuildAirport", 4, "xiib");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::RemoveAirport, "RemoveAirport", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetAirportType, "GetAirportType", 2, "xi");
SQAIAirport.DefSQStaticMethod(engine, &AIAirport::GetNoiseLevelIncrease, "GetNoiseLevelIncrease", 3, "xii");
SQAIAirport.PostRegister(engine);
}

@ -0,0 +1,43 @@
/* $Id$ */
/** @file ai_base.cpp Implementation of AIBase. */
#include "ai_base.hpp"
#include "../../network/network.h"
#include "../../core/random_func.hpp"
/* static */ uint32 AIBase::Rand()
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandom();
return ::Random();
}
/* static */ uint32 AIBase::RandItem(int unused_param)
{
return AIBase::Rand();
}
/* static */ uint AIBase::RandRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandomRange(max);
return ::RandomRange(max);
}
/* static */ uint32 AIBase::RandRangeItem(int unused_param, uint max)
{
return AIBase::RandRange(max);
}
/* static */ bool AIBase::Chance(uint out, uint max)
{
return (uint16)Rand() <= (uint16)((65536 * out) / max);
}
/* static */ bool AIBase::ChanceItem(int unused_param, uint out, uint max)
{
return AIBase::Chance(out, max);
}

@ -0,0 +1,71 @@
/* $Id$ */
/** @file ai_base.hpp Everything to query basic things. */
#ifndef AI_BASE_HPP
#define AI_BASE_HPP
#include "ai_object.hpp"
/**
* Class that handles some basic functions.
*
* @note The random functions are not called Random and RandomRange, because
* RANDOM_DEBUG does some tricky stuff, which messes with those names.
* @note In MP we cannot use Random because that will cause desyncs (AIs are
* ran on the server only, not on all clients). This means that
* we use InteractiveRandom in MP. Rand() takes care of this for you.
*/
class AIBase : public AIObject {
public:
static const char *GetClassName() { return "AIBase"; }
/**
* Get a random value.
* @return A random value between 0 and MAX(uint32).
*/
static uint32 Rand();
/**
* Get a random value.
* @param unused_param This param is not used, but is needed to work with lists.
* @return A random value between 0 and MAX(uint32).
*/
static uint32 RandItem(int unused_param);
/**
* Get a random value in a range.
* @param max The first number this function will never return (the maximum it returns is max - 1).
* @return A random value between 0 .. max - 1.
*/
static uint RandRange(uint max);
/**
* Get a random value in a range.
* @param unused_param This param is not used, but is needed to work with lists.
* @param max The first number this function will never return (the maximum it returns is max - 1).
* @return A random value between 0 .. max - 1.
*/
static uint RandRangeItem(int unused_param, uint max);
/**
* Returns approximatelly 'out' times true when called 'max' times.
* After all, it is a random function.
* @param out How many times it should return true.
* @param max Out of this many times.
* @return True if the chance worked out.
*/
static bool Chance(uint out, uint max);
/**
* Returns approximatelly 'out' times true when called 'max' times.
* After all, it is a random function.
* @param unused_param This param is not used, but is needed to work with lists.
* @param out How many times it should return true.
* @param max Out of this many times.
* @return True if the chance worked out.
*/
static bool ChanceItem(int unused_param, uint out, uint max);
};
#endif /* AI_BASE_HPP */

@ -0,0 +1,29 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_base.hpp"
namespace SQConvert {
/* Allow AIBase to be used as Squirrel parameter */
template <> AIBase *GetParam(ForceType<AIBase *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBase *)instance; }
template <> AIBase &GetParam(ForceType<AIBase &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBase *)instance; }
template <> const AIBase *GetParam(ForceType<const AIBase *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBase *)instance; }
template <> const AIBase &GetParam(ForceType<const AIBase &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBase *)instance; }
template <> int Return<AIBase *>(HSQUIRRELVM vm, AIBase *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIBase", res, NULL, DefSQDestructorCallback<AIBase>); return 1; }
}; // namespace SQConvert
void SQAIBase_Register(Squirrel *engine) {
DefSQClass <AIBase> SQAIBase("AIBase");
SQAIBase.PreRegister(engine);
SQAIBase.AddConstructor<void (AIBase::*)(), 1>(engine, "x");
SQAIBase.DefSQStaticMethod(engine, &AIBase::GetClassName, "GetClassName", 1, "x");
SQAIBase.DefSQStaticMethod(engine, &AIBase::Rand, "Rand", 1, "x");
SQAIBase.DefSQStaticMethod(engine, &AIBase::RandItem, "RandItem", 2, "xi");
SQAIBase.DefSQStaticMethod(engine, &AIBase::RandRange, "RandRange", 2, "xi");
SQAIBase.DefSQStaticMethod(engine, &AIBase::RandRangeItem, "RandRangeItem", 3, "xii");
SQAIBase.DefSQStaticMethod(engine, &AIBase::Chance, "Chance", 3, "xii");
SQAIBase.DefSQStaticMethod(engine, &AIBase::ChanceItem, "ChanceItem", 4, "xiii");
SQAIBase.PostRegister(engine);
}

@ -0,0 +1,177 @@
/* $Id$ */
/** @file ai_bridge.cpp Implementation of AIBridge. */
#include "ai_bridge.hpp"
#include "ai_rail.hpp"
#include "../ai_instance.hpp"
#include "../../openttd.h"
#include "../../bridge_map.h"
#include "../../strings_func.h"
#include "../../core/alloc_func.hpp"
#include "../../economy_func.h"
#include "../../settings_type.h"
#include "../../road_map.h"
#include "table/strings.h"
/* static */ bool AIBridge::IsValidBridge(BridgeID bridge_id)
{
return bridge_id < MAX_BRIDGES;
}
/* static */ bool AIBridge::IsBridgeTile(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
return ::IsBridgeTile(tile);
}
static void _DoCommandReturnBuildBridge2(class AIInstance *instance)
{
if (!AIBridge::_BuildBridgeRoad2()) {
AIObject::SetLastCommandRes(false);
AIInstance::DoCommandReturn(instance);
return;
}
/* This can never happen, as in test-mode this callback is never executed,
* and in execute-mode, the other callback is called. */
NOT_REACHED();
}
static void _DoCommandReturnBuildBridge1(class AIInstance *instance)
{
if (!AIBridge::_BuildBridgeRoad1()) {
AIObject::SetLastCommandRes(false);
AIInstance::DoCommandReturn(instance);
return;
}
/* This can never happen, as in test-mode this callback is never executed,
* and in execute-mode, the other callback is called. */
NOT_REACHED();
}
/* static */ bool AIBridge::BuildBridge(AIVehicle::VehicleType vehicle_type, BridgeID bridge_id, TileIndex start, TileIndex end)
{
EnforcePrecondition(false, start != end);
EnforcePrecondition(false, ::IsValidTile(start) && ::IsValidTile(end));
EnforcePrecondition(false, TileX(start) == TileX(end) || TileY(start) == TileY(end));
EnforcePrecondition(false, vehicle_type == AIVehicle::VEHICLE_ROAD || vehicle_type == AIVehicle::VEHICLE_RAIL || vehicle_type == AIVehicle::VEHICLE_WATER);
EnforcePrecondition(false, vehicle_type != AIVehicle::VEHICLE_RAIL || AIRail::IsRailTypeAvailable(AIRail::GetCurrentRailType()));
uint type = 0;
switch (vehicle_type) {
case AIVehicle::VEHICLE_ROAD:
type |= (TRANSPORT_ROAD << 15);
type |= (RoadTypeToRoadTypes((::RoadType)AIObject::GetRoadType()) << 8);
break;
case AIVehicle::VEHICLE_RAIL:
type |= (TRANSPORT_RAIL << 15);
type |= (AIRail::GetCurrentRailType() << 8);
break;
case AIVehicle::VEHICLE_WATER:
type |= (TRANSPORT_WATER << 15);
break;
default: NOT_REACHED();
}
/* For rail and water we do nothing special */
if (vehicle_type == AIVehicle::VEHICLE_RAIL || vehicle_type == AIVehicle::VEHICLE_WATER) {
return AIObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE);
}
AIObject::SetCallbackVariable(0, start);
if (!AIObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, NULL, &_DoCommandReturnBuildBridge1)) return false;
/* In case of test-mode, test if we can build both road pieces */
return _BuildBridgeRoad1();
}
/* static */ bool AIBridge::_BuildBridgeRoad1()
{
/* Build the piece of road on the 'start' side of the bridge */
TileIndex end = AIObject::GetCallbackVariable(0);
TileIndex start = AIBridge::GetOtherBridgeEnd(end);
DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW));
DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
if (!AIObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &_DoCommandReturnBuildBridge2)) return false;
/* In case of test-mode, test the other road piece too */
return _BuildBridgeRoad2();
}
/* static */ bool AIBridge::_BuildBridgeRoad2()
{
/* Build the piece of road on the 'end' side of the bridge */
TileIndex end = AIObject::GetCallbackVariable(0);
TileIndex start = AIBridge::GetOtherBridgeEnd(end);
DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW));
DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
return AIObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD);
}
/* static */ bool AIBridge::RemoveBridge(TileIndex tile)
{
EnforcePrecondition(false, IsBridgeTile(tile));
return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
}
/* static */ const char *AIBridge::GetName(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return NULL;
static const int len = 64;
char *bridge_name = MallocT<char>(len);
::GetString(bridge_name, ::GetBridgeSpec(bridge_id)->transport_name[0], &bridge_name[len - 1]);
return bridge_name;
}
/* static */ int32 AIBridge::GetMaxSpeed(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return ::GetBridgeSpec(bridge_id)->speed;
}
/* static */ Money AIBridge::GetPrice(BridgeID bridge_id, uint length)
{
if (!IsValidBridge(bridge_id)) return -1;
return length * _price.build_bridge * ::GetBridgeSpec(bridge_id)->price >> 8;
}
/* static */ int32 AIBridge::GetMaxLength(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
uint max = ::GetBridgeSpec(bridge_id)->max_length;
if (max >= 16 && _settings_game.construction.longbridges) max = 100;
return max + 2;
}
/* static */ int32 AIBridge::GetMinLength(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return ::GetBridgeSpec(bridge_id)->min_length + 2;
}
/* static */ int32 AIBridge::GetYearAvailable(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return ::GetBridgeSpec(bridge_id)->avail_year;
}
/* static */ TileIndex AIBridge::GetOtherBridgeEnd(TileIndex tile)
{
if (!::IsValidTile(tile)) return INVALID_TILE;
if (!IsBridgeTile(tile)) return INVALID_TILE;
return ::GetOtherBridgeEnd(tile);
}

@ -0,0 +1,164 @@
/* $Id$ */
/** @file ai_bridge.hpp Everything to query and build bridges. */
#ifndef AI_BRIDGE_HPP
#define AI_BRIDGE_HPP
#include "ai_object.hpp"
#include "ai_vehicle.hpp"
#include "ai_error.hpp"
/**
* Class that handles all bridge related functions.
*/
class AIBridge : public AIObject {
public:
/**
* All bridge related error messages.
*/
enum ErrorMessages {
/** Base for bridge related errors */
ERR_BRIDGE_BASE = AIError::ERR_CAT_BRIDGE << AIError::ERR_CAT_BIT_SIZE,
/**
* The bridge you want to build is not available yet,
* or it is not available for the requested length.
*/
ERR_BRIDGE_TYPE_UNAVAILABLE, // [STR_5015_CAN_T_BUILD_BRIDGE_HERE]
/** One (or more) of the bridge head(s) ends in water. */
ERR_BRIDGE_CANNOT_END_IN_WATER, // [STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH]
/** The bride heads need to be on the same height */
ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, // [STR_BRIDGEHEADS_NOT_SAME_HEIGHT]
};
static const char *GetClassName() { return "AIBridge"; }
/**
* Checks whether the given bridge type is valid.
* @param bridge_id The bridge to check.
* @return True if and only if the bridge type is valid.
*/
static bool IsValidBridge(BridgeID bridge_id);
/**
* Checks whether the given tile is actually a bridge start or end tile.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile is the beginning or end of a bridge.
*/
static bool IsBridgeTile(TileIndex tile);
/**
* Get the name of a bridge.
* @param bridge_id The bridge to get the name of.
* @pre IsValidBridge(bridge_id).
* @return The name the bridge has.
*/
static const char *GetName(BridgeID bridge_id);
/**
* Get the maximum speed of a bridge (in km/h).
* @param bridge_id The bridge to get the maximum speed of.
* @pre IsValidBridge(bridge_id).
* @return The maximum speed the bridge has.
*/
static int32 GetMaxSpeed(BridgeID bridge_id);
/**
* Get the new cost of a bridge.
* @param bridge_id The bridge to get the new cost of.
* @param length The length of the bridge.
* @pre IsValidBridge(bridge_id).
* @return The new cost the bridge has.
*/
static Money GetPrice(BridgeID bridge_id, uint length);
/**
* Get the maximum length of a bridge.
* @param bridge_id The bridge to get the maximum length of.
* @pre IsValidBridge(bridge_id).
* @returns The maximum length the bridge has.
*/
static int32 GetMaxLength(BridgeID bridge_id);
/**
* Get the minimum length of a bridge.
* @param bridge_id The bridge to get the minimum length of.
* @pre IsValidBridge(bridge_id).
* @returns The minimum length the bridge has.
*/
static int32 GetMinLength(BridgeID bridge_id);
/**
* Get the year in which a bridge becomes available.
* @param bridge_id The bridge to get the year of availability of.
* @pre IsValidBridge(bridge_id).
* @returns The year of availability the bridge has.
* @note Years are like 2010, -10 (10 B.C.), 1950, ..
*/
static int32 GetYearAvailable(BridgeID bridge_id);
#ifndef DOXYGEN_SKIP
/**
* Internal function to help BuildBridge in case of road.
*/
static bool _BuildBridgeRoad1();
/**
* Internal function to help BuildBridge in case of road.
*/
static bool _BuildBridgeRoad2();
#endif
/**
* Build a bridge from one tile to the other.
* As an extra for road, this functions builds two half-pieces of road on
* each end of the bridge, making it easier for you to connect it to your
* network.
* @param vehicle_type The vehicle-type of bridge to build.
* @param bridge_id The bridge-type to build.
* @param start Where to start the bridge.
* @param end Where to end the bridge.
* @pre AIMap::IsValidTile(start).
* @pre AIMap::IsValidTile(end).
* @pre 'start' and 'end' are in a straight line, i.e.
* AIMap::GetTileX(start) == AIMap::GetTileX(end) or
* AIMap::GetTileY(start) == AIMap::GetTileY(end).
* @pre vehicle_type == AIVehicle::VEHICLE_ROAD || (vehicle_type == AIVehicle::VEHICLE_RAIL &&
* AIRail::IsRailTypeAvailable(AIRail::GetCurrentRailType())) || vehicle_type == AIVehicle::VEHICLE_WATER.
* @exception AIError::ERR_ALREADY_BUILT
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_LAND_SLOPED_WRONG
* @exception AIError::ERR_VEHICLE_IN_THE_WAY
* @exception AIBridge::ERR_BRIDGE_TYPE_UNAVAILABLE
* @exception AIBridge::ERR_BRIDGE_CANNOT_END_IN_WATER
* @exception AIBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT
* @return Whether the bridge has been/can be build or not.
* @note No matter if the road pieces were build or not, if building the
* bridge succeeded, this function returns true.
*/
static bool BuildBridge(AIVehicle::VehicleType vehicle_type, BridgeID bridge_id, TileIndex start, TileIndex end);
/**
* Removes a bridge, by executing it on either the start or end tile.
* @param tile An end or start tile of the bridge.
* @pre AIMap::IsValidTile(tile).
* @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the bridge has been/can be removed or not.
*/
static bool RemoveBridge(TileIndex tile);
/**
* Get the tile that is on the other end of a bridge starting at tile.
* @param tile The tile that is an end of a bridge.
* @pre AIMap::IsValidTile(tile).
* @pre IsBridgeTile(tile).
* @return The TileIndex that is the other end of the bridge.
*/
static TileIndex GetOtherBridgeEnd(TileIndex tile);
};
#endif /* AI_BRIDGE_HPP */

@ -0,0 +1,51 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_bridge.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AIBridge::ErrorMessages GetParam(ForceType<AIBridge::ErrorMessages>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIBridge::ErrorMessages)tmp; }
template <> int Return<AIBridge::ErrorMessages>(HSQUIRRELVM vm, AIBridge::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AIBridge to be used as Squirrel parameter */
template <> AIBridge *GetParam(ForceType<AIBridge *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridge *)instance; }
template <> AIBridge &GetParam(ForceType<AIBridge &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridge *)instance; }
template <> const AIBridge *GetParam(ForceType<const AIBridge *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridge *)instance; }
template <> const AIBridge &GetParam(ForceType<const AIBridge &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridge *)instance; }
template <> int Return<AIBridge *>(HSQUIRRELVM vm, AIBridge *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIBridge", res, NULL, DefSQDestructorCallback<AIBridge>); return 1; }
}; // namespace SQConvert
void SQAIBridge_Register(Squirrel *engine) {
DefSQClass <AIBridge> SQAIBridge("AIBridge");
SQAIBridge.PreRegister(engine);
SQAIBridge.AddConstructor<void (AIBridge::*)(), 1>(engine, "x");
SQAIBridge.DefSQConst(engine, AIBridge::ERR_BRIDGE_BASE, "ERR_BRIDGE_BASE");
SQAIBridge.DefSQConst(engine, AIBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE");
SQAIBridge.DefSQConst(engine, AIBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER");
SQAIBridge.DefSQConst(engine, AIBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT");
AIError::RegisterErrorMap(STR_5015_CAN_T_BUILD_BRIDGE_HERE, AIBridge::ERR_BRIDGE_TYPE_UNAVAILABLE);
AIError::RegisterErrorMap(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH, AIBridge::ERR_BRIDGE_CANNOT_END_IN_WATER);
AIError::RegisterErrorMap(STR_BRIDGEHEADS_NOT_SAME_HEIGHT, AIBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT);
AIError::RegisterErrorMapString(AIBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE");
AIError::RegisterErrorMapString(AIBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER");
AIError::RegisterErrorMapString(AIBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetClassName, "GetClassName", 1, "x");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::IsValidBridge, "IsValidBridge", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::IsBridgeTile, "IsBridgeTile", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetName, "GetName", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetMaxSpeed, "GetMaxSpeed", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetPrice, "GetPrice", 3, "xii");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetMaxLength, "GetMaxLength", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetMinLength, "GetMinLength", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetYearAvailable, "GetYearAvailable", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::BuildBridge, "BuildBridge", 5, "xiiii");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::RemoveBridge, "RemoveBridge", 2, "xi");
SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetOtherBridgeEnd, "GetOtherBridgeEnd", 2, "xi");
SQAIBridge.PostRegister(engine);
}

@ -0,0 +1,25 @@
/* $Id$ */
/** @file ai_bridgelist.cpp Implementation of AIBridgeList and friends. */
#include "ai_bridgelist.hpp"
#include "ai_bridge.hpp"
#include "../../openttd.h"
#include "../../bridge.h"
#include "../../date_func.h"
AIBridgeList::AIBridgeList()
{
/* Add all bridges, no matter if they are available or not */
for (byte j = 0; j < MAX_BRIDGES; j++)
if (::GetBridgeSpec(j)->avail_year <= _cur_year)
this->AddItem(j);
}
AIBridgeList_Length::AIBridgeList_Length(uint length)
{
for (byte j = 0; j < MAX_BRIDGES; j++)
if (::GetBridgeSpec(j)->avail_year <= _cur_year)
if (length >= (uint)AIBridge::GetMinLength(j) && length <= (uint)AIBridge::GetMaxLength(j))
this->AddItem(j);
}

@ -0,0 +1,34 @@
/* $Id$ */
/** @file ai_bridgelist.hpp List all the bridges. */
#ifndef AI_BRIDGELIST_HPP
#define AI_BRIDGELIST_HPP
#include "ai_abstractlist.hpp"
/**
* Create a list of bridges.
* @ingroup AIList
*/
class AIBridgeList : public AIAbstractList {
public:
static const char *GetClassName() { return "AIBridgeList"; }
AIBridgeList();
};
/**
* Create a list of bridges that can be built on a specific length.
* @ingroup AIList
*/
class AIBridgeList_Length : public AIAbstractList {
public:
static const char *GetClassName() { return "AIBridgeList_Length"; }
/**
* @param length The length of the bridge you want to build.
*/
AIBridgeList_Length(uint length);
};
#endif /* AI_BRIDGELIST_HPP */

@ -0,0 +1,42 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_bridgelist.hpp"
namespace SQConvert {
/* Allow AIBridgeList to be used as Squirrel parameter */
template <> AIBridgeList *GetParam(ForceType<AIBridgeList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridgeList *)instance; }
template <> AIBridgeList &GetParam(ForceType<AIBridgeList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridgeList *)instance; }
template <> const AIBridgeList *GetParam(ForceType<const AIBridgeList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridgeList *)instance; }
template <> const AIBridgeList &GetParam(ForceType<const AIBridgeList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridgeList *)instance; }
template <> int Return<AIBridgeList *>(HSQUIRRELVM vm, AIBridgeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIBridgeList", res, NULL, DefSQDestructorCallback<AIBridgeList>); return 1; }
}; // namespace SQConvert
void SQAIBridgeList_Register(Squirrel *engine) {
DefSQClass <AIBridgeList> SQAIBridgeList("AIBridgeList");
SQAIBridgeList.PreRegister(engine, "AIAbstractList");
SQAIBridgeList.AddConstructor<void (AIBridgeList::*)(), 1>(engine, "x");
SQAIBridgeList.DefSQStaticMethod(engine, &AIBridgeList::GetClassName, "GetClassName", 1, "x");
SQAIBridgeList.PostRegister(engine);
}
namespace SQConvert {
/* Allow AIBridgeList_Length to be used as Squirrel parameter */
template <> AIBridgeList_Length *GetParam(ForceType<AIBridgeList_Length *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridgeList_Length *)instance; }
template <> AIBridgeList_Length &GetParam(ForceType<AIBridgeList_Length &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridgeList_Length *)instance; }
template <> const AIBridgeList_Length *GetParam(ForceType<const AIBridgeList_Length *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIBridgeList_Length *)instance; }
template <> const AIBridgeList_Length &GetParam(ForceType<const AIBridgeList_Length &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIBridgeList_Length *)instance; }
template <> int Return<AIBridgeList_Length *>(HSQUIRRELVM vm, AIBridgeList_Length *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIBridgeList_Length", res, NULL, DefSQDestructorCallback<AIBridgeList_Length>); return 1; }
}; // namespace SQConvert
void SQAIBridgeList_Length_Register(Squirrel *engine) {
DefSQClass <AIBridgeList_Length> SQAIBridgeList_Length("AIBridgeList_Length");
SQAIBridgeList_Length.PreRegister(engine, "AIAbstractList");
SQAIBridgeList_Length.AddConstructor<void (AIBridgeList_Length::*)(uint length), 2>(engine, "xi");
SQAIBridgeList_Length.DefSQStaticMethod(engine, &AIBridgeList_Length::GetClassName, "GetClassName", 1, "x");
SQAIBridgeList_Length.PostRegister(engine);
}

@ -0,0 +1,57 @@
/* $Id$ */
/** @file ai_cargo.cpp Implementation of AICargo. */
#include "ai_cargo.hpp"
#include "../../openttd.h"
#include "../../cargotype.h"
#include "../../economy_func.h"
#include "../../core/alloc_func.hpp"
#include "../../core/bitmath_func.hpp"
#include "../../newgrf_cargo.h"
/* static */ bool AICargo::IsValidCargo(CargoID cargo_type)
{
return (cargo_type < NUM_CARGO && ::GetCargo(cargo_type)->IsValid());
}
/* static */ const char *AICargo::GetCargoLabel(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return NULL;
const CargoSpec *cargo = ::GetCargo(cargo_type);
/* cargo->label is a uint32 packing a 4 character non-terminated string,
* like "PASS", "COAL", "OIL_". New ones can be defined by NewGRFs */
char *cargo_label = MallocT<char>(sizeof(cargo->label) + 1);
for (uint i = 0; i < sizeof(cargo->label); i++) {
cargo_label[i] = GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8);
}
cargo_label[sizeof(cargo->label)] = '\0';
return cargo_label;
}
/* static */ bool AICargo::IsFreight(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return false;
const CargoSpec *cargo = ::GetCargo(cargo_type);
return cargo->is_freight;
}
/* static */ bool AICargo::HasCargoClass(CargoID cargo_type, CargoClass cargo_class)
{
if (!IsValidCargo(cargo_type)) return false;
return ::IsCargoInClass(cargo_type, (::CargoClass)cargo_class);
}
/* static */ AICargo::TownEffect AICargo::GetTownEffect(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return TE_NONE;
return (AICargo::TownEffect)GetCargo(cargo_type)->town_effect;
}
/* static */ Money AICargo::GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit)
{
if (!IsValidCargo(cargo_type)) return -1;
return ::GetTransportedGoodsIncome(1, distance, Clamp(days_in_transit * 2 / 5, 0, 255), cargo_type);
}

@ -0,0 +1,94 @@
/* $Id$ */
/** @file ai_cargo.hpp Everything to query cargos. */
#ifndef AI_CARGO_HPP
#define AI_CARGO_HPP
#include "ai_object.hpp"
/**
* Class that handles all cargo related functions.
*/
class AICargo : public AIObject {
public:
static const char *GetClassName() { return "AICargo"; }
/**
* The classes of cargo (from newgrf_cargo.h).
*/
enum CargoClass {
CC_PASSENGERS = 1 << 0, ///< Passengers
CC_MAIL = 1 << 1, ///< Mail
CC_EXPRESS = 1 << 2, ///< Express cargo (Goods, Food, Candy, but also possible for passengers)
CC_ARMOURED = 1 << 3, ///< Armoured cargo (Valuables, Gold, Diamonds)
CC_BULK = 1 << 4, ///< Bulk cargo (Coal, Grain etc., Ores, Fruit)
CC_PIECE_GOODS = 1 << 5, ///< Piece goods (Livestock, Wood, Steel, Paper)
CC_LIQUID = 1 << 6, ///< Liquids (Oil, Water, Rubber)
CC_REFRIGERATED = 1 << 7, ///< Refrigerated cargo (Food, Fruit)
CC_HAZARDOUS = 1 << 8, ///< Hazardous cargo (Nuclear Fuel, Explosives, etc.)
CC_COVERED = 1 << 9, ///< Covered/Sheltered Freight (Transporation in Box Vans, Silo Wagons, etc.)
};
/**
* The effects a cargo can have on a town.
*/
enum TownEffect {
TE_NONE = 0, ///< This cargo has no effect on a town
TE_PASSENGERS = 1, ///< This cargo supplies passengers to a town
TE_MAIL = 2, ///< This cargo supplies mail to a town
TE_GOODS = 3, ///< This cargo supplies goods to a town
TE_WATER = 4, ///< This cargo supplies water to a town
TE_FOOD = 5, ///< This cargo supplies food to a town
};
/**
* Checks whether the given cargo type is valid.
* @param cargo_type The cargo to check.
* @return True if and only if the cargo type is valid.
*/
static bool IsValidCargo(CargoID cargo_type);
/**
* Gets the string representation of the cargo label.
* @param cargo_type The cargo to get the string representation of.
* @return The cargo label.
* @note Never use this to check if it is a certain cargo. NewGRF can
* redefine all of the names.
*/
static const char *GetCargoLabel(CargoID cargo_type);
/**
* Checks whether the give cargo is a freight or not.
* @param cargo_type The cargo to check on.
* @return True if and only if the cargo is freight.
*/
static bool IsFreight(CargoID cargo_type);
/**
* Check if this cargo is in the requested cargo class.
* @param cargo_type The cargo to check on.
* @param cargo_class The class to check for.
* @return True if and only if the cargo is in the cargo class.
*/
static bool HasCargoClass(CargoID cargo_type, CargoClass cargo_class);
/**
* Get the effect this cargo has on a town.
* @param cargo_type The cargo to check on.
* @return The effect this cargo has on a town, or TE_NONE if it has no effect.
*/
static TownEffect GetTownEffect(CargoID cargo_type);
/**
* Get the income for transporting a piece of cargo over the
* given distance within the specified time.
* @param cargo_type The cargo to transport.
* @param distance The distance the cargo travels from begin to end.
* @param days_in_transit Amount of (game) days the cargo is in transit. The max value of this variable is 637. Any value higher returns the same as 637 would.
* @return The amount of money that would be earned by this trip.
*/
static Money GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit);
};
#endif /* AI_CARGO_HPP */

@ -0,0 +1,52 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_cargo.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AICargo::CargoClass GetParam(ForceType<AICargo::CargoClass>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AICargo::CargoClass)tmp; }
template <> int Return<AICargo::CargoClass>(HSQUIRRELVM vm, AICargo::CargoClass res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> AICargo::TownEffect GetParam(ForceType<AICargo::TownEffect>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AICargo::TownEffect)tmp; }
template <> int Return<AICargo::TownEffect>(HSQUIRRELVM vm, AICargo::TownEffect res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AICargo to be used as Squirrel parameter */
template <> AICargo *GetParam(ForceType<AICargo *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargo *)instance; }
template <> AICargo &GetParam(ForceType<AICargo &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargo *)instance; }
template <> const AICargo *GetParam(ForceType<const AICargo *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargo *)instance; }
template <> const AICargo &GetParam(ForceType<const AICargo &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargo *)instance; }
template <> int Return<AICargo *>(HSQUIRRELVM vm, AICargo *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AICargo", res, NULL, DefSQDestructorCallback<AICargo>); return 1; }
}; // namespace SQConvert
void SQAICargo_Register(Squirrel *engine) {
DefSQClass <AICargo> SQAICargo("AICargo");
SQAICargo.PreRegister(engine);
SQAICargo.AddConstructor<void (AICargo::*)(), 1>(engine, "x");
SQAICargo.DefSQConst(engine, AICargo::CC_PASSENGERS, "CC_PASSENGERS");
SQAICargo.DefSQConst(engine, AICargo::CC_MAIL, "CC_MAIL");
SQAICargo.DefSQConst(engine, AICargo::CC_EXPRESS, "CC_EXPRESS");
SQAICargo.DefSQConst(engine, AICargo::CC_ARMOURED, "CC_ARMOURED");
SQAICargo.DefSQConst(engine, AICargo::CC_BULK, "CC_BULK");
SQAICargo.DefSQConst(engine, AICargo::CC_PIECE_GOODS, "CC_PIECE_GOODS");
SQAICargo.DefSQConst(engine, AICargo::CC_LIQUID, "CC_LIQUID");
SQAICargo.DefSQConst(engine, AICargo::CC_REFRIGERATED, "CC_REFRIGERATED");
SQAICargo.DefSQConst(engine, AICargo::CC_HAZARDOUS, "CC_HAZARDOUS");
SQAICargo.DefSQConst(engine, AICargo::CC_COVERED, "CC_COVERED");
SQAICargo.DefSQConst(engine, AICargo::TE_NONE, "TE_NONE");
SQAICargo.DefSQConst(engine, AICargo::TE_PASSENGERS, "TE_PASSENGERS");
SQAICargo.DefSQConst(engine, AICargo::TE_MAIL, "TE_MAIL");
SQAICargo.DefSQConst(engine, AICargo::TE_GOODS, "TE_GOODS");
SQAICargo.DefSQConst(engine, AICargo::TE_WATER, "TE_WATER");
SQAICargo.DefSQConst(engine, AICargo::TE_FOOD, "TE_FOOD");
SQAICargo.DefSQStaticMethod(engine, &AICargo::GetClassName, "GetClassName", 1, "x");
SQAICargo.DefSQStaticMethod(engine, &AICargo::IsValidCargo, "IsValidCargo", 2, "xi");
SQAICargo.DefSQStaticMethod(engine, &AICargo::GetCargoLabel, "GetCargoLabel", 2, "xi");
SQAICargo.DefSQStaticMethod(engine, &AICargo::IsFreight, "IsFreight", 2, "xi");
SQAICargo.DefSQStaticMethod(engine, &AICargo::HasCargoClass, "HasCargoClass", 3, "xii");
SQAICargo.DefSQStaticMethod(engine, &AICargo::GetTownEffect, "GetTownEffect", 2, "xi");
SQAICargo.DefSQStaticMethod(engine, &AICargo::GetCargoIncome, "GetCargoIncome", 4, "xiii");
SQAICargo.PostRegister(engine);
}

@ -0,0 +1,46 @@
/* $Id$ */
/** @file ai_cargolist.cpp Implementation of AICargoList and friends. */
#include "ai_cargolist.hpp"
#include "ai_industry.hpp"
#include "../../openttd.h"
#include "../../cargotype.h"
#include "../../tile_type.h"
#include "../../industry.h"
AICargoList::AICargoList()
{
for (byte i = 0; i < NUM_CARGO; i++) {
const CargoSpec *c = ::GetCargo(i);
if (c->IsValid()) {
this->AddItem(i);
}
}
}
AICargoList_IndustryAccepting::AICargoList_IndustryAccepting(IndustryID industry_id)
{
if (!AIIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::GetIndustry(industry_id);
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID cargo_id = ind->accepts_cargo[i];
if (cargo_id != CT_INVALID) {
this->AddItem(cargo_id);
}
}
}
AICargoList_IndustryProducing::AICargoList_IndustryProducing(IndustryID industry_id)
{
if (!AIIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::GetIndustry(industry_id);
for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
CargoID cargo_id = ind->produced_cargo[i];
if (cargo_id != CT_INVALID) {
this->AddItem(cargo_id);
}
}
}

@ -0,0 +1,48 @@
/* $Id$ */
/** @file ai_cargolist.hpp List all the cargos. */
#ifndef AI_CARGOLIST_HPP
#define AI_CARGOLIST_HPP
#include "ai_abstractlist.hpp"
/**
* Creates a list of cargos that can be produced in the current game.
* @ingroup AIList
*/
class AICargoList : public AIAbstractList {
public:
static const char *GetClassName() { return "AICargoList"; }
AICargoList();
};
/**
* Creates a list of cargos that the given industry accepts.
* @ingroup AIList
*/
class AICargoList_IndustryAccepting : public AIAbstractList {
public:
static const char *GetClassName() { return "AICargoList_IndustryAccepting"; }
/**
* @param industry_id The industry to get the list of cargos it accepts from.
*/
AICargoList_IndustryAccepting(IndustryID industry_id);
};
/**
* Creates a list of cargos that the given industry can produce.
* @ingroup AIList
*/
class AICargoList_IndustryProducing : public AIAbstractList {
public:
static const char *GetClassName() { return "AICargoList_IndustryProducing"; }
/**
* @param industry_id The industry to get the list of cargos it produces from.
*/
AICargoList_IndustryProducing(IndustryID industry_id);
};
#endif /* AI_CARGOLIST_HPP */

@ -0,0 +1,61 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_cargolist.hpp"
namespace SQConvert {
/* Allow AICargoList to be used as Squirrel parameter */
template <> AICargoList *GetParam(ForceType<AICargoList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList *)instance; }
template <> AICargoList &GetParam(ForceType<AICargoList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList *)instance; }
template <> const AICargoList *GetParam(ForceType<const AICargoList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList *)instance; }
template <> const AICargoList &GetParam(ForceType<const AICargoList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList *)instance; }
template <> int Return<AICargoList *>(HSQUIRRELVM vm, AICargoList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AICargoList", res, NULL, DefSQDestructorCallback<AICargoList>); return 1; }
}; // namespace SQConvert
void SQAICargoList_Register(Squirrel *engine) {
DefSQClass <AICargoList> SQAICargoList("AICargoList");
SQAICargoList.PreRegister(engine, "AIAbstractList");
SQAICargoList.AddConstructor<void (AICargoList::*)(), 1>(engine, "x");
SQAICargoList.DefSQStaticMethod(engine, &AICargoList::GetClassName, "GetClassName", 1, "x");
SQAICargoList.PostRegister(engine);
}
namespace SQConvert {
/* Allow AICargoList_IndustryAccepting to be used as Squirrel parameter */
template <> AICargoList_IndustryAccepting *GetParam(ForceType<AICargoList_IndustryAccepting *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList_IndustryAccepting *)instance; }
template <> AICargoList_IndustryAccepting &GetParam(ForceType<AICargoList_IndustryAccepting &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList_IndustryAccepting *)instance; }
template <> const AICargoList_IndustryAccepting *GetParam(ForceType<const AICargoList_IndustryAccepting *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList_IndustryAccepting *)instance; }
template <> const AICargoList_IndustryAccepting &GetParam(ForceType<const AICargoList_IndustryAccepting &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList_IndustryAccepting *)instance; }
template <> int Return<AICargoList_IndustryAccepting *>(HSQUIRRELVM vm, AICargoList_IndustryAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AICargoList_IndustryAccepting", res, NULL, DefSQDestructorCallback<AICargoList_IndustryAccepting>); return 1; }
}; // namespace SQConvert
void SQAICargoList_IndustryAccepting_Register(Squirrel *engine) {
DefSQClass <AICargoList_IndustryAccepting> SQAICargoList_IndustryAccepting("AICargoList_IndustryAccepting");
SQAICargoList_IndustryAccepting.PreRegister(engine, "AIAbstractList");
SQAICargoList_IndustryAccepting.AddConstructor<void (AICargoList_IndustryAccepting::*)(IndustryID industry_id), 2>(engine, "xi");
SQAICargoList_IndustryAccepting.DefSQStaticMethod(engine, &AICargoList_IndustryAccepting::GetClassName, "GetClassName", 1, "x");
SQAICargoList_IndustryAccepting.PostRegister(engine);
}
namespace SQConvert {
/* Allow AICargoList_IndustryProducing to be used as Squirrel parameter */
template <> AICargoList_IndustryProducing *GetParam(ForceType<AICargoList_IndustryProducing *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList_IndustryProducing *)instance; }
template <> AICargoList_IndustryProducing &GetParam(ForceType<AICargoList_IndustryProducing &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList_IndustryProducing *)instance; }
template <> const AICargoList_IndustryProducing *GetParam(ForceType<const AICargoList_IndustryProducing *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICargoList_IndustryProducing *)instance; }
template <> const AICargoList_IndustryProducing &GetParam(ForceType<const AICargoList_IndustryProducing &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICargoList_IndustryProducing *)instance; }
template <> int Return<AICargoList_IndustryProducing *>(HSQUIRRELVM vm, AICargoList_IndustryProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AICargoList_IndustryProducing", res, NULL, DefSQDestructorCallback<AICargoList_IndustryProducing>); return 1; }
}; // namespace SQConvert
void SQAICargoList_IndustryProducing_Register(Squirrel *engine) {
DefSQClass <AICargoList_IndustryProducing> SQAICargoList_IndustryProducing("AICargoList_IndustryProducing");
SQAICargoList_IndustryProducing.PreRegister(engine, "AIAbstractList");
SQAICargoList_IndustryProducing.AddConstructor<void (AICargoList_IndustryProducing::*)(IndustryID industry_id), 2>(engine, "xi");
SQAICargoList_IndustryProducing.DefSQStaticMethod(engine, &AICargoList_IndustryProducing::GetClassName, "GetClassName", 1, "x");
SQAICargoList_IndustryProducing.PostRegister(engine);
}

@ -0,0 +1,200 @@
/* $Id$ */
/** @file ai_company.cpp Implementation of AICompany. */
#include "ai_company.hpp"
#include "ai_error.hpp"
#include "ai_log.hpp"
#include "../../openttd.h"
#include "../../command_func.h"
#include "../../company_func.h"
#include "../../company_base.h"
#include "../../economy_func.h"
#include "../../strings_func.h"
#include "../../tile_map.h"
#include "../../variables.h"
#include "../../core/alloc_func.hpp"
#include "../../string_func.h"
#include "table/strings.h"
/* static */ AICompany::CompanyID AICompany::ResolveCompanyID(AICompany::CompanyID company)
{
if (company == MY_COMPANY) return (CompanyID)((byte)_current_company);
return ::IsValidCompanyID((::CompanyID)company) ? company : INVALID_COMPANY;
}
/* static */ bool AICompany::IsMine(AICompany::CompanyID company)
{
return ResolveCompanyID(company) == ResolveCompanyID(MY_COMPANY);
}
/* static */ bool AICompany::SetCompanyName(const char *name)
{
AILog::Error("AICompany::SetCompanyName is obsolete. Use AICompany::SetName instead.");
return AICompany::SetName(name);
}
/* static */ bool AICompany::SetName(const char *name)
{
EnforcePrecondition(false, !::StrEmpty(name));
EnforcePreconditionCustomError(false, ::strlen(name) < MAX_LENGTH_COMPANY_NAME_BYTES, AIError::ERR_PRECONDITION_STRING_TOO_LONG);
return AIObject::DoCommand(0, 0, 0, CMD_RENAME_COMPANY, name);
}
/* static */ const char *AICompany::GetCompanyName(AICompany::CompanyID company)
{
AILog::Error("AICompany::GetCompanyName is obsolete. Use AICompany::GetName instead.");
return AICompany::GetName(company);
}
/* static */ const char *AICompany::GetName(AICompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return NULL;
static const int len = 64;
char *company_name = MallocT<char>(len);
::SetDParam(0, company);
::GetString(company_name, STR_COMPANY_NAME, &company_name[len - 1]);
return company_name;
}
/* static */ bool AICompany::SetPresidentName(const char *name)
{
EnforcePrecondition(false, !::StrEmpty(name));
return AIObject::DoCommand(0, 0, 0, CMD_RENAME_PRESIDENT, name);
}
/* static */ const char *AICompany::GetPresidentName(AICompany::CompanyID company)
{
company = ResolveCompanyID(company);
static const int len = 64;
char *president_name = MallocT<char>(len);
if (company != INVALID_COMPANY) {
::SetDParam(0, company);
::GetString(president_name, STR_PRESIDENT_NAME, &president_name[len - 1]);
} else {
*president_name = '\0';
}
return president_name;
}
/* static */ Money AICompany::GetCompanyValue(AICompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return -1;
return ::CalculateCompanyValue(::GetCompany((CompanyID)company));
}
/* static */ Money AICompany::GetBankBalance(AICompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return -1;
return ::GetCompany((CompanyID)company)->money;
}
/* static */ Money AICompany::GetLoanAmount()
{
return ::GetCompany(_current_company)->current_loan;
}
/* static */ Money AICompany::GetMaxLoanAmount()
{
return _economy.max_loan;
}
/* static */ Money AICompany::GetLoanInterval()
{
return LOAN_INTERVAL;
}
/* static */ bool AICompany::SetLoanAmount(int32 loan)
{
EnforcePrecondition(false, loan >= 0);
EnforcePrecondition(false, (loan % GetLoanInterval()) == 0);
EnforcePrecondition(false, loan <= GetMaxLoanAmount());
EnforcePrecondition(false, (loan - GetLoanAmount() + GetBankBalance(MY_COMPANY)) >= 0);
if (loan == GetLoanAmount()) return true;
return AIObject::DoCommand(0,
abs(loan - GetLoanAmount()), 2,
(loan > GetLoanAmount()) ? CMD_INCREASE_LOAN : CMD_DECREASE_LOAN);
}
/* static */ bool AICompany::SetMinimumLoanAmount(int32 loan)
{
EnforcePrecondition(false, loan >= 0);
int32 over_interval = loan % GetLoanInterval();
if (over_interval != 0) loan += GetLoanInterval() - over_interval;
EnforcePrecondition(false, loan <= GetMaxLoanAmount());
SetLoanAmount(loan);
return GetLoanAmount() == loan;
}
/* static */ bool AICompany::BuildCompanyHQ(TileIndex tile)
{
EnforcePrecondition(false, ::IsValidTile(tile));
return AIObject::DoCommand(tile, 0, 0, CMD_BUILD_COMPANY_HQ);
}
/* static */ TileIndex AICompany::GetCompanyHQ(CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return INVALID_TILE;
TileIndex loc = ::GetCompany((CompanyID)company)->location_of_HQ;
return (loc == 0) ? INVALID_TILE : loc;
}
/* static */ bool AICompany::SetAutoRenewStatus(bool autorenew)
{
return AIObject::DoCommand(0, 0, autorenew ? 1 : 0, CMD_SET_AUTOREPLACE);
}
/* static */ bool AICompany::GetAutoRenewStatus(CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return false;
return ::GetCompany((CompanyID)company)->engine_renew;
}
/* static */ bool AICompany::SetAutoRenewMonths(int16 months)
{
return AIObject::DoCommand(0, 1, months, CMD_SET_AUTOREPLACE);
}
/* static */ int16 AICompany::GetAutoRenewMonths(CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return 0;
return ::GetCompany((CompanyID)company)->engine_renew_months;
}
/* static */ bool AICompany::SetAutoRenewMoney(uint32 money)
{
return AIObject::DoCommand(0, 2, money, CMD_SET_AUTOREPLACE);
}
/* static */ uint32 AICompany::GetAutoRenewMoney(CompanyID company)
{
company = ResolveCompanyID(company);
if (company == INVALID_COMPANY) return 0;
return ::GetCompany((CompanyID)company)->engine_renew_money;
}

@ -0,0 +1,214 @@
/* $Id$ */
/** @file ai_company.hpp Everything to query a company's financials and statistics or build company related buildings. */
#ifndef AI_COMPANY_HPP
#define AI_COMPANY_HPP
#include "ai_object.hpp"
/**
* Class that handles all company related functions.
*/
class AICompany : public AIObject {
public:
static const char *GetClassName() { return "AICompany"; }
/** Different constants related to CompanyID. */
enum CompanyID {
INVALID_COMPANY = -1, //!< An invalid company.
FIRST_COMPANY = 0, //!< The first available company.
LAST_COMPANY = 7, //!< The last available company.
MY_COMPANY = 8, //!< Constant that gets resolved to the correct company index for your company.
};
/**
* Resolved the given company index to the correct index for the company. If
* the company index was MY_COMPANY it will be resolved to the index of
* your company. If the company with the given index does not exist it will
* return INVALID_COMPANY.
* @param company The company index to resolve.
* @return The resolved company index.
*/
static CompanyID ResolveCompanyID(CompanyID company);
/**
* Check if a CompanyID is your CompanyID, to ease up checks.
* @param company The company index to check.
* @return True if and only if this company is your CompanyID.
*/
static bool IsMine(CompanyID company);
/**
* Obsolete, use AICompany::SetName instead.
*/
static bool SetCompanyName(const char *name);
/**
* Set the name of your company.
* @param name The new name of the company.
* @pre 'name' must have at least one character.
* @pre 'name' must have at most 30 characters.
* @exception AIError::ERR_NAME_IS_NOT_UNIQUE
* @return True if the name was changed.
*/
static bool SetName(const char *name);
/**
* Obsolete, use AICompany::GetName instead.
*/
static const char *GetCompanyName(CompanyID company);
/**
* Get the name of the given company.
* @param company The company to get the name for.
* @pre ResolveCompanyID(company) != INVALID_COMPANY
* @return The name of the given company.
*/
static const char *GetName(CompanyID company);
/**
* Set the name of your president.
* @param name The new name of the president.
* @pre 'name' must have at least one character.
* @exception AIError::ERR_NAME_IS_NOT_UNIQUE
* @return True if the name was changed.
*/
static bool SetPresidentName(const char *name);
/**
* Get the name of the president of the given company.
* @param company The company to get the president's name for.
* @pre ResolveCompanyID(company) != INVALID_COMPANY
* @return The name of the president of the given company.
*/
static const char *GetPresidentName(CompanyID company);
/**
* Sets the amount to loan.
* @param loan The amount to loan (multiplier of GetLoanInterval()).
* @pre 'loan' must be non-negative.
* @pre GetLoanInterval() must be a multiplier of GetLoanInterval().
* @pre 'loan' must be below GetMaxLoanAmount().
* @pre 'loan' - GetLoanAmount() + GetBankBalance() must be non-negative.
* @return True if the loan could be set to your requested amount.
*/
static bool SetLoanAmount(int32 loan);
/**
* Sets the minimum amount to loan, i.e. the given amount of loan rounded up.
* @param loan The amount to loan (any positive number).
* @pre 'loan' must be non-negative.
* @pre 'loan' must be below GetMaxLoanAmount().
* @return True if we could allocate a minimum of "loan" loan.
*/
static bool SetMinimumLoanAmount(int32 loan);
/**
* Gets the amount your company have loaned.
* @return The amount loaned money.
* @post The return value is always non-negative.
* @post GetLoanInterval() is always a multiplier of the return value.
*/
static Money GetLoanAmount();
/**
* Gets the maximum amount your company can loan.
* @return The maximum amount your company can loan.
* @post The return value is always non-negative.
* @post GetLoanInterval() is always a multiplier of the return value.
*/
static Money GetMaxLoanAmount();
/**
* Gets the interval/loan step.
* @return The loan step.
* @post Return value is always positive.
*/
static Money GetLoanInterval();
/**
* Gets the current value of the given company.
* @param company The company to get the company value of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY
* @return The current value of the given company.
*/
static Money GetCompanyValue(CompanyID company);
/**
* Gets the bank balance. In other words, the amount of money the given company can spent.
* @param company The company to get the bank balance of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY
* @return The actual bank balance.
*/
static Money GetBankBalance(CompanyID company);
/**
* Build your company's HQ on the given tile.
* @param tile The tile to build your HQ on, this tile is the most nothern tile of your HQ.
* @pre AIMap::IsValidTile(tile).
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @return True if the HQ could be build.
* @note An HQ can not be removed, only by water or rebuilding; If an HQ is
* build again, the old one is removed.
*/
static bool BuildCompanyHQ(TileIndex tile);
/**
* Return the location of a company's HQ.
* @param company The company the get the HQ of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY.
* @return The tile of the company's HQ, this tile is the most nothern tile of that HQ, or INVALID_TILE if there is no HQ yet.
*/
static TileIndex GetCompanyHQ(CompanyID company);
/**
* Set whether autorenew is enabled for your company.
* @param autorenew The new autorenew status.
* @return True if autorenew status has been modified.
*/
static bool SetAutoRenewStatus(bool autorenew);
/**
* Return whether autorenew is enabled for a company.
* @param company The company to get the autorenew status of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY.
* @return True if autorenew is enabled.
*/
static bool GetAutoRenewStatus(CompanyID company);
/**
* Set the number of months before/after max age to autorenew an engine for your company.
* @param months The new months between autorenew.
* @return True if autorenew months has been modified.
*/
static bool SetAutoRenewMonths(int16 months);
/**
* Return the number of months before/after max age to autorenew an engine for a company.
* @param company The company to get the autorenew months of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY.
* @return The months before/after max age of engine.
*/
static int16 GetAutoRenewMonths(CompanyID company);
/**
* Set the minimum money needed to autorenew an engine for your company.
* @param money The new minimum required money for autorenew to work.
* @return True if autorenew money has been modified.
*/
static bool SetAutoRenewMoney(uint32 money);
/**
* Return the minimum money needed to autorenew an engine for a company.
* @param company The company to get the autorenew money of.
* @pre ResolveCompanyID(company) != INVALID_COMPANY.
* @return The minimum required money for autorenew to work.
*/
static uint32 GetAutoRenewMoney(CompanyID company);
};
DECLARE_POSTFIX_INCREMENT(AICompany::CompanyID);
#endif /* AI_COMPANY_HPP */

@ -0,0 +1,55 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_company.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AICompany::CompanyID GetParam(ForceType<AICompany::CompanyID>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AICompany::CompanyID)tmp; }
template <> int Return<AICompany::CompanyID>(HSQUIRRELVM vm, AICompany::CompanyID res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AICompany to be used as Squirrel parameter */
template <> AICompany *GetParam(ForceType<AICompany *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICompany *)instance; }
template <> AICompany &GetParam(ForceType<AICompany &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICompany *)instance; }
template <> const AICompany *GetParam(ForceType<const AICompany *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AICompany *)instance; }
template <> const AICompany &GetParam(ForceType<const AICompany &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AICompany *)instance; }
template <> int Return<AICompany *>(HSQUIRRELVM vm, AICompany *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AICompany", res, NULL, DefSQDestructorCallback<AICompany>); return 1; }
}; // namespace SQConvert
void SQAICompany_Register(Squirrel *engine) {
DefSQClass <AICompany> SQAICompany("AICompany");
SQAICompany.PreRegister(engine);
SQAICompany.AddConstructor<void (AICompany::*)(), 1>(engine, "x");
SQAICompany.DefSQConst(engine, AICompany::INVALID_COMPANY, "INVALID_COMPANY");
SQAICompany.DefSQConst(engine, AICompany::FIRST_COMPANY, "FIRST_COMPANY");
SQAICompany.DefSQConst(engine, AICompany::LAST_COMPANY, "LAST_COMPANY");
SQAICompany.DefSQConst(engine, AICompany::MY_COMPANY, "MY_COMPANY");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetClassName, "GetClassName", 1, "x");
SQAICompany.DefSQStaticMethod(engine, &AICompany::ResolveCompanyID, "ResolveCompanyID", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::IsMine, "IsMine", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetCompanyName, "SetCompanyName", 2, "xs");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetName, "SetName", 2, "xs");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetCompanyName, "GetCompanyName", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetName, "GetName", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetPresidentName, "SetPresidentName", 2, "xs");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetPresidentName, "GetPresidentName", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetLoanAmount, "SetLoanAmount", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetMinimumLoanAmount, "SetMinimumLoanAmount", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetLoanAmount, "GetLoanAmount", 1, "x");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetMaxLoanAmount, "GetMaxLoanAmount", 1, "x");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetLoanInterval, "GetLoanInterval", 1, "x");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetCompanyValue, "GetCompanyValue", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetBankBalance, "GetBankBalance", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::BuildCompanyHQ, "BuildCompanyHQ", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetCompanyHQ, "GetCompanyHQ", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetAutoRenewStatus, "SetAutoRenewStatus", 2, "xb");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetAutoRenewStatus, "GetAutoRenewStatus", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetAutoRenewMonths, "SetAutoRenewMonths", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetAutoRenewMonths, "GetAutoRenewMonths", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::SetAutoRenewMoney, "SetAutoRenewMoney", 2, "xi");
SQAICompany.DefSQStaticMethod(engine, &AICompany::GetAutoRenewMoney, "GetAutoRenewMoney", 2, "xi");
SQAICompany.PostRegister(engine);
}

@ -0,0 +1,85 @@
/* $Id$ */
/** @file ai_controller.cpp Implementation of AIControler. */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../company_func.h"
#include "../../core/alloc_func.hpp"
#include "../../string_func.h"
#include "../../settings_type.h"
#include "../../company_base.h"
#include "../../saveload/saveload.h"
#include "table/strings.h"
#include "../ai.hpp"
#include "ai_controller.hpp"
#include "../ai_info.hpp"
#include "../ai_storage.hpp"
#include "../ai_instance.hpp"
#include "../ai_config.hpp"
#include "ai_log.hpp"
/* static */ void AIController::SetCommandDelay(int ticks)
{
if (ticks <= 0) return;
AIObject::SetDoCommandDelay(ticks);
}
/* static */ void AIController::Sleep(int ticks)
{
if (ticks <= 0) {
AILog::Warning("Sleep() value should be > 0. Assuming value 1.");
ticks = 1;
}
throw AI_VMSuspend(ticks, NULL);
}
/* static */ void AIController::Print(bool error_msg, const char *message)
{
AILog::Log(error_msg ? AILog::LOG_SQ_ERROR : AILog::LOG_SQ_INFO, message);
}
AIController::AIController() :
ticks(0),
loaded_library_count(0)
{
}
AIController::~AIController()
{
for (LoadedLibraryList::iterator iter = this->loaded_library.begin(); iter != this->loaded_library.end(); iter++) {
free((void *)(*iter).second);
free((void *)(*iter).first);
}
this->loaded_library.clear();
}
uint AIController::GetTick()
{
return this->ticks;
}
int AIController::GetSetting(const char *name)
{
return AIConfig::GetConfig(_current_company)->GetSetting(name);
}
bool AIController::LoadedLibrary(const char *library_name, int *next_number, char *fake_class_name, int fake_class_name_len)
{
LoadedLibraryList::iterator iter = this->loaded_library.find(library_name);
if (iter == this->loaded_library.end()) {
*next_number = ++this->loaded_library_count;
return false;
}
ttd_strlcpy(fake_class_name, (*iter).second, fake_class_name_len);
return true;
}
void AIController::AddLoadedLibrary(const char *library_name, const char *fake_class_name)
{
this->loaded_library[strdup(library_name)] = strdup(fake_class_name);
}

@ -0,0 +1,117 @@
/* $Id$ */
/** @file ai_controller.hpp The controller of the AI. */
#ifndef AI_CONTROLLER_HPP
#define AI_CONTROLLER_HPP
#include <map>
#ifndef AI_HPP
struct ltstr { bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; } };
#endif /* AI_HPP */
/**
* The Controller, the class each AI should extend. It creates the AI, makes
* sure the logic kicks in correctly, and that GetTick() has a valid value.
*/
class AIController {
friend class AIScanner;
friend class AIInstance;
public:
static const char *GetClassName() { return "AIController"; }
/**
* Initializer of the AIController.
*/
AIController();
/**
* Destructor of the AIController.
*/
~AIController();
/**
* This function is called to start your AI. Your AI starts here. If you
* return from this function, your AI dies, so make sure that doesn't
* happen.
* @note Cannot be called from within your AI.
*/
void Start();
/**
* Find at which tick your AI currently is.
* @return returns the current tick.
*/
uint GetTick();
/**
* Get the value of one of your settings you set via info.nut.
* @param name The name of the setting.
* @return the value for the setting, or -1 if the setting is not known.
*/
int GetSetting(const char *name);
/**
* Change the minimum amount of time the AI should be put in suspend mode
* when you execute a command. Normally in SP this is 1, and in MP it is
* what ever delay the server has been programmed to delay commands
* (normally between 1 and 5). To give a more 'real' effect to your AI,
* you can control that number here.
* @param ticks The minimum amount of ticks to wait.
* @pre Ticks should be positive. Too big values will influence performance of the AI.
* @note If the number is lower then the MP setting, the MP setting wins.
*/
static void SetCommandDelay(int ticks);
/**
* Sleep for X ticks. The code continues after this line when the X AI ticks
* are passed. Mind that an AI tick is different from in-game ticks and
* differ per AI speed.
* @param ticks the ticks to wait
* @pre ticks > 0.
* @post the value of GetTick() will be changed exactly 'ticks' in value after
* calling this.
*/
static void Sleep(int ticks);
/**
* When Squirrel triggers a print, this function is called.
* Squirrel calls this when 'print' is used, or when the script made an error.
* @param error_msg If true, it is a Squirrel error message.
* @param message The message Squirrel logged.
* @note Use AILog.Info/Warning/Error instead of 'print'.
*/
static void Print(bool error_msg, const char *message);
private:
typedef std::map<const char *, const char *, ltstr> LoadedLibraryList;
uint ticks;
LoadedLibraryList loaded_library;
int loaded_library_count;
/**
* Register all classes that are known inside the NoAI API.
*/
void RegisterClasses();
/**
* Check if a library is already loaded. If found, fake_class_name is filled
* with the fake class name as given via AddLoadedLibrary. If not found,
* next_number is set to the next number available for the fake namespace.
* @param library_name The library to check if already loaded.
* @param next_number The next available number for a library if not already loaded.
* @param fake_class_name The name the library has if already loaded.
* @param fake_class_name_len The maximum length of fake_class_name.
* @return True if the library is already loaded.
*/
bool LoadedLibrary(const char *library_name, int *next_number, char *fake_class_name, int fake_class_name_len);
/**
* Add a library as loaded.
*/
void AddLoadedLibrary(const char *library_name, const char *fake_class_name);
};
#endif /* AI_CONTROLLER_HPP */

@ -0,0 +1,12 @@
#include "ai_controller.hpp"
void SQAIController_Register(Squirrel *engine) {
DefSQClass <AIController> SQAIController("AIController");
SQAIController.PreRegister(engine);
SQAIController.DefSQMethod(engine, &AIController::GetTick, "GetTick", 1, "x");
SQAIController.DefSQStaticMethod(engine, &AIController::SetCommandDelay, "SetCommandDelay", 2, "xi");
SQAIController.DefSQStaticMethod(engine, &AIController::Sleep, "Sleep", 2, "xi");
SQAIController.DefSQStaticMethod(engine, &AIController::GetSetting, "GetSetting", 2, "xs");
SQAIController.DefSQStaticMethod(engine, &AIController::Print, "Print", 3, "xbs");
SQAIController.PostRegister(engine);
}

@ -0,0 +1,47 @@
/* $Id$ */
/** @file ai_date.cpp Implementation of AIDate. */
#include "ai_date.hpp"
#include "../../date_func.h"
/* static */ int32 AIDate::GetCurrentDate()
{
return ::_date;
}
/* static */ int32 AIDate::GetYear(int32 date)
{
if (date < 0) return -1;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
return ymd.year;
}
/* static */ int32 AIDate::GetMonth(int32 date)
{
if (date < 0) return -1;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
return ymd.month + 1;
}
/* static */ int32 AIDate::GetDayOfMonth(int32 date)
{
if (date < 0) return -1;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
return ymd.day;
}
/* static */ int32 AIDate::GetDate(int32 year, int32 month, int32 day_of_month)
{
if (month < 1 || month > 12) return -1;
if (day_of_month < 1 || day_of_month > 31) return -1;
if (year < 0 || year > MAX_YEAR) return -1;
return ::ConvertYMDToDate(year, month - 1, day_of_month);
}

@ -0,0 +1,64 @@
/* $Id$ */
/** @file ai_date.hpp Everything to query and manipulate date related information. */
#ifndef AI_DATE_HPP
#define AI_DATE_HPP
#include "ai_object.hpp"
/**
* Class that handles all date related (calculation) functions.
*
* @note Months and days of month are 1-based; the first month of the
* year is 1 and the first day of the month is also 1.
* @note Years are zero based; they start with the year 0.
* @note Dates can be used to determine the number of days between
* two different moments in time because they count the number
* of days since the year 0.
*/
class AIDate : public AIObject {
public:
static const char *GetClassName() { return "AIDate"; }
/**
* Get the current date.
* This is the number of days since epoch under the assumption that
* there is a leap year every 4 years, except when dividable by
* 100 but not by 400.
* @return The current date.
*/
static int32 GetCurrentDate();
/**
* Get the year of the given date.
* @param date The date to get the year of.
* @return The year.
*/
static int32 GetYear(int32 date);
/**
* Get the month of the given date.
* @param date The date to get the month of.
* @return The month.
*/
static int32 GetMonth(int32 date);
/**
* Get the day (of the month) of the given date.
* @param date The date to get the day of.
* @return The day.
*/
static int32 GetDayOfMonth(int32 date);
/**
* Get the date given a year, month and day of month.
* @param year The year of the to-be determined date.
* @param month The month of the to-be determined date.
* @param day_of_month The day of month of the to-be determined date.
* @return The date.
*/
static int32 GetDate(int32 year, int32 month, int32 day_of_month);
};
#endif /* AI_DATE_HPP */

@ -0,0 +1,28 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_date.hpp"
namespace SQConvert {
/* Allow AIDate to be used as Squirrel parameter */
template <> AIDate *GetParam(ForceType<AIDate *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIDate *)instance; }
template <> AIDate &GetParam(ForceType<AIDate &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIDate *)instance; }
template <> const AIDate *GetParam(ForceType<const AIDate *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIDate *)instance; }
template <> const AIDate &GetParam(ForceType<const AIDate &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIDate *)instance; }
template <> int Return<AIDate *>(HSQUIRRELVM vm, AIDate *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIDate", res, NULL, DefSQDestructorCallback<AIDate>); return 1; }
}; // namespace SQConvert
void SQAIDate_Register(Squirrel *engine) {
DefSQClass <AIDate> SQAIDate("AIDate");
SQAIDate.PreRegister(engine);
SQAIDate.AddConstructor<void (AIDate::*)(), 1>(engine, "x");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetClassName, "GetClassName", 1, "x");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetCurrentDate, "GetCurrentDate", 1, "x");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetYear, "GetYear", 2, "xi");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetMonth, "GetMonth", 2, "xi");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetDayOfMonth, "GetDayOfMonth", 2, "xi");
SQAIDate.DefSQStaticMethod(engine, &AIDate::GetDate, "GetDate", 4, "xiii");
SQAIDate.PostRegister(engine);
}

@ -0,0 +1,42 @@
/* $Id$ */
/** @file ai_depotlist.cpp Implementation of AIDepotList and friends. */
#include "ai_depotlist.hpp"
#include "../../core/math_func.hpp"
#include "../../tile_map.h"
#include "../../company_func.h"
#include "../../depot_base.h"
#include "../../station_base.h"
AIDepotList::AIDepotList(AITile::TransportType transport_type)
{
::TileType tile_type;
switch (transport_type) {
default: return;
case AITile::TRANSPORT_ROAD: tile_type = ::MP_ROAD; break;
case AITile::TRANSPORT_RAIL: tile_type = ::MP_RAILWAY; break;
case AITile::TRANSPORT_WATER: tile_type = ::MP_WATER; break;
case AITile::TRANSPORT_AIR: {
/* Hangars are not seen as real depots by the depot code. */
const Station *st;
FOR_ALL_STATIONS(st) {
if (st->owner == ::_current_company) {
const AirportFTAClass *afc = st->Airport();
for (uint i = 0; i < afc->nof_depots; i++) {
this->AddItem(st->xy + ToTileIndexDiff(afc->airport_depots[i]));
}
}
}
return;
}
}
/* Handle 'standard' depots. */
const Depot *depot;
FOR_ALL_DEPOTS(depot) {
if (::GetTileOwner(depot->xy) == ::_current_company && ::IsTileType(depot->xy, tile_type)) this->AddItem(depot->xy);
}
}

@ -0,0 +1,25 @@
/* $Id$ */
/** @file ai_depotlist.hpp List all the depots (you own). */
#ifndef AI_DEPOTLIST_HPP
#define AI_DEPOTLIST_HPP
#include "ai_abstractlist.hpp"
#include "ai_tile.hpp"
/**
* Creates a list of the locations of the depots (and hangars) of which you are the owner.
* @ingroup AIList
*/
class AIDepotList : public AIAbstractList {
public:
static const char *GetClassName() { return "AIDepotList"; }
/**
* @param transport_type The type of transport to make a list of depots for.
*/
AIDepotList(AITile::TransportType transport_type);
};
#endif /* AI_DEPOTLIST_HPP */

@ -0,0 +1,23 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_depotlist.hpp"
namespace SQConvert {
/* Allow AIDepotList to be used as Squirrel parameter */
template <> AIDepotList *GetParam(ForceType<AIDepotList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIDepotList *)instance; }
template <> AIDepotList &GetParam(ForceType<AIDepotList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIDepotList *)instance; }
template <> const AIDepotList *GetParam(ForceType<const AIDepotList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIDepotList *)instance; }
template <> const AIDepotList &GetParam(ForceType<const AIDepotList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIDepotList *)instance; }
template <> int Return<AIDepotList *>(HSQUIRRELVM vm, AIDepotList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIDepotList", res, NULL, DefSQDestructorCallback<AIDepotList>); return 1; }
}; // namespace SQConvert
void SQAIDepotList_Register(Squirrel *engine) {
DefSQClass <AIDepotList> SQAIDepotList("AIDepotList");
SQAIDepotList.PreRegister(engine, "AIAbstractList");
SQAIDepotList.AddConstructor<void (AIDepotList::*)(AITile::TransportType transport_type), 2>(engine, "xi");
SQAIDepotList.DefSQStaticMethod(engine, &AIDepotList::GetClassName, "GetClassName", 1, "x");
SQAIDepotList.PostRegister(engine);
}

@ -0,0 +1,295 @@
/* $Id$ */
/** @file ai_engine.cpp Implementation of AIEngine. */
#include "ai_engine.hpp"
#include "ai_cargo.hpp"
#include "ai_rail.hpp"
#include "../../openttd.h"
#include "../../company_func.h"
#include "../../strings_func.h"
#include "../../roadveh.h"
#include "../../train.h"
#include "../../ship.h"
#include "../../aircraft.h"
#include "../../vehicle_func.h"
#include "../../core/alloc_func.hpp"
#include "../../economy_func.h"
#include "../../core/bitmath_func.hpp"
#include "../../settings_type.h"
#include "../../articulated_vehicles.h"
#include "table/strings.h"
/* static */ bool AIEngine::IsValidEngine(EngineID engine_id)
{
return ::IsEngineIndex(engine_id) && HasBit(::GetEngine(engine_id)->company_avail, _current_company);
}
/* static */ const char *AIEngine::GetName(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return NULL;
static const int len = 64;
char *engine_name = MallocT<char>(len);
::SetDParam(0, engine_id);
::GetString(engine_name, STR_ENGINE_NAME, &engine_name[len - 1]);
return engine_name;
}
/* static */ CargoID AIEngine::GetCargoType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return CT_INVALID;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine_id);
return vi->cargo_type;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine_id);
return vi->cargo_type;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine_id);
return vi->cargo_type;
} break;
case VEH_AIRCRAFT: {
return CT_PASSENGERS;
} break;
default: NOT_REACHED();
}
}
/* static */ bool AIEngine::CanRefitCargo(EngineID engine_id, CargoID cargo_id)
{
if (!IsValidEngine(engine_id)) return false;
if (!AICargo::IsValidCargo(cargo_id)) return false;
if (GetCargoType(engine_id) == cargo_id) return true;
if (cargo_id == CT_MAIL && ::GetEngine(engine_id)->type == VEH_AIRCRAFT) return true;
if (::GetEngine(engine_id)->type == VEH_SHIP && !ShipVehInfo(engine_id)->refittable) return false;
return ::CanRefitTo(engine_id, cargo_id);
}
/* static */ bool AIEngine::CanPullCargo(EngineID engine_id, CargoID cargo_id)
{
if (!IsValidEngine(engine_id)) return false;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return false;
if (!AICargo::IsValidCargo(cargo_id)) return false;
return (::RailVehInfo(engine_id)->ai_passenger_only != 1) || AICargo::HasCargoClass(cargo_id, AICargo::CC_PASSENGERS);
}
/* static */ int32 AIEngine::GetCapacity(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD:
case VEH_TRAIN: {
uint16 *capacities = GetCapacityOfArticulatedParts(engine_id, ::GetEngine(engine_id)->type);
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (capacities[c] == 0) continue;
return capacities[c];
}
return -1;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine_id);
return vi->capacity;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine_id);
return vi->passenger_capacity;
} break;
default: NOT_REACHED();
}
}
/* static */ int32 AIEngine::GetReliability(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
return (::GetEngine(engine_id)->reliability * 100 >> 16);
}
/* static */ int32 AIEngine::GetMaxSpeed(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine_id);
/* Internal speeds are km/h * 2 */
return vi->max_speed / 2;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine_id);
return vi->max_speed;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine_id);
/* Internal speeds are km/h * 2 */
return vi->max_speed / 2;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine_id);
return vi->max_speed / _settings_game.vehicle.plane_speed;
} break;
default: NOT_REACHED();
}
}
/* static */ Money AIEngine::GetPrice(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine_id);
return (_price.roadveh_base >> 3) * vi->cost_factor >> 5;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine_id);
return (_price.build_railvehicle >> 3) * vi->cost_factor >> 5;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine_id);
return (_price.ship_base >> 3) * vi->cost_factor >> 5;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine_id);
return (_price.aircraft_base >> 3) * vi->cost_factor >> 5;
} break;
default: NOT_REACHED();
}
}
/* static */ int32 AIEngine::GetMaxAge(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
return ::GetEngine(engine_id)->lifelength * 366;
}
/* static */ Money AIEngine::GetRunningCost(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
/* We need to create an instance in order to obtain GetRunningCost.
* This means we temporary allocate a vehicle in the pool, but
* there is no other way.. */
Vehicle *vehicle;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: {
vehicle = new RoadVehicle();
} break;
case VEH_TRAIN: {
vehicle = new Train();
} break;
case VEH_SHIP: {
vehicle = new Ship();
} break;
case VEH_AIRCRAFT: {
vehicle = new Aircraft();
} break;
default: NOT_REACHED();
}
vehicle->engine_type = engine_id;
Money runningCost = vehicle->GetRunningCost();
delete vehicle;
return runningCost >> 8;
}
/* static */ AIVehicle::VehicleType AIEngine::GetVehicleType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return AIVehicle::VEHICLE_INVALID;
switch (::GetEngine(engine_id)->type) {
case VEH_ROAD: return AIVehicle::VEHICLE_ROAD;
case VEH_TRAIN: return AIVehicle::VEHICLE_RAIL;
case VEH_SHIP: return AIVehicle::VEHICLE_WATER;
case VEH_AIRCRAFT: return AIVehicle::VEHICLE_AIR;
default: NOT_REACHED();
}
}
/* static */ bool AIEngine::IsWagon(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return false;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return false;
return ::RailVehInfo(engine_id)->power == 0;
}
/* static */ bool AIEngine::CanRunOnRail(EngineID engine_id, AIRail::RailType track_rail_type)
{
if (!IsValidEngine(engine_id)) return false;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return false;
if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
return ::IsCompatibleRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
}
/* static */ bool AIEngine::HasPowerOnRail(EngineID engine_id, AIRail::RailType track_rail_type)
{
if (!IsValidEngine(engine_id)) return false;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return false;
if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
}
/* static */ AIRoad::RoadType AIEngine::GetRoadType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return AIRoad::ROADTYPE_INVALID;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_ROAD) return AIRoad::ROADTYPE_INVALID;
return HasBit(::EngInfo(engine_id)->misc_flags, EF_ROAD_TRAM) ? AIRoad::ROADTYPE_TRAM : AIRoad::ROADTYPE_ROAD;
}
/* static */ AIRail::RailType AIEngine::GetRailType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return AIRail::RAILTYPE_INVALID;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return AIRail::RAILTYPE_INVALID;
return (AIRail::RailType)(uint)::RailVehInfo(engine_id)->railtype;
}
/* static */ bool AIEngine::IsArticulated(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return false;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_ROAD && GetVehicleType(engine_id) != AIVehicle::VEHICLE_RAIL) return false;
return CountArticulatedParts(engine_id, true) != 0;
}
/* static */ AIAirport::PlaneType AIEngine::GetPlaneType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return AIAirport::PT_INVALID;
if (GetVehicleType(engine_id) != AIVehicle::VEHICLE_AIR) return AIAirport::PT_INVALID;
return (AIAirport::PlaneType)::AircraftVehInfo(engine_id)->subtype;
}

@ -0,0 +1,202 @@
/* $Id$ */
/** @file ai_engine.hpp Everything to query and build engines. */
#ifndef AI_ENGINE_HPP
#define AI_ENGINE_HPP
#include "ai_object.hpp"
#include "ai_vehicle.hpp"
#include "ai_road.hpp"
#include "ai_rail.hpp"
#include "ai_airport.hpp"
/**
* Class that handles all engine related functions.
*/
class AIEngine : public AIObject {
public:
static const char *GetClassName() { return "AIEngine"; }
/**
* Checks whether the given engine type is valid and buildable by you.
* @param engine_id The engine to check.
* @return True if and only if the engine type is valid.
*/
static bool IsValidEngine(EngineID engine_id);
/**
* Get the name of an engine.
* @param engine_id The engine to get the name of.
* @pre IsValidEngine(engine_id).
* @return The name the engine has.
*/
static const char *GetName(EngineID engine_id);
/**
* Get the cargo-type of an engine. In case it can transport 2 cargos, it
* returns the first.
* @param engine_id The engine to get the cargo-type of.
* @pre IsValidEngine(engine_id).
* @return The cargo-type of the engine.
*/
static CargoID GetCargoType(EngineID engine_id);
/**
* Check if the cargo of an engine can be refitted to your requested. If
* the engine already allows this cargo, the function also returns true.
* @param engine_id The engine to check for refitting.
* @param cargo_id The cargo to check for refitting.
* @pre IsValidEngine(engine_id).
* @pre AICargo::IsValidCargo(cargo_id).
* @return True if the engine can carry this cargo, either via refit, or
* by default.
*/
static bool CanRefitCargo(EngineID engine_id, CargoID cargo_id);
/**
* Check if the engine can pull a wagon with the given cargo.
* @param engine_id The engine to check.
* @param cargo_id The cargo to check.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_RAIL.
* @pre AICargo::IsValidCargo(cargo_id).
* @return True if the engine can pull wagons carrying this cargo.
* @note This function is not exhaustive; a true here does not mean
* that the vehicle can pull the wagons, a false does mean it can't.
*/
static bool CanPullCargo(EngineID engine_id, CargoID cargo_id);
/**
* Get the capacity of an engine. In case it can transport 2 cargos, it
* returns the first.
* @param engine_id The engine to get the capacity of.
* @pre IsValidEngine(engine_id).
* @return The capacity of the engine.
*/
static int32 GetCapacity(EngineID engine_id);
/**
* Get the reliability of an engine. The value is between 0 and 100, where
* 100 means 100% reliability (never breaks down) and 0 means 0%
* reliability (you most likely don't want to buy it).
* @param engine_id The engine to get the reliability of.
* @pre IsValidEngine(engine_id).
* @return The reliability the engine has.
*/
static int32 GetReliability(EngineID engine_id);
/**
* Get the maximum speed of an engine.
* @param engine_id The engine to get the maximum speed of.
* @pre IsValidEngine(engine_id).
* @return The maximum speed the engine has.
* @note The speed is in km/h.
*/
static int32 GetMaxSpeed(EngineID engine_id);
/**
* Get the new cost of an engine.
* @param engine_id The engine to get the new cost of.
* @pre IsValidEngine(engine_id).
* @return The new cost the engine has.
*/
static Money GetPrice(EngineID engine_id);
/**
* Get the maximum age of a brand new engine.
* @param engine_id The engine to get the maximum age of.
* @pre IsValidEngine(engine_id).
* @returns The maximum age of a new engine in days.
* @note Age is in days; divide by 366 to get per year.
*/
static int32 GetMaxAge(EngineID engine_id);
/**
* Get the running cost of an engine.
* @param engine_id The engine to get the running cost of.
* @pre IsValidEngine(engine_id).
* @return The running cost of a vehicle per year.
* @note Cost is per year; divide by 364 to get per day.
*/
static Money GetRunningCost(EngineID engine_id);
/**
* Get the type of an engine.
* @param engine_id The engine to get the type of.
* @pre IsValidEngine(engine_id).
* @return The type the engine has.
*/
static AIVehicle::VehicleType GetVehicleType(EngineID engine_id);
/**
* Check if an engine is a wagon.
* @param engine_id The engine to check.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_RAIL.
* @return Whether or not the engine is a wagon.
*/
static bool IsWagon(EngineID engine_id);
/**
* Check if a train vehicle can run on a RailType.
* @param engine_id The engine to check.
* @param track_rail_type The type you want to check.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle::VEHICLE_RAIL.
* @pre AIRail::IsRailTypeAvailable(track_rail_type).
* @return Whether an engine of type 'engine_id' can run on 'track_rail_type'.
* @note Even if a train can run on a RailType that doesn't mean that it'll be
* able to power the train. Use HasPowerOnRail for that.
*/
static bool CanRunOnRail(EngineID engine_id, AIRail::RailType track_rail_type);
/**
* Check if a train engine has power on a RailType.
* @param engine_id The engine to check.
* @param track_rail_type Another RailType.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle::VEHICLE_RAIL.
* @pre AIRail::IsRailTypeAvailable(track_rail_type).
* @return Whether an engine of type 'engine_id' has power on 'track_rail_type'.
*/
static bool HasPowerOnRail(EngineID engine_id, AIRail::RailType track_rail_type);
/**
* Get the RoadType of the engine.
* @param engine_id The engine to get the RoadType of.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_ROAD.
* @return The RoadType the engine has.
*/
static AIRoad::RoadType GetRoadType(EngineID engine_id);
/**
* Get the RailType of the engine.
* @param engine_id The engine to get the RailType of.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_RAIL.
* @return The RailType the engine has.
*/
static AIRail::RailType GetRailType(EngineID engine_id);
/**
* Check if the engine is articulated.
* @param engine_id The engine to check.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_ROAD || GetVehicleType(engine_id) == AIVehicle.VEHICLE_RAIL.
* @return True if the engine is articulated.
*/
static bool IsArticulated(EngineID engine_id);
/**
* Get the PlaneType of the engine.
* @param engine_id The engine to get the PlaneType of.
* @pre IsValidEngine(engine_id).
* @pre GetVehicleType(engine_id) == AIVehicle.VEHICLE_AIR.
* @return The PlaneType the engine has.
*/
static AIAirport::PlaneType GetPlaneType(EngineID engine_id);
};
#endif /* AI_ENGINE_HPP */

@ -0,0 +1,42 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_engine.hpp"
namespace SQConvert {
/* Allow AIEngine to be used as Squirrel parameter */
template <> AIEngine *GetParam(ForceType<AIEngine *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEngine *)instance; }
template <> AIEngine &GetParam(ForceType<AIEngine &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEngine *)instance; }
template <> const AIEngine *GetParam(ForceType<const AIEngine *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEngine *)instance; }
template <> const AIEngine &GetParam(ForceType<const AIEngine &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEngine *)instance; }
template <> int Return<AIEngine *>(HSQUIRRELVM vm, AIEngine *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEngine", res, NULL, DefSQDestructorCallback<AIEngine>); return 1; }
}; // namespace SQConvert
void SQAIEngine_Register(Squirrel *engine) {
DefSQClass <AIEngine> SQAIEngine("AIEngine");
SQAIEngine.PreRegister(engine);
SQAIEngine.AddConstructor<void (AIEngine::*)(), 1>(engine, "x");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetClassName, "GetClassName", 1, "x");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::IsValidEngine, "IsValidEngine", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetName, "GetName", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetCargoType, "GetCargoType", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::CanRefitCargo, "CanRefitCargo", 3, "xii");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::CanPullCargo, "CanPullCargo", 3, "xii");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetCapacity, "GetCapacity", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetReliability, "GetReliability", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetMaxSpeed, "GetMaxSpeed", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetPrice, "GetPrice", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetMaxAge, "GetMaxAge", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetRunningCost, "GetRunningCost", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetVehicleType, "GetVehicleType", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::IsWagon, "IsWagon", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::CanRunOnRail, "CanRunOnRail", 3, "xii");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::HasPowerOnRail, "HasPowerOnRail", 3, "xii");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetRoadType, "GetRoadType", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetRailType, "GetRailType", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::IsArticulated, "IsArticulated", 2, "xi");
SQAIEngine.DefSQStaticMethod(engine, &AIEngine::GetPlaneType, "GetPlaneType", 2, "xi");
SQAIEngine.PostRegister(engine);
}

@ -0,0 +1,16 @@
/* $Id$ */
/** @file ai_enginelist.cpp Implementation of AIEngineList and friends. */
#include "ai_enginelist.hpp"
#include "../../company_func.h"
#include "../../engine_base.h"
#include "../../core/bitmath_func.hpp"
AIEngineList::AIEngineList(AIVehicle::VehicleType vehicle_type)
{
Engine *e;
FOR_ALL_ENGINES_OF_TYPE(e, (::VehicleType)vehicle_type) {
if (HasBit(e->company_avail, _current_company)) this->AddItem(e->index);
}
}

@ -0,0 +1,25 @@
/* $Id$ */
/** @file ai_enginelist.hpp List all the engines. */
#ifndef AI_ENGINELIST_HPP
#define AI_ENGINELIST_HPP
#include "ai_abstractlist.hpp"
#include "ai_vehicle.hpp"
/**
* Create a list of engines based on a vehicle type.
* @ingroup AIList
*/
class AIEngineList : public AIAbstractList {
public:
static const char *GetClassName() { return "AIEngineList"; }
/**
* @param vehicle_type The type of vehicle to make a list of engines for.
*/
AIEngineList(AIVehicle::VehicleType vehicle_type);
};
#endif /* AI_ENGINELIST_HPP */

@ -0,0 +1,23 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_enginelist.hpp"
namespace SQConvert {
/* Allow AIEngineList to be used as Squirrel parameter */
template <> AIEngineList *GetParam(ForceType<AIEngineList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEngineList *)instance; }
template <> AIEngineList &GetParam(ForceType<AIEngineList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEngineList *)instance; }
template <> const AIEngineList *GetParam(ForceType<const AIEngineList *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEngineList *)instance; }
template <> const AIEngineList &GetParam(ForceType<const AIEngineList &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEngineList *)instance; }
template <> int Return<AIEngineList *>(HSQUIRRELVM vm, AIEngineList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEngineList", res, NULL, DefSQDestructorCallback<AIEngineList>); return 1; }
}; // namespace SQConvert
void SQAIEngineList_Register(Squirrel *engine) {
DefSQClass <AIEngineList> SQAIEngineList("AIEngineList");
SQAIEngineList.PreRegister(engine, "AIAbstractList");
SQAIEngineList.AddConstructor<void (AIEngineList::*)(AIVehicle::VehicleType vehicle_type), 2>(engine, "xi");
SQAIEngineList.DefSQStaticMethod(engine, &AIEngineList::GetClassName, "GetClassName", 1, "x");
SQAIEngineList.PostRegister(engine);
}

@ -0,0 +1,60 @@
/* $Id$ */
/** @file ai_error.cpp Implementation of AIError. */
#include "ai_error.hpp"
#include "table/strings.h"
#include "../../core/bitmath_func.hpp"
AIError::AIErrorMap AIError::error_map = AIError::AIErrorMap();
AIError::AIErrorMapString AIError::error_map_string = AIError::AIErrorMapString();
/* static */ AIErrorType AIError::GetLastError()
{
return AIObject::GetLastError();
}
/* static */ const char *AIError::GetLastErrorString()
{
return (*error_map_string.find(AIError::GetLastError())).second;
}
/* static */ AIErrorType AIError::StringToError(StringID internal_string_id)
{
uint index = GB(internal_string_id, 11, 5);
switch (GB(internal_string_id, 11, 5)) {
case 26: case 28: case 29: case 30: // NewGRF strings.
return ERR_NEWGRF_SUPPLIED_ERROR;
/* DO NOT SWAP case 14 and 4 because that will break StringToError due
* to the index dependency that relies on FALL THROUGHs. */
case 14: if (index < 0xE4) break; // Player name
case 4: if (index < 0xC0) break; // Town name
case 15: // Custom name
case 31: // Dynamic strings
/* These strings are 'random' and have no meaning.
* They actually shouldn't even be returned as error messages. */
return ERR_UNKNOWN;
default:
break;
}
AIErrorMap::iterator it = error_map.find(internal_string_id);
if (it == error_map.end()) return ERR_UNKNOWN;
return (*it).second;
}
/* static */ void AIError::RegisterErrorMap(StringID internal_string_id, AIErrorType ai_error_msg)
{
error_map[internal_string_id] = ai_error_msg;
}
/* static */ void AIError::RegisterErrorMapString(AIErrorType ai_error_msg, const char *message)
{
error_map_string[ai_error_msg] = message;
}
/* static */ AIError::ErrorCategories AIError::GetErrorCategory() {
return (AIError::ErrorCategories)(GetLastError() >> (uint)ERR_CAT_BIT_SIZE);
}

@ -0,0 +1,171 @@
/* $Id$ */
/** @file ai_error.hpp Everything to query errors. */
#ifndef AI_ERROR_HPP
#define AI_ERROR_HPP
#include "ai_object.hpp"
#include <map>
/**
* Helper to write precondition enforcers for the AI API in an abbreviated manner.
* @param returnval The value to return on failure.
* @param condition The condition that must be obeyed.
*/
#define EnforcePrecondition(returnval, condition) \
if (!(condition)) { \
AIObject::SetLastError(AIError::ERR_PRECONDITION_FAILED); \
return returnval; \
}
/**
* Helper to write precondition enforcers for the AI API in an abbreviated manner.
* @param returnval The value to return on failure.
* @param condition The condition that must be obeyed.
* @param error_code The error code passed to AIObject::SetLastError.
*/
#define EnforcePreconditionCustomError(returnval, condition, error_code) \
if (!(condition)) { \
AIObject::SetLastError(error_code); \
return returnval; \
}
/**
* Class that handles all error related functions.
*/
class AIError : public AIObject {
public:
static const char *GetClassName() { return "AIError"; }
/**
* All categories errors can be divided in.
*/
enum ErrorCategories {
ERR_CAT_NONE = 0, //!< Error messages not related to any category.
ERR_CAT_GENERAL, //!< Error messages related to general things.
ERR_CAT_VEHICLE, //!< Error messages related to building / maintaining vehicles.
ERR_CAT_STATION, //!< Error messages related to building / maintaining stations.
ERR_CAT_BRIDGE, //!< Error messages related to building / removing bridges.
ERR_CAT_TUNNEL, //!< Error messages related to building / removing tunnels.
ERR_CAT_TILE, //!< Error messages related to raising / lowering and demolishing tiles.
ERR_CAT_SIGN, //!< Error messages related to building / removing signs.
ERR_CAT_RAIL, //!< Error messages related to building / maintaining rails.
ERR_CAT_ROAD, //!< Error messages related to building / maintaining roads.
ERR_CAT_ORDER, //!< Error messages related to managing orders.
ERR_CAT_MARINE, //!< Error messages related to building / removing ships, docks and channels.
/**
* DO NOT USE! The error bitsize determines how many errors can be stored in
* a category and what the offsets are of all categories.
*/
ERR_CAT_BIT_SIZE = 8,
};
/**
* All general related error messages.
*/
enum ErrorMessages {
/** Initial error value */
ERR_NONE = ERR_CAT_NONE << ERR_CAT_BIT_SIZE, // []
/** If an error occured and the error wasn't mapped */
ERR_UNKNOWN, // []
/** If a precondition is not met */
ERR_PRECONDITION_FAILED, // []
/** A string supplied was too long */
ERR_PRECONDITION_STRING_TOO_LONG, // []
/** An error returned by a NewGRF. No possibility to get the exact error in an AI readable format */
ERR_NEWGRF_SUPPLIED_ERROR, // []
/** Base for general errors */
ERR_GENERAL_BASE = ERR_CAT_GENERAL << ERR_CAT_BIT_SIZE,
/** Not enough cash to perform the previous action */
ERR_NOT_ENOUGH_CASH, // [STR_0003_NOT_ENOUGH_CASH_REQUIRES]
/** Local authority won't allow the previous action */
ERR_LOCAL_AUTHORITY_REFUSES, // [STR_2009_LOCAL_AUTHORITY_REFUSES]
/** The piece of infrastructure you tried to build is already in place */
ERR_ALREADY_BUILT, // [STR_1007_ALREADY_BUILT, STR_5007_MUST_DEMOLISH_BRIDGE_FIRST]
/** Area isn't clear, try to demolish the building on it */
ERR_AREA_NOT_CLEAR, // [STR_2004_BUILDING_MUST_BE_DEMOLISHED, STR_5007_MUST_DEMOLISH_BRIDGE_FIRST, STR_300B_MUST_DEMOLISH_RAILROAD, STR_300E_MUST_DEMOLISH_AIRPORT_FIRST, STR_MUST_DEMOLISH_CARGO_TRAM_STATION, STR_3047_MUST_DEMOLISH_TRUCK_STATION, STR_MUST_DEMOLISH_PASSENGER_TRAM_STATION, STR_3046_MUST_DEMOLISH_BUS_STATION, STR_306A_BUOY_IN_THE_WAY, STR_304D_MUST_DEMOLISH_DOCK_FIRST, STR_4800_IN_THE_WAY, STR_5804_COMPANY_HEADQUARTERS_IN, STR_5800_OBJECT_IN_THE_WAY, STR_1801_MUST_REMOVE_ROAD_FIRST, STR_1008_MUST_REMOVE_RAILROAD_TRACK, STR_5007_MUST_DEMOLISH_BRIDGE_FIRST, STR_5006_MUST_DEMOLISH_TUNNEL_FIRST, STR_1002_EXCAVATION_WOULD_DAMAGE]
/** Area / property is owned by another company */
ERR_OWNED_BY_ANOTHER_COMPANY, // [STR_1024_AREA_IS_OWNED_BY_ANOTHER, STR_013B_OWNED_BY]
/** The name given is not unique for the object type */
ERR_NAME_IS_NOT_UNIQUE, // [STR_NAME_MUST_BE_UNIQUE]
/** The building you want to build requires flat land */
ERR_FLAT_LAND_REQUIRED, // [STR_0007_FLAT_LAND_REQUIRED]
/** Land is sloped in the wrong direction for this build action */
ERR_LAND_SLOPED_WRONG, // [STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION]
/** A vehicle is in the way */
ERR_VEHICLE_IN_THE_WAY, // [STR_8803_TRAIN_IN_THE_WAY, STR_9000_ROAD_VEHICLE_IN_THE_WAY, STR_980E_SHIP_IN_THE_WAY, STR_A015_AIRCRAFT_IN_THE_WAY]
/** Site is unsuitable */
ERR_SITE_UNSUITABLE, // [STR_0239_SITE_UNSUITABLE, STR_304B_SITE_UNSUITABLE]
/** Too close to the edge of the map */
ERR_TOO_CLOSE_TO_EDGE, // [STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP]
/** Station is too spread out */
ERR_STATION_TOO_SPREAD_OUT, // [STR_306C_STATION_TOO_SPREAD_OUT]
};
/**
* Check the membership of the last thrown error.
* @return The category the error belongs to.
* @note The last throw error can be aquired by calling GetLastError().
*/
static ErrorCategories GetErrorCategory();
/**
* Get the last error.
* @return An ErrorMessages enum value.
*/
static AIErrorType GetLastError();
/**
* Get the last error in string format (for human readability).
* @return An ErrorMessage enum item, as string.
*/
static const char *GetLastErrorString();
/**
* Get the error based on the OpenTTD StringID.
* @note DO NOT INVOKE THIS METHOD YOURSELF!
* @param internal_string_id The string to convert.
* @return The NoAI equivalent error message.
*/
static AIErrorType StringToError(StringID internal_string_id);
/**
* Map an internal OpenTTD error message to it's NoAI equivalent.
* @note DO NOT INVOKE THIS METHOD YOURSELF! The calls are autogenerated.
* @param internal_string_id The OpenTTD StringID used for an error.
* @param ai_error_msg The NoAI equivalent error message.
*/
static void RegisterErrorMap(StringID internal_string_id, AIErrorType ai_error_msg);
/**
* Map an internal OpenTTD error message to it's NoAI equivalent.
* @note DO NOT INVOKE THIS METHOD YOURSELF! The calls are autogenerated.
* @param ai_error_msg The NoAI error message representation.
* @param message The string representation of this error message, used for debug purposes.
*/
static void RegisterErrorMapString(AIErrorType ai_error_msg, const char *message);
private:
typedef std::map<StringID, AIErrorType> AIErrorMap;
typedef std::map<AIErrorType, const char *> AIErrorMapString;
static AIErrorMap error_map;
static AIErrorMapString error_map_string;
};
#endif /* AI_ERROR_HPP */

@ -0,0 +1,121 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_error.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AIError::ErrorCategories GetParam(ForceType<AIError::ErrorCategories>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIError::ErrorCategories)tmp; }
template <> int Return<AIError::ErrorCategories>(HSQUIRRELVM vm, AIError::ErrorCategories res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> AIError::ErrorMessages GetParam(ForceType<AIError::ErrorMessages>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIError::ErrorMessages)tmp; }
template <> int Return<AIError::ErrorMessages>(HSQUIRRELVM vm, AIError::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AIError to be used as Squirrel parameter */
template <> AIError *GetParam(ForceType<AIError *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIError *)instance; }
template <> AIError &GetParam(ForceType<AIError &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIError *)instance; }
template <> const AIError *GetParam(ForceType<const AIError *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIError *)instance; }
template <> const AIError &GetParam(ForceType<const AIError &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIError *)instance; }
template <> int Return<AIError *>(HSQUIRRELVM vm, AIError *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIError", res, NULL, DefSQDestructorCallback<AIError>); return 1; }
}; // namespace SQConvert
void SQAIError_Register(Squirrel *engine) {
DefSQClass <AIError> SQAIError("AIError");
SQAIError.PreRegister(engine);
SQAIError.AddConstructor<void (AIError::*)(), 1>(engine, "x");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_NONE, "ERR_CAT_NONE");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_GENERAL, "ERR_CAT_GENERAL");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_VEHICLE, "ERR_CAT_VEHICLE");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_STATION, "ERR_CAT_STATION");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_BRIDGE, "ERR_CAT_BRIDGE");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_TUNNEL, "ERR_CAT_TUNNEL");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_TILE, "ERR_CAT_TILE");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_SIGN, "ERR_CAT_SIGN");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_RAIL, "ERR_CAT_RAIL");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_ROAD, "ERR_CAT_ROAD");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_ORDER, "ERR_CAT_ORDER");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_MARINE, "ERR_CAT_MARINE");
SQAIError.DefSQConst(engine, AIError::ERR_CAT_BIT_SIZE, "ERR_CAT_BIT_SIZE");
SQAIError.DefSQConst(engine, AIError::ERR_NONE, "ERR_NONE");
SQAIError.DefSQConst(engine, AIError::ERR_UNKNOWN, "ERR_UNKNOWN");
SQAIError.DefSQConst(engine, AIError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED");
SQAIError.DefSQConst(engine, AIError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG");
SQAIError.DefSQConst(engine, AIError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR");
SQAIError.DefSQConst(engine, AIError::ERR_GENERAL_BASE, "ERR_GENERAL_BASE");
SQAIError.DefSQConst(engine, AIError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH");
SQAIError.DefSQConst(engine, AIError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES");
SQAIError.DefSQConst(engine, AIError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT");
SQAIError.DefSQConst(engine, AIError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR");
SQAIError.DefSQConst(engine, AIError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY");
SQAIError.DefSQConst(engine, AIError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE");
SQAIError.DefSQConst(engine, AIError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED");
SQAIError.DefSQConst(engine, AIError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG");
SQAIError.DefSQConst(engine, AIError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY");
SQAIError.DefSQConst(engine, AIError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE");
SQAIError.DefSQConst(engine, AIError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE");
SQAIError.DefSQConst(engine, AIError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT");
AIError::RegisterErrorMap(STR_0003_NOT_ENOUGH_CASH_REQUIRES, AIError::ERR_NOT_ENOUGH_CASH);
AIError::RegisterErrorMap(STR_2009_LOCAL_AUTHORITY_REFUSES, AIError::ERR_LOCAL_AUTHORITY_REFUSES);
AIError::RegisterErrorMap(STR_1007_ALREADY_BUILT, AIError::ERR_ALREADY_BUILT);
AIError::RegisterErrorMap(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST, AIError::ERR_ALREADY_BUILT);
AIError::RegisterErrorMap(STR_2004_BUILDING_MUST_BE_DEMOLISHED, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_300B_MUST_DEMOLISH_RAILROAD, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_300E_MUST_DEMOLISH_AIRPORT_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_MUST_DEMOLISH_CARGO_TRAM_STATION, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_3047_MUST_DEMOLISH_TRUCK_STATION, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_MUST_DEMOLISH_PASSENGER_TRAM_STATION, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_3046_MUST_DEMOLISH_BUS_STATION, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_306A_BUOY_IN_THE_WAY, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_304D_MUST_DEMOLISH_DOCK_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_4800_IN_THE_WAY, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_5804_COMPANY_HEADQUARTERS_IN, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_5800_OBJECT_IN_THE_WAY, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_1801_MUST_REMOVE_ROAD_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_1008_MUST_REMOVE_RAILROAD_TRACK, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_1002_EXCAVATION_WOULD_DAMAGE, AIError::ERR_AREA_NOT_CLEAR);
AIError::RegisterErrorMap(STR_1024_AREA_IS_OWNED_BY_ANOTHER, AIError::ERR_OWNED_BY_ANOTHER_COMPANY);
AIError::RegisterErrorMap(STR_013B_OWNED_BY, AIError::ERR_OWNED_BY_ANOTHER_COMPANY);
AIError::RegisterErrorMap(STR_NAME_MUST_BE_UNIQUE, AIError::ERR_NAME_IS_NOT_UNIQUE);
AIError::RegisterErrorMap(STR_0007_FLAT_LAND_REQUIRED, AIError::ERR_FLAT_LAND_REQUIRED);
AIError::RegisterErrorMap(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION, AIError::ERR_LAND_SLOPED_WRONG);
AIError::RegisterErrorMap(STR_8803_TRAIN_IN_THE_WAY, AIError::ERR_VEHICLE_IN_THE_WAY);
AIError::RegisterErrorMap(STR_9000_ROAD_VEHICLE_IN_THE_WAY, AIError::ERR_VEHICLE_IN_THE_WAY);
AIError::RegisterErrorMap(STR_980E_SHIP_IN_THE_WAY, AIError::ERR_VEHICLE_IN_THE_WAY);
AIError::RegisterErrorMap(STR_A015_AIRCRAFT_IN_THE_WAY, AIError::ERR_VEHICLE_IN_THE_WAY);
AIError::RegisterErrorMap(STR_0239_SITE_UNSUITABLE, AIError::ERR_SITE_UNSUITABLE);
AIError::RegisterErrorMap(STR_304B_SITE_UNSUITABLE, AIError::ERR_SITE_UNSUITABLE);
AIError::RegisterErrorMap(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP, AIError::ERR_TOO_CLOSE_TO_EDGE);
AIError::RegisterErrorMap(STR_306C_STATION_TOO_SPREAD_OUT, AIError::ERR_STATION_TOO_SPREAD_OUT);
AIError::RegisterErrorMapString(AIError::ERR_NONE, "ERR_NONE");
AIError::RegisterErrorMapString(AIError::ERR_UNKNOWN, "ERR_UNKNOWN");
AIError::RegisterErrorMapString(AIError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED");
AIError::RegisterErrorMapString(AIError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG");
AIError::RegisterErrorMapString(AIError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR");
AIError::RegisterErrorMapString(AIError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH");
AIError::RegisterErrorMapString(AIError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES");
AIError::RegisterErrorMapString(AIError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT");
AIError::RegisterErrorMapString(AIError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR");
AIError::RegisterErrorMapString(AIError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY");
AIError::RegisterErrorMapString(AIError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE");
AIError::RegisterErrorMapString(AIError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED");
AIError::RegisterErrorMapString(AIError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG");
AIError::RegisterErrorMapString(AIError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY");
AIError::RegisterErrorMapString(AIError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE");
AIError::RegisterErrorMapString(AIError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE");
AIError::RegisterErrorMapString(AIError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT");
SQAIError.DefSQStaticMethod(engine, &AIError::GetClassName, "GetClassName", 1, "x");
SQAIError.DefSQStaticMethod(engine, &AIError::GetErrorCategory, "GetErrorCategory", 1, "x");
SQAIError.DefSQStaticMethod(engine, &AIError::GetLastError, "GetLastError", 1, "x");
SQAIError.DefSQStaticMethod(engine, &AIError::GetLastErrorString, "GetLastErrorString", 1, "x");
SQAIError.DefSQStaticMethod(engine, &AIError::StringToError, "StringToError", 2, "xi");
SQAIError.DefSQStaticMethod(engine, &AIError::RegisterErrorMap, "RegisterErrorMap", 3, "xii");
SQAIError.DefSQStaticMethod(engine, &AIError::RegisterErrorMapString, "RegisterErrorMapString", 3, "xis");
SQAIError.PostRegister(engine);
}

@ -0,0 +1,65 @@
/* $Id$ */
/** @file ai_event.cpp Implementation of AIEvent. */
#include "ai_event.hpp"
#include "ai_event_types.hpp"
#include <queue>
#include <set>
struct AIEventData {
std::queue<AIEvent *> stack;
};
/* static */ void AIEventController::CreateEventPointer()
{
assert(AIObject::GetEventPointer() == NULL);
AIObject::GetEventPointer() = new AIEventData();
}
/* static */ void AIEventController::FreeEventPointer()
{
AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
/* Free all waiting events (if any) */
while (!data->stack.empty()) {
AIEvent *e = data->stack.front();
data->stack.pop();
e->Release();
}
/* Now kill our data pointer */
delete data;
}
/* static */ bool AIEventController::IsEventWaiting()
{
if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
return !data->stack.empty();
}
/* static */ AIEvent *AIEventController::GetNextEvent()
{
if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
if (data->stack.empty()) return NULL;
AIEvent *e = data->stack.front();
data->stack.pop();
return e;
}
/* static */ void AIEventController::InsertEvent(AIEvent *event)
{
if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
event->AddRef();
data->stack.push(event);
}

@ -0,0 +1,107 @@
/* $Id$ */
/** @file ai_event.hpp Everything to handle events from the game. */
#ifndef AI_EVENT_HPP
#define AI_EVENT_HPP
#include "ai_object.hpp"
/**
* Class that handles all event related functions.
* You can lookup the type, and than convert it to the real event-class.
* That way you can request more detailed information about the event.
*/
class AIEvent : public AIObject {
public:
static const char *GetClassName() { return "AIEvent"; }
/**
* The type of event. Needed to lookup the detailed class.
*/
enum AIEventType {
AI_ET_INVALID = 0,
AI_ET_TEST,
AI_ET_SUBSIDY_OFFER,
AI_ET_SUBSIDY_OFFER_EXPIRED,
AI_ET_SUBSIDY_AWARDED,
AI_ET_SUBSIDY_EXPIRED,
AI_ET_ENGINE_PREVIEW,
AI_ET_COMPANY_NEW,
AI_ET_COMPANY_IN_TROUBLE,
AI_ET_COMPANY_MERGER,
AI_ET_COMPANY_BANKRUPT,
AI_ET_VEHICLE_CRASHED,
AI_ET_VEHICLE_LOST,
AI_ET_VEHICLE_WAITING_IN_DEPOT,
AI_ET_VEHICLE_UNPROFITABLE,
AI_ET_INDUSTRY_OPEN,
AI_ET_INDUSTRY_CLOSE,
AI_ET_ENGINE_AVAILABLE,
AI_ET_STATION_FIRST_VEHICLE,
};
/**
* Constructor of AIEvent, to get the type of event.
*/
AIEvent(AIEvent::AIEventType type) :
type(type)
{}
/**
* Get the event-type.
* @return The @c AIEventType.
*/
AIEventType GetEventType() { return this->type; }
protected:
/**
* The type of this event.
*/
AIEventType type;
};
/**
* Class that handles all event related functions.
* @note it is not needed to create an instance of AIEvent to access it, as
* all members are static, and all data is stored AI-wide.
*/
class AIEventController : public AIObject {
public:
/**
* The name of the class, needed by several sub-processes.
*/
static const char *GetClassName() { return "AIEventController"; }
/**
* Check if there is an event waiting.
* @return true if there is an event on the stack.
*/
static bool IsEventWaiting();
/**
* Get the next event.
* @return a class of the event-child issues.
*/
static AIEvent *GetNextEvent();
/**
* Insert an event to the queue for the company.
* @param event The event to insert.
*/
static void InsertEvent(AIEvent *event);
/**
* Free the event pointer.
* @note DO NOT CALL YOURSELF; leave it to the internal AI programming.
*/
static void FreeEventPointer();
private:
/**
* Create the event pointer.
*/
static void CreateEventPointer();
};
#endif /* AI_EVENT_HPP */

@ -0,0 +1,72 @@
/* $Id$ */
/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
#include "ai_event.hpp"
namespace SQConvert {
/* Allow enums to be used as Squirrel parameters */
template <> AIEvent::AIEventType GetParam(ForceType<AIEvent::AIEventType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIEvent::AIEventType)tmp; }
template <> int Return<AIEvent::AIEventType>(HSQUIRRELVM vm, AIEvent::AIEventType res) { sq_pushinteger(vm, (int32)res); return 1; }
/* Allow AIEvent to be used as Squirrel parameter */
template <> AIEvent *GetParam(ForceType<AIEvent *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEvent *)instance; }
template <> AIEvent &GetParam(ForceType<AIEvent &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEvent *)instance; }
template <> const AIEvent *GetParam(ForceType<const AIEvent *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEvent *)instance; }
template <> const AIEvent &GetParam(ForceType<const AIEvent &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEvent *)instance; }
template <> int Return<AIEvent *>(HSQUIRRELVM vm, AIEvent *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, "AIEvent", res, NULL, DefSQDestructorCallback<AIEvent>); return 1; }
}; // namespace SQConvert
void SQAIEvent_Register(Squirrel *engine) {
DefSQClass <AIEvent> SQAIEvent("AIEvent");
SQAIEvent.PreRegister(engine);
SQAIEvent.AddConstructor<void (AIEvent::*)(AIEvent::AIEventType type), 2>(engine, "xi");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_INVALID, "AI_ET_INVALID");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_TEST, "AI_ET_TEST");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_SUBSIDY_OFFER, "AI_ET_SUBSIDY_OFFER");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_SUBSIDY_OFFER_EXPIRED, "AI_ET_SUBSIDY_OFFER_EXPIRED");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_SUBSIDY_AWARDED, "AI_ET_SUBSIDY_AWARDED");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_SUBSIDY_EXPIRED, "AI_ET_SUBSIDY_EXPIRED");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_ENGINE_PREVIEW, "AI_ET_ENGINE_PREVIEW");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_NEW, "AI_ET_COMPANY_NEW");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_IN_TROUBLE, "AI_ET_COMPANY_IN_TROUBLE");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_MERGER, "AI_ET_COMPANY_MERGER");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_BANKRUPT, "AI_ET_COMPANY_BANKRUPT");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_VEHICLE_CRASHED, "AI_ET_VEHICLE_CRASHED");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_VEHICLE_LOST, "AI_ET_VEHICLE_LOST");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_VEHICLE_WAITING_IN_DEPOT, "AI_ET_VEHICLE_WAITING_IN_DEPOT");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_VEHICLE_UNPROFITABLE, "AI_ET_VEHICLE_UNPROFITABLE");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_INDUSTRY_OPEN, "AI_ET_INDUSTRY_OPEN");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_INDUSTRY_CLOSE, "AI_ET_INDUSTRY_CLOSE");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_ENGINE_AVAILABLE, "AI_ET_ENGINE_AVAILABLE");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_STATION_FIRST_VEHICLE, "AI_ET_STATION_FIRST_VEHICLE");
SQAIEvent.DefSQStaticMethod(engine, &AIEvent::GetClassName, "GetClassName", 1, "x");
SQAIEvent.DefSQMethod(engine, &AIEvent::GetEventType, "GetEventType", 1, "x");
SQAIEvent.PostRegister(engine);
}
namespace SQConvert {
/* Allow AIEventController to be used as Squirrel parameter */
template <> AIEventController *GetParam(ForceType<AIEventController *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventController *)instance; }
template <> AIEventController &GetParam(ForceType<AIEventController &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventController *)instance; }
template <> const AIEventController *GetParam(ForceType<const AIEventController *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventController *)instance; }
template <> const AIEventController &GetParam(ForceType<const AIEventController &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventController *)instance; }
template <> int Return<AIEventController *>(HSQUIRRELVM vm, AIEventController *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEventController", res, NULL, DefSQDestructorCallback<AIEventController>); return 1; }
}; // namespace SQConvert
void SQAIEventController_Register(Squirrel *engine) {
DefSQClass <AIEventController> SQAIEventController("AIEventController");
SQAIEventController.PreRegister(engine);
SQAIEventController.AddConstructor<void (AIEventController::*)(), 1>(engine, "x");
SQAIEventController.DefSQStaticMethod(engine, &AIEventController::GetClassName, "GetClassName", 1, "x");
SQAIEventController.DefSQStaticMethod(engine, &AIEventController::IsEventWaiting, "IsEventWaiting", 1, "x");
SQAIEventController.DefSQStaticMethod(engine, &AIEventController::GetNextEvent, "GetNextEvent", 1, "x");
SQAIEventController.DefSQStaticMethod(engine, &AIEventController::InsertEvent, "InsertEvent", 2, "xx");
SQAIEventController.DefSQStaticMethod(engine, &AIEventController::FreeEventPointer, "FreeEventPointer", 1, "x");
SQAIEventController.PostRegister(engine);
}

@ -0,0 +1,187 @@
/* $Id$ */
/** @file ai_event_types.cpp Implementation of all EventTypes. */
#include "ai_event_types.hpp"
#include "../../openttd.h"
#include "../../core/alloc_func.hpp"
#include "../../strings_func.h"
#include "../../roadveh.h"
#include "../../train.h"
#include "../../ship.h"
#include "../../aircraft.h"
#include "../../settings_type.h"
#include "../../articulated_vehicles.h"
#include "table/strings.h"
bool AIEventVehicleCrashed::CloneCrashedVehicle(TileIndex depot)
{
return false;
}
const char *AIEventEnginePreview::GetName()
{
static const int len = 64;
char *engine_name = MallocT<char>(len);
::SetDParam(0, engine);
::GetString(engine_name, STR_ENGINE_NAME, &engine_name[len - 1]);
return engine_name;
}
CargoID AIEventEnginePreview::GetCargoType()
{
switch (::GetEngine(engine)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine);
return vi->cargo_type;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine);
return vi->cargo_type;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine);
return vi->cargo_type;
} break;
case VEH_AIRCRAFT: {
return CT_PASSENGERS;
} break;
default: NOT_REACHED();
}
}
int32 AIEventEnginePreview::GetCapacity()
{
switch (::GetEngine(engine)->type) {
case VEH_ROAD:
case VEH_TRAIN: {
uint16 *capacities = GetCapacityOfArticulatedParts(engine, ::GetEngine(engine)->type);
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (capacities[c] == 0) continue;
return capacities[c];
}
return -1;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine);
return vi->capacity;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine);
return vi->passenger_capacity;
} break;
default: NOT_REACHED();
}
}
int32 AIEventEnginePreview::GetMaxSpeed()
{
switch (::GetEngine(engine)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine);
/* Internal speeds are km/h * 2 */
return vi->max_speed / 2;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine);
return vi->max_speed;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine);
/* Internal speeds are km/h * 2 */
return vi->max_speed / 2;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine);
return vi->max_speed / _settings_game.vehicle.plane_speed;
} break;
default: NOT_REACHED();
}
}
Money AIEventEnginePreview::GetPrice()
{
switch (::GetEngine(engine)->type) {
case VEH_ROAD: {
const RoadVehicleInfo *vi = ::RoadVehInfo(engine);
return (_price.roadveh_base >> 3) * vi->cost_factor >> 5;
} break;
case VEH_TRAIN: {
const RailVehicleInfo *vi = ::RailVehInfo(engine);
return (_price.build_railvehicle >> 3) * vi->cost_factor >> 5;
} break;
case VEH_SHIP: {
const ShipVehicleInfo *vi = ::ShipVehInfo(engine);
return (_price.ship_base >> 3) * vi->cost_factor >> 5;
} break;
case VEH_AIRCRAFT: {
const AircraftVehicleInfo *vi = ::AircraftVehInfo(engine);
return (_price.aircraft_base >> 3) * vi->cost_factor >> 5;
} break;
default: NOT_REACHED();
}
}
Money AIEventEnginePreview::GetRunningCost()
{
/* We need to create an instance in order to obtain GetRunningCost.
* This means we temporary allocate a vehicle in the pool, but
* there is no other way.. */
Vehicle *vehicle;
switch (::GetEngine(engine)->type) {
case VEH_ROAD: {
vehicle = new RoadVehicle();
} break;
case VEH_TRAIN: {
vehicle = new Train();
} break;
case VEH_SHIP: {
vehicle = new Ship();
} break;
case VEH_AIRCRAFT: {
vehicle = new Aircraft();
} break;
default: NOT_REACHED();
}
vehicle->engine_type = engine;
Money runningCost = vehicle->GetRunningCost();
delete vehicle;
return runningCost >> 8;
}
AIVehicle::VehicleType AIEventEnginePreview::GetVehicleType()
{
switch (::GetEngine(engine)->type) {
case VEH_ROAD: return AIVehicle::VEHICLE_ROAD;
case VEH_TRAIN: return AIVehicle::VEHICLE_RAIL;
case VEH_SHIP: return AIVehicle::VEHICLE_WATER;
case VEH_AIRCRAFT: return AIVehicle::VEHICLE_AIR;
default: NOT_REACHED();
}
}
bool AIEventEnginePreview::AcceptPreview()
{
return AIObject::DoCommand(0, engine, 0, CMD_WANT_ENGINE_PREVIEW);
}

@ -0,0 +1,684 @@
/* $Id$ */
/** @file ai_event_types.hpp The detailed types of all events. */
#ifndef AI_EVENT_TYPES_HPP
#define AI_EVENT_TYPES_HPP
#include "ai_object.hpp"
#include "ai_event.hpp"
#include "ai_town.hpp"
#include "ai_industry.hpp"
#include "ai_engine.hpp"
#include "ai_subsidy.hpp"
/**
* Event Test: a simple test event, to see if the event system is working.
* Triggered via AIEventController::Test();
*/
class AIEventTest : public AIEvent {
public:
static const char *GetClassName() { return "AIEventTest"; }
/**
* @param test A test value.
*/
AIEventTest(uint test) :
AIEvent(AI_ET_TEST),
test(test)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventTest *Convert(AIEvent *instance) { return (AIEventTest *)instance; }
/**
* Return the test value.
* @return The test value.
*/
uint GetTest() { return this->test; }
private:
uint test;
};
/**
* Event Vehicle Crash, indicating a vehicle of yours is crashed.
* It contains both the crash site as the vehicle crashed. It has a nice
* helper that creates a new vehicle in a depot with the same type
* and orders as the crashed one. In case the vehicle type isn't available
* anymore, it will find the next best.
*/
class AIEventVehicleCrashed : public AIEvent {
public:
static const char *GetClassName() { return "AIEventVehicleCrashed"; }
/**
* @param vehicle The vehicle that crashed.
* @param crash_site Where the vehicle crashed.
*/
AIEventVehicleCrashed(VehicleID vehicle, TileIndex crash_site) :
AIEvent(AI_ET_VEHICLE_CRASHED),
crash_site(crash_site),
vehicle(vehicle)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventVehicleCrashed *Convert(AIEvent *instance) { return (AIEventVehicleCrashed *)instance; }
/**
* Get the VehicleID of the crashed vehicle.
* @return The crashed vehicle.
*/
VehicleID GetVehicleID() { return vehicle; }
/**
* Find the tile the vehicle crashed.
* @return The crash site.
*/
TileIndex GetCrashSite() { return crash_site; }
/**
* Clone the crashed vehicle and send it on its way again.
* @param depot the depot to build the vehicle in.
* @return True when the cloning succeeded.
* @note This function isn't implemented yet.
*/
bool CloneCrashedVehicle(TileIndex depot);
private:
TileIndex crash_site;
VehicleID vehicle;
};
/**
* Event Subsidy Offered, indicating someone offered a subsidy.
*/
class AIEventSubsidyOffer : public AIEvent {
public:
static const char *GetClassName() { return "AIEventSubsidyOffer"; }
/**
* @param subsidy_id The index of this subsidy in the _subsidies array.
*/
AIEventSubsidyOffer(SubsidyID subsidy_id) :
AIEvent(AI_ET_SUBSIDY_OFFER),
subsidy_id(subsidy_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventSubsidyOffer *Convert(AIEvent *instance) { return (AIEventSubsidyOffer *)instance; }
/**
* Get the SubsidyID of the subsidy.
* @return The subsidy id.
*/
SubsidyID GetSubsidyID() { return subsidy_id; }
private:
SubsidyID subsidy_id;
};
/**
* Event Subsidy Offer Expired, indicating a subsidy will no longer be awarded.
*/
class AIEventSubsidyOfferExpired : public AIEvent {
public:
static const char *GetClassName() { return "AIEventSubsidyOfferExpired"; }
/**
* @param subsidy_id The index of this subsidy in the _subsidies array.
*/
AIEventSubsidyOfferExpired(SubsidyID subsidy_id) :
AIEvent(AI_ET_SUBSIDY_OFFER_EXPIRED),
subsidy_id(subsidy_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventSubsidyOfferExpired *Convert(AIEvent *instance) { return (AIEventSubsidyOfferExpired *)instance; }
/**
* Get the SubsidyID of the subsidy.
* @return The subsidy id.
*/
SubsidyID GetSubsidyID() { return subsidy_id; }
private:
SubsidyID subsidy_id;
};
/**
* Event Subidy Awarded, indicating a subsidy is awarded to some company.
*/
class AIEventSubsidyAwarded : public AIEvent {
public:
static const char *GetClassName() { return "AIEventSubsidyAwarded"; }
/**
* @param subsidy_id The index of this subsidy in the _subsidies array.
*/
AIEventSubsidyAwarded(SubsidyID subsidy_id) :
AIEvent(AI_ET_SUBSIDY_AWARDED),
subsidy_id(subsidy_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventSubsidyAwarded *Convert(AIEvent *instance) { return (AIEventSubsidyAwarded *)instance; }
/**
* Get the SubsidyID of the subsidy.
* @return The subsidy id.
*/
SubsidyID GetSubsidyID() { return subsidy_id; }
private:
SubsidyID subsidy_id;
};
/**
* Event Subsidy Expired, indicating a route that was once subsidized no longer is.
*/
class AIEventSubsidyExpired : public AIEvent {
public:
static const char *GetClassName() { return "AIEventSubsidyExpired"; }
/**
* @param subsidy_id The index of this subsidy in the _subsidies array.
*/
AIEventSubsidyExpired(SubsidyID subsidy_id) :
AIEvent(AI_ET_SUBSIDY_EXPIRED),
subsidy_id(subsidy_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventSubsidyExpired *Convert(AIEvent *instance) { return (AIEventSubsidyExpired *)instance; }
/**
* Get the SubsidyID of the subsidy.
* @return The subsidy id.
*/
SubsidyID GetSubsidyID() { return subsidy_id; }
private:
SubsidyID subsidy_id;
};
/**
* Event Engine Preview, indicating a manufacturer offer you to test a new engine.
* You can get the same information about the offered engine as a real user
* would see in the offer window. And you can also accept the offer.
*/
class AIEventEnginePreview : public AIEvent {
public:
static const char *GetClassName() { return "AIEventEnginePreview"; }
/**
* @param engine The engine offered to test.
*/
AIEventEnginePreview(EngineID engine) :
AIEvent(AI_ET_ENGINE_PREVIEW),
engine(engine)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventEnginePreview *Convert(AIEvent *instance) { return (AIEventEnginePreview *)instance; }
/**
* Get the name of the offered engine.
* @return The name the engine has.
*/
const char *GetName();
/**
* Get the cargo-type of the offered engine. In case it can transport 2 cargos, it
* returns the first.
* @return The cargo-type of the engine.
*/
CargoID GetCargoType();
/**
* Get the capacity of the offered engine. In case it can transport 2 cargos, it
* returns the first.
* @return The capacity of the engine.
*/
int32 GetCapacity();
/**
* Get the maximum speed of the offered engine.
* @return The maximum speed the engine has.
* @note The speed is in km/h.
*/
int32 GetMaxSpeed();
/**
* Get the new cost of the offered engine.
* @return The new cost the engine has.
*/
Money GetPrice();
/**
* Get the running cost of the offered engine.
* @return The running cost of the vehicle per year.
* @note Cost is per year; divide by 364 to get per day.
*/
Money GetRunningCost();
/**
* Get the type of the offered engine.
* @return The type the engine has.
*/
AIVehicle::VehicleType GetVehicleType();
/**
* Accept the engine preview.
* @return True when the accepting succeeded.
*/
bool AcceptPreview();
private:
EngineID engine;
};
/**
* Event Company New, indicating a new company has been created.
*/
class AIEventCompanyNew : public AIEvent {
public:
static const char *GetClassName() { return "AIEventCompanyNew"; }
/**
* @param owner The new company.
*/
AIEventCompanyNew(Owner owner) :
AIEvent(AI_ET_COMPANY_NEW),
owner((AICompany::CompanyID)(byte)owner)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventCompanyNew *Convert(AIEvent *instance) { return (AIEventCompanyNew *)instance; }
/**
* Get the CompanyID of the company that has been created.
* @return The CompanyID of the company.
*/
AICompany::CompanyID GetCompanyID() { return owner; }
private:
AICompany::CompanyID owner;
};
/**
* Event Company In Trouble, indicating a company is in trouble and might go
* bankrupt soon.
*/
class AIEventCompanyInTrouble : public AIEvent {
public:
static const char *GetClassName() { return "AIEventCompanyInTrouble"; }
/**
* @param owner The company that is in trouble.
*/
AIEventCompanyInTrouble(Owner owner) :
AIEvent(AI_ET_COMPANY_IN_TROUBLE),
owner((AICompany::CompanyID)(byte)owner)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventCompanyInTrouble *Convert(AIEvent *instance) { return (AIEventCompanyInTrouble *)instance; }
/**
* Get the CompanyID of the company that is in trouble.
* @return The CompanyID of the company in trouble.
*/
AICompany::CompanyID GetCompanyID() { return owner; }
private:
AICompany::CompanyID owner;
};
/**
* Event Company Merger, indicating a company has been bought by another
* company.
*/
class AIEventCompanyMerger : public AIEvent {
public:
static const char *GetClassName() { return "AIEventCompanyMerger"; }
/**
* @param old_owner The company bought off.
* @param new_owner The company that bougth owner.
*/
AIEventCompanyMerger(Owner old_owner, Owner new_owner) :
AIEvent(AI_ET_COMPANY_MERGER),
old_owner((AICompany::CompanyID)(byte)old_owner),
new_owner((AICompany::CompanyID)(byte)new_owner)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventCompanyMerger *Convert(AIEvent *instance) { return (AIEventCompanyMerger *)instance; }
/**
* Get the CompanyID of the company that has been bought.
* @return The CompanyID of the company that has been bought.
* @note: The value below is not valid anymore as CompanyID, and
* AICompany::ResolveCompanyID will return INVALID_COMPANY. It's
* only usefull if you're keeping track of company's yourself.
*/
AICompany::CompanyID GetOldCompanyID() { return old_owner; }
/**
* Get the CompanyID of the new owner.
* @return The CompanyID of the new owner.
*/
AICompany::CompanyID GetNewCompanyID() { return new_owner; }
private:
AICompany::CompanyID old_owner;
AICompany::CompanyID new_owner;
};
/**
* Event Company Bankrupt, indicating a company has gone bankrupt.
*/
class AIEventCompanyBankrupt : public AIEvent {
public:
static const char *GetClassName() { return "AIEventCompanyBankrupt"; }
/**
* @param owner The company that has gone bankrupt.
*/
AIEventCompanyBankrupt(Owner owner) :
AIEvent(AI_ET_COMPANY_BANKRUPT),
owner((AICompany::CompanyID)(byte)owner)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventCompanyBankrupt *Convert(AIEvent *instance) { return (AIEventCompanyBankrupt *)instance; }
/**
* Get the CompanyID of the company that has gone bankrupt.
* @return The CompanyID of the company that has gone bankrupt.
*/
AICompany::CompanyID GetCompanyID() { return owner; }
private:
AICompany::CompanyID owner;
};
/**
* Event Vehicle Lost, indicating a vehicle can't find its way to its destination.
*/
class AIEventVehicleLost : public AIEvent {
public:
static const char *GetClassName() { return "AIEventVehicleLost"; }
/**
* @param vehicle_id The vehicle that is lost.
*/
AIEventVehicleLost(VehicleID vehicle_id) :
AIEvent(AI_ET_VEHICLE_LOST),
vehicle_id(vehicle_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventVehicleLost *Convert(AIEvent *instance) { return (AIEventVehicleLost *)instance; }
/**
* Get the VehicleID of the vehicle that is lost.
* @return The VehicleID of the vehicle that is lost.
*/
VehicleID GetVehicleID() { return vehicle_id; }
private:
VehicleID vehicle_id;
};
/**
* Event VehicleWaitingInDepot, indicating a vehicle has arrived a depot and is now waiting there.
*/
class AIEventVehicleWaitingInDepot : public AIEvent {
public:
static const char *GetClassName() { return "AIEventVehicleWaitingInDepot"; }
/**
* @param vehicle_id The vehicle that is waiting in a depot.
*/
AIEventVehicleWaitingInDepot(VehicleID vehicle_id) :
AIEvent(AI_ET_VEHICLE_WAITING_IN_DEPOT),
vehicle_id(vehicle_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventVehicleWaitingInDepot *Convert(AIEvent *instance) { return (AIEventVehicleWaitingInDepot *)instance; }
/**
* Get the VehicleID of the vehicle that is waiting in a depot.
* @return The VehicleID of the vehicle that is waiting in a depot.
*/
VehicleID GetVehicleID() { return vehicle_id; }
private:
VehicleID vehicle_id;
};
/**
* Event Vehicle Unprofitable, indicating a vehicle lost money last year.
*/
class AIEventVehicleUnprofitable : public AIEvent {
public:
static const char *GetClassName() { return "AIEventVehicleUnprofitable"; }
/**
* @param vehicle_id The vehicle that was unprofitable.
*/
AIEventVehicleUnprofitable(VehicleID vehicle_id) :
AIEvent(AI_ET_VEHICLE_UNPROFITABLE),
vehicle_id(vehicle_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventVehicleUnprofitable *Convert(AIEvent *instance) { return (AIEventVehicleUnprofitable *)instance; }
/**
* Get the VehicleID of the vehicle that lost money.
* @return The VehicleID of the vehicle that lost money.
*/
VehicleID GetVehicleID() { return vehicle_id; }
private:
VehicleID vehicle_id;
};
/**
* Event Industry Open, indicating a new industry has been created.
*/
class AIEventIndustryOpen : public AIEvent {
public:
static const char *GetClassName() { return "AIEventIndustryOpen"; }
/**
* @param industry_id The new industry.
*/
AIEventIndustryOpen(IndustryID industry_id) :
AIEvent(AI_ET_INDUSTRY_OPEN),
industry_id(industry_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventIndustryOpen *Convert(AIEvent *instance) { return (AIEventIndustryOpen *)instance; }
/**
* Get the IndustryID of the new industry.
* @return The IndustryID of the industry.
*/
IndustryID GetIndustryID() { return industry_id; }
private:
IndustryID industry_id;
};
/**
* Event Industry Close, indicating an industry is going to be closed.
*/
class AIEventIndustryClose : public AIEvent {
public:
static const char *GetClassName() { return "AIEventIndustryClose"; }
/**
* @param industry_id The new industry.
*/
AIEventIndustryClose(IndustryID industry_id) :
AIEvent(AI_ET_INDUSTRY_CLOSE),
industry_id(industry_id)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventIndustryClose *Convert(AIEvent *instance) { return (AIEventIndustryClose *)instance; }
/**
* Get the IndustryID of the closing industry.
* @return The IndustryID of the industry.
*/
IndustryID GetIndustryID() { return industry_id; }
private:
IndustryID industry_id;
};
/**
* Event Engine Available, indicating a new engine is available.
*/
class AIEventEngineAvailable : public AIEvent {
public:
static const char *GetClassName() { return "AIEventEngineAvailable"; }
/**
* @param engine The engine that is available.
*/
AIEventEngineAvailable(EngineID engine) :
AIEvent(AI_ET_ENGINE_AVAILABLE),
engine(engine)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventEngineAvailable *Convert(AIEvent *instance) { return (AIEventEngineAvailable *)instance; }
/**
* Get the EngineID of the new engine.
* @return The EngineID of the new engine.
*/
EngineID GetEngineID() { return engine; }
private:
EngineID engine;
};
/**
* Event Station First Vehicle, indicating a station has been visited by a vehicle for the first time.
*/
class AIEventStationFirstVehicle : public AIEvent {
public:
static const char *GetClassName() { return "AIEventStationFirstVehicle"; }
/**
* @param station The station visited for the first time.
* @param vehicle The vehicle visiting the station.
*/
AIEventStationFirstVehicle(StationID station, VehicleID vehicle) :
AIEvent(AI_ET_STATION_FIRST_VEHICLE),
station(station),
vehicle(vehicle)
{}
/**
* Convert an AIEvent to the real instance.
* @param instance The instance to convert.
* @return The converted instance.
*/
static AIEventStationFirstVehicle *Convert(AIEvent *instance) { return (AIEventStationFirstVehicle *)instance; }
/**
* Get the StationID of the visited station.
* @return The StationID of the visited station.
*/
StationID GetStationID() { return station; }
/**
* Get the VehicleID of the first vehicle.
* @return The VehicleID of the first vehicle.
*/
VehicleID GetVehicleID() { return vehicle; }
private:
StationID station;
VehicleID vehicle;
};
#endif /* AI_EVENT_TYPES_HPP */

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save