src/ai/default/default.cpp
branchNewGRF_ports
changeset 6720 35756db7e577
parent 6719 4cc327ad39d5
child 6734 6e4db2fda167
--- a/src/ai/default/default.cpp	Sat Jun 02 19:59:29 2007 +0000
+++ b/src/ai/default/default.cpp	Sat Jul 14 19:42:58 2007 +0000
@@ -132,11 +132,11 @@
 	p->ai.state_counter = 0;
 }
 
-static EngineID AiChooseTrainToBuild(RailType railtype, int32 money, byte flag, TileIndex tile)
+static EngineID AiChooseTrainToBuild(RailType railtype, Money money, byte flag, TileIndex tile)
 {
 	EngineID best_veh_index = INVALID_ENGINE;
 	byte best_veh_score = 0;
-	int32 ret;
+	CommandCost ret;
 	EngineID i;
 
 	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
@@ -152,7 +152,7 @@
 		}
 
 		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_RAIL_VEHICLE);
-		if (!CmdFailed(ret) && ret <= money && rvi->ai_rank >= best_veh_score) {
+		if (CmdSucceeded(ret) && ret.GetCost() <= money && rvi->ai_rank >= best_veh_score) {
 			best_veh_score = rvi->ai_rank;
 			best_veh_index = i;
 		}
@@ -161,7 +161,7 @@
 	return best_veh_index;
 }
 
-static EngineID AiChooseRoadVehToBuild(CargoID cargo, int32 money, TileIndex tile)
+static EngineID AiChooseRoadVehToBuild(CargoID cargo, Money money, TileIndex tile)
 {
 	EngineID best_veh_index = INVALID_ENGINE;
 	int32 best_veh_rating = 0;
@@ -172,7 +172,7 @@
 		const RoadVehicleInfo *rvi = RoadVehInfo(i);
 		const Engine* e = GetEngine(i);
 		int32 rating;
-		int32 ret;
+		CommandCost ret;
 
 		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
 			continue;
@@ -189,8 +189,8 @@
 		if (CmdFailed(ret)) continue;
 
 		/* Add the cost of refitting */
-		if (rvi->cargo_type != cargo) ret += GetRefitCost(i);
-		if (ret > money) continue;
+		if (rvi->cargo_type != cargo) ret.AddCost(GetRefitCost(i));
+		if (ret.GetCost() > money) continue;
 
 		best_veh_rating = rating;
 		best_veh_index = i;
@@ -199,15 +199,15 @@
 	return best_veh_index;
 }
 
-static EngineID AiChooseAircraftToBuild(int32 money, byte flag)
+static EngineID AiChooseAircraftToBuild(Money money, byte flag)
 {
 	EngineID best_veh_index = INVALID_ENGINE;
-	int32 best_veh_cost = 0;
+	Money best_veh_cost = 0;
 	EngineID i;
 
 	for (i = AIRCRAFT_ENGINES_INDEX; i != AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
 		const Engine* e = GetEngine(i);
-		int32 ret;
+		CommandCost ret;
 
 		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
 			continue;
@@ -216,8 +216,8 @@
 		if ((AircraftVehInfo(i)->subtype & AIR_CTOL) != flag) continue;
 
 		ret = DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_AIRCRAFT);
-		if (!CmdFailed(ret) && ret <= money && ret >= best_veh_cost) {
-			best_veh_cost = ret;
+		if (CmdSucceeded(ret) && ret.GetCost() <= money && ret.GetCost() >= best_veh_cost) {
+			best_veh_cost = ret.GetCost();
 			best_veh_index = i;
 		}
 	}
@@ -225,9 +225,9 @@
 	return best_veh_index;
 }
 
-static int32 AiGetBasePrice(const Player* p)
+static Money AiGetBasePrice(const Player* p)
 {
-	int32 base = _price.station_value;
+	Money base = _price.station_value;
 
 	// adjust base price when more expensive vehicles are available
 	switch (p->ai.railtype_to_use) {
@@ -242,7 +242,7 @@
 }
 
 #if 0
-static EngineID AiChooseShipToBuild(byte cargo, int32 money)
+static EngineID AiChooseShipToBuild(byte cargo, Money money)
 {
 	// XXX: not done
 	return INVALID_ENGINE;
@@ -251,13 +251,13 @@
 
 static EngineID AiChooseRoadVehToReplaceWith(const Player* p, const Vehicle* v)
 {
-	int32 avail_money = p->player_money + v->value;
+	Money avail_money = p->player_money + v->value;
 	return AiChooseRoadVehToBuild(v->cargo_type, avail_money, v->tile);
 }
 
 static EngineID AiChooseAircraftToReplaceWith(const Player* p, const Vehicle* v)
 {
-	int32 avail_money = p->player_money + v->value;
+	Money avail_money = p->player_money + v->value;
 	return AiChooseAircraftToBuild(
 		avail_money, AircraftVehInfo(v->engine_type)->subtype & AIR_CTOL
 	);
@@ -265,7 +265,7 @@
 
 static EngineID AiChooseTrainToReplaceWith(const Player* p, const Vehicle* v)
 {
-	int32 avail_money = p->player_money + v->value;
+	Money avail_money = p->player_money + v->value;
 	const Vehicle* u = v;
 	int num = 0;
 
@@ -331,8 +331,8 @@
 		BackupVehicleOrders(v, orderbak);
 		tile = v->tile;
 
-		if (!CmdFailed(DoCommand(0, v->index, 2, DC_EXEC, CMD_SELL_RAIL_WAGON)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE))) {
+		if (CmdSucceeded(DoCommand(0, v->index, 2, DC_EXEC, CMD_SELL_RAIL_WAGON)) &&
+				CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE))) {
 			VehicleID veh = _new_vehicle_id;
 			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
 			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_TRAIN);
@@ -360,8 +360,8 @@
 		BackupVehicleOrders(v, orderbak);
 		tile = v->tile;
 
-		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) {
+		if (CmdSucceeded(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH)) &&
+				CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) {
 			VehicleID veh = _new_vehicle_id;
 
 			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
@@ -389,8 +389,8 @@
 		BackupVehicleOrders(v, orderbak);
 		tile = v->tile;
 
-		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) {
+		if (CmdSucceeded(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
+				CmdSucceeded(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) {
 			VehicleID veh = _new_vehicle_id;
 			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
 			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
@@ -622,7 +622,6 @@
 	int dist;
 	uint same_station = 0;
 
-	// Make sure distance to closest station is < 37 pixels.
 	from_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->from);
 	to_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->to);
 
@@ -646,7 +645,19 @@
 		return false;
 	}
 
-	if (dist != 0xFFFF && dist > 37) return false;
+	/* Requiring distance to nearest station to be always under 37 tiles may be suboptimal,
+	 * Especially for longer aircraft routes that start and end pretty at any arbitrary place on map
+	 * While it may be nice for AI to cluster their creations together, hardcoded limit is not ideal.
+	 * If AI will randomly start on some isolated spot, it will never get out of there.
+	 * AI will have chance of randomly rejecting routes further than 37 tiles from their network,
+	 * so there will be some attempt to cluster the network together */
+
+	/* Random value between 37 and 292. Low values are exponentially more likely
+	 * With 50% chance the value will be under 52 tiles */
+	int min_distance = 36 + (1 << (Random() % 9)); // 0..8
+
+	/* Make sure distance to closest station is < min_distance tiles. */
+	if (dist != 0xFFFF && dist > min_distance) return false;
 
 	if (p->ai.route_type_mask != 0 &&
 			!(p->ai.route_type_mask & bitmask) &&
@@ -672,8 +683,8 @@
 		const Industry* i = (const Industry*)fr->from;
 		const IndustrySpec *indsp = GetIndustrySpec(i->type);
 
-		if (i->pct_transported[fr->cargo != indsp->produced_cargo[0]] > 0x99 ||
-				i->total_production[fr->cargo != indsp->produced_cargo[0]] == 0) {
+		if (i->last_month_pct_transported[fr->cargo != indsp->produced_cargo[0]] > 0x99 ||
+				i->last_month_production[fr->cargo != indsp->produced_cargo[0]] == 0) {
 			return false;
 		}
 	}
@@ -1371,15 +1382,55 @@
 	FoundRoute fr;
 	int i;
 
+	/* Get aircraft that would be bought for this route
+	 * (probably, as conditions may change before the route is fully built,
+	 * like running out of money and having to select different aircraft, etc ...) */
+	EngineID veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL);
+
+	/* No aircraft buildable mean no aircraft route */
+	if (veh == INVALID_ENGINE) return;
+
+	const AircraftVehicleInfo *avi = AircraftVehInfo(veh);
+
+	/* For passengers, "optimal" number of days in transit is about 80 to 100
+	 * Calculate "maximum optimal number of squares" from speed for 80 days
+	 * 20 days should be enough for takeoff, land, taxi, etc ...
+	 *
+	 * "A vehicle traveling at 100kph will cross 5.6 tiles per day" ->
+	 * Since in table aircraft speeds are in "real km/h", this should be accurate
+	 * We get max_squares = avi->max_speed * 5.6 / 100.0 * 80 */
+	int max_squares = avi->max_speed * 448 / 100;
+
+	/* For example this will be 10456 tiles for 2334 km/h aircrafts with realistic aircraft speeds
+	 * and 836 with "unrealistic" speeds, much more than the original 95 squares limit
+	 *
+	 * Size of the map, if not rectangular, it is the larger dimension of it
+	 */
+	int map_size = max(MapSizeX(), MapSizeY());
+
+	/* Minimum distance between airports is half of map size, clamped between 1% and 20% of optimum.
+	 * May prevent building plane routes at all on small maps, but they will be ineffective there, so
+	 * it is feature, not a bug.
+	 * On smaller distances, buses or trains are usually more effective approach anyway.
+	 * Additional safeguard is needing at least 20 squares,
+	 * which may trigger in highly unusual configurations */
+	int min_squares = max(20, max(max_squares / 100, min(max_squares / 5, map_size / 2)));
+
+	/* Should not happen, unless aircraft with real speed under approx. 5 km/h is selected.
+	 * No such exist, unless using some NewGRF with ballons, zeppelins or similar
+	 * slow-moving stuff. In that case, bail out, it is faster to walk by foot anyway :). */
+	if (max_squares < min_squares) return;
+
 	i = 60;
 	for (;;) {
+
 		// look for one from the subsidy list
 		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+		if (IS_INT_INSIDE(fr.distance, min_squares, max_squares + 1)) break;
 
 		// try a random one
 		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+		if (IS_INT_INSIDE(fr.distance, min_squares, max_squares + 1)) break;
 
 		// only test 60 times
 		if (--i == 0) return;
@@ -1408,7 +1459,19 @@
 	p->ai.build_kind = 0;
 	p->ai.num_build_rec = 2;
 	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 1;
+	/* Using full load always may not be the best.
+	 * Pick random value and rely on selling the vehicle & route
+	 * afterwards if the choice was utterly wrong (or maybe altering the value if AI is improved)
+	 * When traffic is very low or very assymetric, is is better not to full load
+	 * When traffic is high, full/non-full make no difference
+	 * It should be better to run with aircraft only one way full 6 times per year,
+	 * rather than two way full 1 times.
+	 * Practical experiments with AI show that the non-full-load aircrafts are usually
+	 * those that survive
+	 * Also, non-full load is more resistant against starving (by building better stations
+	 * or using exclusive rights)
+	 */
+	p->ai.num_want_fullload = CHANCE16(1, 5); // 20% chance
 //	p->ai.loco_id = INVALID_VEHICLE;
 	p->ai.order_list_blocks[0] = 0;
 	p->ai.order_list_blocks[1] = 1;
@@ -1575,10 +1638,10 @@
 	return true;
 }
 
-static int32 AiDoBuildDefaultRailTrack(TileIndex tile, const AiDefaultBlockData* p, RailType railtype, byte flag)
+static CommandCost AiDoBuildDefaultRailTrack(TileIndex tile, const AiDefaultBlockData* p, RailType railtype, byte flag)
 {
-	int32 ret;
-	int32 total_cost = 0;
+	CommandCost ret;
+	CommandCost total_cost;
 	Town *t = NULL;
 	int rating = 0;
 	int i, j, k;
@@ -1599,7 +1662,7 @@
 			}
 
 			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
+			total_cost.AddCost(ret);
 
 clear_town_stuff:;
 			if (_cleared_town != NULL) {
@@ -1621,7 +1684,7 @@
 					k = i;
 					ret = DoCommand(c, railtype, i, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
 					if (CmdFailed(ret)) return CMD_ERROR;
-					total_cost += ret;
+					total_cost.AddCost(ret);
 				}
 			}
 
@@ -1636,17 +1699,18 @@
 						ret = DoCommand(c, k, 0, flag, CMD_BUILD_SIGNALS);
 					} while (--j);
 				} else {
-					ret = _price.build_signals;
+					ret.AddCost(_price.build_signals);
 				}
 				if (CmdFailed(ret)) return CMD_ERROR;
-				total_cost += ret;
+				total_cost.AddCost(ret);
 			}
 		} else if (p->mode == 3) {
 			//Clear stuff and then build single rail.
 			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
 			ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
 			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret + _price.build_rail;
+			total_cost.AddCost(ret);
+			total_cost.AddCost(_price.build_rail);
 
 			if (flag & DC_EXEC) {
 				DoCommand(c, railtype, p->attr & 1, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_SINGLE_RAIL);
@@ -1671,7 +1735,7 @@
 }
 
 // Returns rule and cost
-static int AiBuildDefaultRailTrack(TileIndex tile, byte p0, byte p1, byte p2, byte p3, byte dir, byte cargo, RailType railtype, int32* cost)
+static int AiBuildDefaultRailTrack(TileIndex tile, byte p0, byte p1, byte p2, byte p3, byte dir, byte cargo, RailType railtype, CommandCost* cost)
 {
 	int i;
 	const AiDefaultRailBlock *p;
@@ -1680,7 +1744,7 @@
 		if (p->p0 == p0 && p->p1 == p1 && p->p2 == p2 && p->p3 == p3 &&
 				(p->dir == 0xFF || p->dir == dir || ((p->dir - 1) & 3) == dir)) {
 			*cost = AiDoBuildDefaultRailTrack(tile, p->data, railtype, DC_NO_TOWN_RATING);
-			if (!CmdFailed(*cost) && AiCheckTrackResources(tile, p->data, cargo))
+			if (CmdSucceeded(*cost) && AiCheckTrackResources(tile, p->data, cargo))
 				return i;
 		}
 	}
@@ -1758,7 +1822,7 @@
 	int j;
 	AiBuildRec *aib;
 	int rule;
-	int32 cost;
+	CommandCost cost;
 
 	// time out?
 	if (++p->ai.timeout_counter == 1388) {
@@ -2004,9 +2068,9 @@
 	uint z;
 
 	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
-		int32 cost = DoCommand(tile, arf->player->ai.railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-
-		if (!CmdFailed(cost) && cost <= (arf->player->player_money >> 4)) {
+		CommandCost cost = DoCommand(tile, arf->player->ai.railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+
+		if (CmdSucceeded(cost) && cost.GetCost() <= (arf->player->player_money >> 4)) {
 			AiBuildRailRecursive(arf, _build_tunnel_endtile, p[0] & 3);
 			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
 		}
@@ -2060,7 +2124,7 @@
 		do {
 			// Make sure the tile is not in the list of banned tiles and that a rail can be built here.
 			if (!AiIsTileBanned(arf->player, tile, p[0]) &&
-					!CmdFailed(DoCommand(tile, arf->player->ai.railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) {
+					CmdSucceeded(DoCommand(tile, arf->player->ai.railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) {
 				AiBuildRailRecursive(arf, tile, p[1]);
 			}
 
@@ -2147,8 +2211,8 @@
 		 */
 		for (i = MAX_BRIDGES - 1; i != 0; i--) {
 			if (CheckBridge_Stuff(i, bridge_len)) {
-				int32 cost = DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE);
-				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
+				CommandCost cost = DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE);
+				if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 5)) break;
 			}
 		}
 
@@ -2402,7 +2466,7 @@
 	EngineID veh;
 	int i;
 	CargoID cargo;
-	int32 cost;
+	CommandCost cost;
 	Vehicle *v;
 	VehicleID loco_id;
 
@@ -2437,7 +2501,7 @@
 		if (++p->ai.state_counter == 1000) {
 			for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
 				cost = DoCommand(tile, p->ai.wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
-				assert(!CmdFailed(cost));
+				assert(CmdSucceeded(cost));
 			}
 			p->ai.state = AIS_0;
 		}
@@ -2446,7 +2510,7 @@
 
 	// Try to build the locomotive
 	cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
-	assert(!CmdFailed(cost));
+	assert(CmdSucceeded(cost));
 	loco_id = _new_vehicle_id;
 
 	// Sell a vehicle if the train is double headed.
@@ -2542,10 +2606,10 @@
 }
 
 static bool _want_road_truck_station;
-static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag);
+static CommandCost AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag);
 
 // Returns rule and cost
-static int AiFindBestDefaultRoadBlock(TileIndex tile, byte direction, byte cargo, int32 *cost)
+static int AiFindBestDefaultRoadBlock(TileIndex tile, byte direction, byte cargo, CommandCost *cost)
 {
 	int i;
 	const AiDefaultRoadBlock *p;
@@ -2555,7 +2619,7 @@
 	for (i = 0; (p = _road_default_block_data[i]) != NULL; i++) {
 		if (p->dir == direction) {
 			*cost = AiDoBuildDefaultRoadBlock(tile, p->data, 0);
-			if (!CmdFailed(*cost) && AiCheckRoadResources(tile, p->data, cargo))
+			if (CmdSucceeded(*cost) && AiCheckRoadResources(tile, p->data, cargo))
 				return i;
 		}
 	}
@@ -2563,10 +2627,10 @@
 	return -1;
 }
 
-static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
+static CommandCost AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
 {
-	int32 ret;
-	int32 total_cost = 0;
+	CommandCost ret;
+	CommandCost total_cost;
 	Town *t = NULL;
 	int rating = 0;
 	int roadflag = 0;
@@ -2588,7 +2652,7 @@
 
 			ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
 			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
+			total_cost.AddCost(ret);
 
 			continue;
 		}
@@ -2608,7 +2672,7 @@
 clear_town_stuff:;
 
 			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
+			total_cost.AddCost(ret);
 
 			if (_cleared_town != NULL) {
 				if (t != NULL && t != _cleared_town) return CMD_ERROR;
@@ -2658,7 +2722,7 @@
 	int j;
 	AiBuildRec *aib;
 	int rule;
-	int32 cost;
+	CommandCost cost;
 
 	// time out?
 	if (++p->ai.timeout_counter == 1388) {
@@ -2695,7 +2759,7 @@
 					p->ai.state_mode = -p->ai.state_mode;
 				}
 			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) {
-				int32 r;
+				CommandCost r;
 
 				// player has money, build it.
 				aib->cur_building_rule = rule;
@@ -2705,7 +2769,7 @@
 					_road_default_block_data[rule]->data,
 					DC_EXEC | DC_NO_TOWN_RATING
 				);
-				assert(!CmdFailed(r));
+				assert(CmdSucceeded(r));
 			}
 		} while (++aib, --j);
 	}
@@ -2853,7 +2917,7 @@
 		ROAD_NW | ROAD_SW,
 		ROAD_SE | ROAD_NE
 	};
-	return !CmdFailed(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
+	return CmdSucceeded(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
 }
 
 static inline void AiCheckBuildRoadBridgeHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
@@ -2888,7 +2952,7 @@
 		}
 
 		// Is building a (rail)bridge possible at this place (type doesn't matter)?
-		if (CmdFailed(DoCommand(tile_new, tile, 0x8000, DC_AUTO, CMD_BUILD_BRIDGE)))
+		if (CmdFailed(DoCommand(tile_new, tile, ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE)))
 			return;
 		AiBuildRoadRecursive(arf, tile_new, dir2);
 
@@ -2904,9 +2968,9 @@
 	uint z;
 
 	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
-		int32 cost = DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-
-		if (!CmdFailed(cost) && cost <= (arf->player->player_money >> 4)) {
+		CommandCost cost = DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+
+		if (CmdSucceeded(cost) && cost.GetCost() <= (arf->player->player_money >> 4)) {
 			AiBuildRoadRecursive(arf, _build_tunnel_endtile, p[0] & 3);
 			if (arf->depth == 1)  AiCheckRoadPathBetter(arf, p);
 		}
@@ -3038,13 +3102,13 @@
 		 */
 		for (i = 10; i != 0; i--) {
 			if (CheckBridge_Stuff(i, bridge_len)) {
-				int32 cost = DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO, CMD_BUILD_BRIDGE);
-				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
+				CommandCost cost = DoCommand(tile, p->ai.cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE);
+				if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 5)) break;
 			}
 		}
 
 		// Build it
-		DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
+		DoCommand(tile, p->ai.cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
 
 		p->ai.state_counter = 0;
 	} else if (arf.best_ptr[0] & 0x40) {
@@ -3324,16 +3388,16 @@
 	p->ai.state_counter = 0;
 }
 
-static int32 AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
+static CommandCost AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
 {
 	uint32 avail_airports = GetValidAirports();
-	int32 total_cost = 0, ret;
+	CommandCost total_cost, ret;
 
 	for (; p->mode == 0; p++) {
 		if (!HASBIT(avail_airports, p->attr)) return CMD_ERROR;
 		ret = DoCommand(TILE_MASK(tile + ToTileIndexDiff(p->tileoffs)), p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_AIRPORT);
 		if (CmdFailed(ret)) return CMD_ERROR;
-		total_cost += ret;
+		total_cost.AddCost(ret);
 	}
 
 	return total_cost;
@@ -3361,7 +3425,7 @@
 	return true;
 }
 
-static int AiFindBestDefaultAirportBlock(TileIndex tile, byte cargo, byte heli, int32 *cost)
+static int AiFindBestDefaultAirportBlock(TileIndex tile, byte cargo, byte heli, CommandCost *cost)
 {
 	const AiDefaultBlockData *p;
 	uint i;
@@ -3372,7 +3436,7 @@
 		if (heli && !(GetAirport(p->attr)->flags & AirportFTAClass::HELICOPTERS)) continue;
 
 		*cost = AiDoBuildDefaultAirportBlock(tile, p, 0);
-		if (!CmdFailed(*cost) && AiCheckAirportResources(tile, p, cargo))
+		if (CmdSucceeded(*cost) && AiCheckAirportResources(tile, p, cargo))
 			return i;
 	}
 	return -1;
@@ -3383,7 +3447,7 @@
 	int i, j;
 	AiBuildRec *aib;
 	int rule;
-	int32 cost;
+	CommandCost cost;
 
 	// time out?
 	if (++p->ai.timeout_counter == 1388) {
@@ -3422,7 +3486,7 @@
 				}
 			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) {
 				// player has money, build it.
-				int32 r;
+				CommandCost r;
 
 				aib->cur_building_rule = rule;
 
@@ -3431,7 +3495,7 @@
 					_airport_default_block_data[rule],
 					DC_EXEC | DC_NO_TOWN_RATING
 				);
-				assert(!CmdFailed(r));
+				assert(CmdSucceeded(r));
 			}
 		} while (++aib, --j);
 	} while (--i);
@@ -3837,7 +3901,7 @@
 
 static void AiAdjustLoan(const Player* p)
 {
-	int32 base = AiGetBasePrice(p);
+	Money base = AiGetBasePrice(p);
 
 	if (p->player_money > base * 1400) {
 		// Decrease loan