Changeset - r4000:702cb45b8eab
[Not reviewed]
master
0 44 0
tron - 18 years ago 2006-06-10 08:37:41
tron@openttd.org
(svn r5210) Many small changes which piled up: const, unsigned, variable scope, CSE for readability, DeMorgan, if cascades -> switch, whitespace, parentheses, bracing, misc.
43 files changed with 380 insertions and 390 deletions:
0 comments (0 inline, 0 general)
ai/ai.c
Show inline comments
 
@@ -76,75 +76,78 @@ static void AI_PutCommandInQueue(PlayerI
 
		com->text = strdup(_cmd_text);
 
		_cmd_text = NULL;
 
	}
 
}
 

	
 
/**
 
 * Executes a raw DoCommand for the AI.
 
 */
 
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
 
{
 
	PlayerID old_lp;
 
	int32 res = 0;
 
	const char* tmp_cmdtext;
 

	
 
	/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
 
	 *   person.. should we check for those funny jokes?
 
	 */
 

	
 
	/* The test already resets _cmd_text, so backup the pointer */
 
	tmp_cmdtext = _cmd_text;
 

	
 
	/* First, do a test-run to see if we can do this */
 
	res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
 
	/* 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)) {
 
	if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
 
		return res;
 
	}
 

	
 
	/* Restore _cmd_text */
 
	_cmd_text = tmp_cmdtext;
 

	
 
	/* If we did a DC_EXEC, and the command did not return an error, execute it
 
	    over the network */
 
	 * over the network */
 
	if (flags & DC_AUTO)                  procc |= CMD_AUTO;
 
	if (flags & DC_NO_WATER)              procc |= CMD_NO_WATER;
 

	
 
	/* NetworkSend_Command needs _local_player to be set correctly, so
 
	    adjust it, and put it back right after the function */
 
	 * adjust it, and put it back right after the function */
 
	old_lp = _local_player;
 
	_local_player = _current_player;
 

	
 
#ifdef ENABLE_NETWORK
 
	/* Send the command */
 
	if (_networking)
 
	if (_networking) {
 
		/* Network is easy, send it to his handler */
 
		NetworkSend_Command(tile, p1, p2, procc, callback);
 
	else
 
	} 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_player, tile, p1, p2, procc, callback);
 
	}
 

	
 
	/* Set _local_player back */
 
	_local_player = old_lp;
 

	
 
	return res;
 
}
 

	
 

	
 
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
 
{
 
	return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
 
}
 

	
 

	
 
/**
 
 * Run 1 tick of the AI. Don't overdo it, keep it realistic.
 
 */
 
static void AI_RunTick(PlayerID player)
 
{
 
	extern void AiNewDoGameLoop(Player *p);
 

	
 
	Player *p = GetPlayer(player);
 
	_current_player = player;
 

	
 
@@ -152,111 +155,110 @@ static void AI_RunTick(PlayerID player)
 
		AiNewDoGameLoop(p);
 
	} else {
 
		/* Enable all kind of cheats the old AI needs in order to operate correctly... */
 
		_is_old_ai_player = true;
 
		AiDoGameLoop(p);
 
		_is_old_ai_player = false;
 
	}
 
}
 

	
 

	
 
/**
 
 * The gameloop for AIs.
 
 *  Handles one tick for all the AIs.
 
 */
 
void AI_RunGameLoop(void)
 
{
 
	/* Don't do anything if ai is disabled */
 
	if (!_ai.enabled) return;
 

	
 
	/* Don't do anything if we are a network-client
 
	 *  (too bad when a client joins, he thinks the AIs are real, so it wants to control
 
	 *   them.. this avoids that, while loading a network game in singleplayer, does make
 
	 *   the AIs to continue ;))
 
	 */
 
	if (_networking && !_network_server && !_ai.network_client)
 
		return;
 
	if (_networking && !_network_server && !_ai.network_client) return;
 

	
 
	/* New tick */
 
	_ai.tick++;
 

	
 
	/* Make sure the AI follows the difficulty rule.. */
 
	assert(_opt.diff.competitor_speed <= 4);
 
	if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0)
 
		return;
 
	if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
 

	
 
	/* Check for AI-client (so joining a network with an AI) */
 
	if (_ai.network_client && _ai_player[_ai.network_playas].active) {
 
		/* Run the script */
 
		AI_DequeueCommands(_ai.network_playas);
 
		AI_RunTick(_ai.network_playas);
 
	} else if (!_networking || _network_server) {
 
		/* Check if we want to run AIs (server or SP only) */
 
		Player *p;
 
		const Player* p;
 

	
 
		FOR_ALL_PLAYERS(p) {
 
			if (p->is_active && p->is_ai) {
 
				/* This should always be true, else something went wrong... */
 
				assert(_ai_player[p->index].active);
 

	
 
				/* Run the script */
 
				AI_DequeueCommands(p->index);
 
				AI_RunTick(p->index);
 
			}
 
		}
 
	}
 

	
 
	_current_player = OWNER_NONE;
 
}
 

	
 
/**
 
 * A new AI sees the day of light. You can do here what ever you think is needed.
 
 */
 
void AI_StartNewAI(PlayerID player)
 
{
 
	assert(player < MAX_PLAYERS);
 

	
 
	/* Called if a new AI is booted */
 
	_ai_player[player].active = true;
 
}
 

	
 
/**
 
 * This AI player died. Give it some chance to make a final puf.
 
 */
 
void AI_PlayerDied(PlayerID player)
 
{
 
	if (_ai.network_client && _ai.network_playas == player)
 
	if (_ai.network_client && _ai.network_playas == player) {
 
		_ai.network_playas = OWNER_SPECTATOR;
 
	}
 

	
 
	/* Called if this AI died */
 
	_ai_player[player].active = false;
 
}
 

	
 
/**
 
 * Initialize some AI-related stuff.
 
 */
 
void AI_Initialize(void)
 
{
 
	bool ai_network_client = _ai.network_client;
 

	
 
	/* First, make sure all AIs are DEAD! */
 
	AI_Uninitialize();
 

	
 
	memset(&_ai, 0, sizeof(_ai));
 
	memset(&_ai_player, 0, sizeof(_ai_player));
 

	
 
	_ai.network_client = ai_network_client;
 
	_ai.network_playas = OWNER_SPECTATOR;
 
	_ai.enabled = true;
 
}
 

	
 
/**
 
 * Deinitializer for AI-related stuff.
 
 */
 
void AI_Uninitialize(void)
 
{
 
	Player* p;
 
	const Player* p;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
 
	}
 
}
ai/default/default.c
Show inline comments
 
@@ -329,51 +329,51 @@ static void AiHandleReplaceTrain(Player 
 
	}
 
}
 

	
 
static void AiHandleReplaceRoadVeh(Player *p)
 
{
 
	Vehicle *v = p->ai.cur_veh;
 
	BackuppedOrders orderbak[1];
 
	EngineID veh;
 

	
 
	if (!IsRoadVehInDepotStopped(v)) {
 
		AiHandleGotoDepot(p, CMD_SEND_ROADVEH_TO_DEPOT);
 
		return;
 
	}
 

	
 
	veh = AiChooseRoadVehToReplaceWith(p, v);
 
	if (veh != INVALID_ENGINE) {
 
		TileIndex tile;
 

	
 
		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)) ) {
 
			VehicleID veh = _new_vehicle_id;
 

	
 
			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
 
			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
 

	
 
			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
 
		}
 
	}
 
}
 

	
 
static void AiHandleReplaceAircraft(Player *p)
 
{
 
	Vehicle *v = p->ai.cur_veh;
 
	BackuppedOrders orderbak[1];
 
	EngineID veh;
 

	
 
	if (!IsAircraftInHangarStopped(v)) {
 
		AiHandleGotoDepot(p, CMD_SEND_AIRCRAFT_TO_HANGAR);
 
		return;
 
	}
 

	
 
	veh = AiChooseAircraftToReplaceWith(p, v);
 
	if (veh != INVALID_ENGINE) {
 
		TileIndex tile;
 

	
 
		BackupVehicleOrders(v, orderbak);
 
		tile = v->tile;
 

	
 
		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
 
@@ -1587,50 +1587,49 @@ clear_town_stuff:;
 
					if (CmdFailed(ret)) return CMD_ERROR;
 
					total_cost += ret;
 
				}
 
			}
 

	
 
			/* signals too? */
 
			if (j & 3) {
 
				/* XXX - we need to check manually whether we can build a signal if DC_EXEC is
 
				   not set because the rail has not actually been built */
 
				if (!IsTileType(c, MP_RAILWAY)) return CMD_ERROR;
 

	
 
				if (flag & DC_EXEC) {
 
					j = 4 - j;
 
					do {
 
						ret = DoCommand(c, k, 0, flag, CMD_BUILD_SIGNALS);
 
					} while (--j);
 
				} else {
 
					ret = _price.build_signals;
 
				}
 
				if (CmdFailed(ret)) return CMD_ERROR;
 
				total_cost += ret;
 
			}
 
		} else if (p->mode == 3) {
 
			//Clear stuff and then build single rail.
 
			if (GetTileSlope(c, NULL) != SLOPE_FLAT)
 
				return CMD_ERROR;
 
			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;
 

	
 
			if (flag & DC_EXEC) {
 
				DoCommand(c, railtype, p->attr&1, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_SINGLE_RAIL);
 
			}
 

	
 
			goto clear_town_stuff;
 
		} else {
 
			// Unk
 
			break;
 
		}
 

	
 
		p++;
 
	}
 

	
 
	if (!(flag & DC_EXEC)) {
 
		if (t != NULL && rating > t->ratings[_current_player]) {
 
			return CMD_ERROR;
 
		}
 
	}
 

	
 
	return total_cost;
 
@@ -1906,161 +1905,158 @@ static bool AiCheckRailPathBetter(AiRail
 
			arf->best_dist = arf->cur_best_dist;
 
			arf->best_ptr = p;
 
			arf->best_tile = arf->cur_best_tile;
 
			better = true;
 
		}
 
	} else if (arf->recursive_mode > 1) {
 
		// Mode is 2.
 
		if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
 
			arf->best_depth = arf->cur_best_depth;
 
			arf->best_dist = 0;
 
			arf->best_ptr = p;
 
			arf->best_tile = 0;
 
			better = true;
 
		}
 
	}
 
	arf->recursive_mode = 0;
 
	arf->cur_best_dist = (uint)-1;
 
	arf->cur_best_depth = 0xff;
 

	
 
	return better;
 
}
 

	
 
static inline void AiCheckBuildRailBridgeHere(AiRailFinder *arf, TileIndex tile, const byte *p)
 
{
 
	TileIndex tile_new;
 
	Slope tileh;
 
	uint z;
 
	bool flag;
 

	
 
	int dir2 = p[0] & 3;
 

	
 
	tileh = GetTileSlope(tile, &z);
 
	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
 
		tile_new = tile;
 
		TileIndex tile_new = tile;
 

	
 
		// Allow bridges directly over bottom tiles
 
		flag = z == 0;
 
		for (;;) {
 
			TileType type;
 

	
 
			if ((TileIndexDiff)tile_new < -TileOffsByDir(dir2)) return; // Wraping around map, no bridge possible!
 
			tile_new = TILE_MASK(tile_new + TileOffsByDir(dir2));
 
			type = GetTileType(tile_new);
 

	
 
			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile_new, NULL) != SLOPE_FLAT) {
 
				if (!flag) return;
 
				break;
 
			}
 
			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
 
			flag = true;
 
		}
 

	
 
		// Is building a (rail)bridge possible at this place (type doesn't matter)?
 
		if (CmdFailed(DoCommand(tile_new, tile, 0 | arf->player->ai.railtype_to_use << 8,
 
			DC_AUTO, CMD_BUILD_BRIDGE)) )
 
				return;
 
		AiBuildRailRecursive(arf, tile_new, dir2);
 

	
 
		// At the bottom depth, check if the new path is better than the old one.
 
		if (arf->depth == 1) {
 
			if (AiCheckRailPathBetter(arf, p))
 
				arf->bridge_end_tile = tile_new;
 
		}
 
	}
 
}
 

	
 
static inline void AiCheckBuildRailTunnelHere(AiRailFinder *arf, TileIndex tile, const byte *p)
 
{
 
	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)) {
 
			AiBuildRailRecursive(arf, _build_tunnel_endtile, p[0]&3);
 
			if (arf->depth == 1) {
 
				AiCheckRailPathBetter(arf, p);
 
			}
 
			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
 
		}
 
	}
 
}
 

	
 

	
 
static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, int dir)
 
{
 
	const byte *p;
 

	
 
	tile = TILE_MASK(tile + TileOffsByDir(dir));
 

	
 
	// Reached destination?
 
	if (tile == arf->final_tile) {
 
		if (arf->final_dir != (dir^2)) {
 
			if (arf->recursive_mode != 2)
 
				arf->recursive_mode = 1;
 
		} else if (arf->recursive_mode != 2) {
 
			arf->recursive_mode = 2;
 
			arf->cur_best_depth = arf->depth;
 
		} else {
 
			if (arf->depth < arf->cur_best_depth)
 
				arf->cur_best_depth = arf->depth;
 
		}
 
		return;
 
	}
 

	
 
	// Depth too deep?
 
	if (arf->depth >= 4) {
 
		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
 

	
 
		if (dist < arf->cur_best_dist) {
 
			// Store the tile that is closest to the final position.
 
			arf->cur_best_depth = arf->depth;
 
			arf->cur_best_dist = dist;
 
			arf->cur_best_tile = tile;
 
			arf->cur_best_dir = dir;
 
		}
 
		return;
 
	}
 

	
 
	// Increase recursion depth
 
	arf->depth++;
 

	
 
	// Grab pointer to list of stuff that is possible to build
 
	p = _ai_table_15[dir];
 

	
 
	// Try to build a single rail in all directions.
 
	if (GetTileZ(tile) == 0) {
 
		p += 6;
 
	} else {
 
		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))) {
 
				AiBuildRailRecursive(arf, tile, p[1]);
 
			}
 

	
 
			// At the bottom depth?
 
			if (arf->depth == 1) {
 
				AiCheckRailPathBetter(arf, p);
 
			}
 
			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
 

	
 
			p += 2;
 
		} while (!(p[0]&0x80));
 
	}
 

	
 
	AiCheckBuildRailBridgeHere(arf, tile, p);
 
	AiCheckBuildRailTunnelHere(arf, tile, p+1);
 

	
 
	arf->depth--;
 
}
 

	
 

	
 
static const byte _dir_table_3[]= {0x25, 0x2A, 0x19, 0x16};
 

	
 
static void AiBuildRailConstruct(Player *p)
 
{
 
	AiRailFinder arf;
 
	int i;
 

	
 
	// Check too much lookahead?
 
	if (AiDoFollowTrack(p)) {
 
		p->ai.state_counter = (Random()&0xE)+6; // Destruct this amount of blocks
 
		p->ai.state_mode = 1; // Start destruct
 

	
 
@@ -2072,77 +2068,78 @@ static void AiBuildRailConstruct(Player 
 
	// Setup recursive finder and call it.
 
	arf.player = p;
 
	arf.final_tile = p->ai.cur_tile_b;
 
	arf.final_dir = p->ai.cur_dir_b;
 
	arf.depth = 0;
 
	arf.recursive_mode = 0;
 
	arf.best_ptr = NULL;
 
	arf.cur_best_dist = (uint)-1;
 
	arf.cur_best_depth = 0xff;
 
	arf.best_dist = (uint)-1;
 
	arf.best_depth = 0xff;
 
	arf.cur_best_tile = 0;
 
	arf.best_tile = 0;
 
	AiBuildRailRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a);
 

	
 
	// Reached destination?
 
	if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
 
		p->ai.state_mode = 255;
 
		return;
 
	}
 

	
 
	// Didn't find anything to build?
 
	if (arf.best_ptr == NULL) {
 
		// Terraform some
 
		for (i=0; i!=5; i++)
 
		for (i = 0; i != 5; i++) {
 
			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
 
		}
 

	
 
		if (++p->ai.state_counter == 21) {
 
			p->ai.state_counter = 40;
 
			p->ai.state_mode = 1;
 

	
 
			// Ban this tile
 
			AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a)));
 
		}
 
		return;
 
	}
 

	
 
	p->ai.cur_tile_a += TileOffsByDir(p->ai.cur_dir_a);
 

	
 
	if (arf.best_ptr[0] & 0x80) {
 
		int i;
 
		int32 bridge_len = GetBridgeLength(arf.bridge_end_tile, p->ai.cur_tile_a);
 

	
 
		/*	Figure out what (rail)bridge type to build
 
				start with best bridge, then go down to worse and worse bridges
 
				unnecessary to check for worse bridge (i=0), since AI will always build that.
 
				AI is so fucked up that fixing this small thing will probably not solve a thing
 
		/* Figure out which (rail)bridge type to build
 
		 * start with best bridge, then go down to worse and worse bridges
 
		 * unnecessary to check for worst bridge (i=0), since AI will always build
 
		 * that. AI is so fucked up that fixing this small thing will probably not
 
		 * solve a thing
 
		*/
 
		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;
 
				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
 
			}
 
		}
 

	
 
		// Build it
 
		DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
 

	
 
		p->ai.cur_tile_a = arf.bridge_end_tile;
 
		p->ai.state_counter = 0;
 
	} else if (arf.best_ptr[0]&0x40) {
 
		// tunnel
 
		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
 
		p->ai.cur_tile_a = _build_tunnel_endtile;
 
		p->ai.state_counter = 0;
 
	} else {
 
		// rail
 
		p->ai.cur_dir_a = arf.best_ptr[1];
 
		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, arf.best_ptr[0],
 
			DC_EXEC | DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL);
 
		p->ai.state_counter = 0;
 
	}
 

	
 
	if (arf.best_tile != 0) {
 
		for (i = 0; i != 2; i++) {
 
			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
 
@@ -2327,136 +2324,132 @@ static StationID AiGetStationIdByDef(Til
 
{
 
	const AiDefaultBlockData *p = _default_rail_track_data[id]->data;
 
	while (p->mode != 1) p++;
 
	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
 
}
 

	
 
static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
 
{
 
	EngineID best_veh_index = INVALID_ENGINE;
 
	EngineID i;
 
	uint16 best_capacity = 0;
 
	uint16 best_speed    = 0;
 
	uint speed;
 

	
 
	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const Engine* e = GetEngine(i);
 

	
 
		if (!IsCompatibleRail(e->railtype, railtype) ||
 
				!(rvi->flags & RVI_WAGON) ||
 
				!HASBIT(e->player_avail, _current_player)) {
 
			continue;
 
		}
 

	
 
		if (rvi->cargo_type != cargo) {
 
			continue;
 
		}
 
		if (rvi->cargo_type != cargo) continue;
 

	
 
		/* max_speed of 0 indicates no speed limit */
 
		speed = rvi->max_speed == 0 ? 0xFFFF : rvi->max_speed;
 

	
 
		if (rvi->capacity >= best_capacity && speed >= best_speed) {
 
			best_capacity = rvi->capacity;
 
			best_speed    = best_speed;
 
			best_veh_index = i;
 
		}
 
	}
 

	
 
	return best_veh_index;
 
}
 

	
 
static void AiStateBuildRailVeh(Player *p)
 
{
 
	const AiDefaultBlockData *ptr;
 
	TileIndex tile;
 
	EngineID veh;
 
	int i;
 
	CargoID cargo;
 
	int32 cost;
 
	Vehicle *v;
 
	uint loco_id;
 
	VehicleID loco_id;
 

	
 
	ptr = _default_rail_track_data[p->ai.src.cur_building_rule]->data;
 
	while (ptr->mode != 0) ptr++;
 

	
 
	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
 

	
 

	
 
	cargo = p->ai.cargo_type;
 
	for (i = 0;;) {
 
		if (p->ai.wagon_list[i] == INVALID_VEHICLE) {
 
			veh = AiFindBestWagon(cargo, p->ai.railtype_to_use);
 
			/* veh will return INVALID_ENGINE if no suitable wagon is available.
 
			 * We shall treat this in the same way as having no money */
 
			if (veh == INVALID_ENGINE) goto handle_nocash;
 
			cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
 
			if (CmdFailed(cost)) goto handle_nocash;
 
			p->ai.wagon_list[i] = _new_vehicle_id;
 
			p->ai.wagon_list[i + 1] = INVALID_VEHICLE;
 
			return;
 
		}
 
		if (cargo == CT_MAIL)
 
			cargo = CT_PASSENGERS;
 
		if (++i == p->ai.num_wagons * 2 - 1)
 
			break;
 
		if (cargo == CT_MAIL) cargo = CT_PASSENGERS;
 
		if (++i == p->ai.num_wagons * 2 - 1) break;
 
	}
 

	
 
	// Which locomotive to build?
 
	veh = AiChooseTrainToBuild(p->ai.railtype_to_use, p->player_money, (cargo!=CT_PASSENGERS)?1:0, tile);
 
	veh = AiChooseTrainToBuild(p->ai.railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile);
 
	if (veh == INVALID_ENGINE) {
 
handle_nocash:
 
		// after a while, if AI still doesn't have cash, get out of this block by selling the wagons.
 
		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));
 
			}
 
			p->ai.state =	AIS_0;
 
		}
 
		return;
 
	}
 

	
 
	// Try to build the locomotive
 
	cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
 
	assert(!CmdFailed(cost));
 
	loco_id = _new_vehicle_id;
 

	
 
	// Sell a vehicle if the train is double headed.
 
	v = GetVehicle(loco_id);
 
	if (v->next != NULL) {
 
		i = p->ai.wagon_list[p->ai.num_wagons * 2 - 2];
 
		p->ai.wagon_list[p->ai.num_wagons * 2 - 2] = INVALID_VEHICLE;
 
		DoCommand(tile, i, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
 
	}
 

	
 
	// Move the wagons onto the train
 
	for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
 
		DoCommand(tile, p->ai.wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
 
	}
 

	
 
	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
 
		AiBuildRec *aib = (&p->ai.src) + p->ai.order_list_blocks[i];
 
		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
 
		bool is_pass = (
 
			p->ai.cargo_type == CT_PASSENGERS ||
 
			p->ai.cargo_type == CT_MAIL ||
 
			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
 
		);
 
		Order order;
 

	
 
		order.type = OT_GOTO_STATION;
 
		order.flags = 0;
 
		order.station = AiGetStationIdByDef(aib->use_tile, aib->cur_building_rule);
 

	
 
		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
 
		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
 
			order.flags |= OF_FULL_LOAD;
 

	
 
		DoCommand(0, loco_id + (i << 16),	PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
 
	}
 

	
 
	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_TRAIN);
 

	
 
	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
 

	
 
	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
 

	
 
@@ -2594,53 +2587,50 @@ clear_town_stuff:;
 
		} else if (p->mode == 3) {
 
			if (flag & DC_EXEC) continue;
 

	
 
			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
 

	
 
			if (!IsTileType(c, MP_STREET) || GetRoadTileType(c) != ROAD_TILE_NORMAL) {
 
				ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
 
				if (CmdFailed(ret)) return CMD_ERROR;
 
			}
 

	
 
		}
 
	}
 

	
 
	if (!_want_road_truck_station && !(roadflag & 2)) return CMD_ERROR;
 

	
 
	if (!(flag & DC_EXEC)) {
 
		if (t != NULL && rating > t->ratings[_current_player]) return CMD_ERROR;
 
	}
 
	return total_cost;
 
}
 

	
 
// Make sure the blocks are not too close to each other
 
static bool AiCheckBlockDistances(Player *p, TileIndex tile)
 
{
 
	AiBuildRec *aib;
 
	int num;
 

	
 
	num = p->ai.num_build_rec;
 
	aib = &p->ai.src;
 
	const AiBuildRec* aib = &p->ai.src;
 
	uint num = p->ai.num_build_rec;
 

	
 
	do {
 
		if (aib->cur_building_rule != 255) {
 
			if (DistanceManhattan(aib->use_tile, tile) < 9) return false;
 
		}
 
	} while (++aib, --num);
 

	
 
	return true;
 
}
 

	
 

	
 
static void AiStateBuildDefaultRoadBlocks(Player *p)
 
{
 
	uint i;
 
	int j;
 
	AiBuildRec *aib;
 
	int rule;
 
	int32 cost;
 

	
 
	// time out?
 
	if (++p->ai.timeout_counter == 1388) {
 
		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
 
		return;
 
	}
 
@@ -2814,101 +2804,99 @@ static bool AiCheckRoadFinished(Player *
 

	
 
	if (are.best_dist == 0) return true;
 

	
 
	p->ai.cur_tile_a = are.best_tile;
 
	p->ai.cur_dir_a = _dir_by_track[are.best_track];
 
	return false;
 
}
 

	
 

	
 
static bool AiBuildRoadHelper(TileIndex tile, int flags, int type)
 
{
 
	static const byte _road_bits[] = {
 
		8+2,
 
		1+4,
 
		1+8,
 
		4+2,
 
		1+2,
 
		8+4,
 
	};
 
	return !CmdFailed(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
 
}
 

	
 
static inline void AiCheckBuildRoadBridgeHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
 
{
 
	TileIndex tile_new;
 
	Slope tileh;
 
	uint z;
 
	bool flag;
 

	
 
	int dir2 = p[0] & 3;
 

	
 
	tileh = GetTileSlope(tile, &z);
 
	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
 
		tile_new = tile;
 
		TileIndex tile_new = tile;
 

	
 
		// Allow bridges directly over bottom tiles
 
		flag = z == 0;
 
		for (;;) {
 
			TileType type;
 

	
 
			if ((TileIndexDiff)tile_new < -TileOffsByDir(dir2)) return; // Wraping around map, no bridge possible!
 
			tile_new = TILE_MASK(tile_new + TileOffsByDir(dir2));
 
			type = GetTileType(tile_new);
 

	
 
			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
 
				// Allow a bridge if either we have a tile that's water, rail or street,
 
				// or if we found an up tile.
 
				if (!flag) return;
 
				break;
 
			}
 
			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
 
			flag = true;
 
		}
 

	
 
		// 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)))
 
			return;
 
		AiBuildRoadRecursive(arf, tile_new, dir2);
 

	
 
		// At the bottom depth, check if the new path is better than the old one.
 
		if (arf->depth == 1) {
 
			if (AiCheckRoadPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
 
		}
 
	}
 
}
 

	
 
static inline void AiCheckBuildRoadTunnelHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
 
{
 
	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)) {
 
			AiBuildRoadRecursive(arf, _build_tunnel_endtile, p[0]&3);
 
			if (arf->depth == 1) {
 
				AiCheckRoadPathBetter(arf, p);
 
			}
 
			if (arf->depth == 1)  AiCheckRoadPathBetter(arf, p);
 
		}
 
	}
 
}
 

	
 

	
 

	
 
static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, int dir)
 
{
 
	const byte *p;
 

	
 
	tile = TILE_MASK(tile + TileOffsByDir(dir));
 

	
 
	// Reached destination?
 
	if (tile == arf->final_tile) {
 
		if ((arf->final_dir^2) == dir) {
 
			arf->recursive_mode = 2;
 
			arf->cur_best_depth = arf->depth;
 
		}
 
		return;
 
	}
 

	
 
	// Depth too deep?
 
	if (arf->depth >= 4) {
 
		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
 
@@ -3011,80 +2999,80 @@ do_some_terraform:
 
		bridge_len = GetBridgeLength(tile, p->ai.cur_tile_a); // tile
 

	
 
		/*	Figure out what (road)bridge type to build
 
				start with best bridge, then go down to worse and worse bridges
 
				unnecessary to check for worse bridge (i=0), since AI will always build that.
 
				AI is so fucked up that fixing this small thing will probably not solve a thing
 
		*/
 
		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;
 
			}
 
		}
 

	
 
		// Build it
 
		DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
 

	
 
		p->ai.state_counter = 0;
 
	} else if (arf.best_ptr[0]&0x40) {
 
		// tunnel
 
		DoCommand(tile, 0x200, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
 
		p->ai.cur_tile_a = _build_tunnel_endtile;
 
		p->ai.state_counter = 0;
 
	} else {
 

	
 
		// road
 
		if (!AiBuildRoadHelper(tile, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, arf.best_ptr[0]))
 
			goto do_some_terraform;
 

	
 
		p->ai.cur_dir_a = arf.best_ptr[1];
 
		p->ai.cur_tile_a = tile;
 
		p->ai.state_counter = 0;
 
	}
 

	
 
	if (arf.best_tile != 0) {
 
		for (i = 0; i != 2; i++)
 
			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
 
	}
 
}
 

	
 

	
 
static void AiBuildRoad(Player *p)
 
{
 
	if (p->ai.state_mode < 1) {
 
		// Construct mode, build new road.
 
		AiBuildRoadConstruct(p);
 
	} else if (p->ai.state_mode == 1) {
 
		// Destruct mode, not implemented for roads.
 
		p->ai.state_mode = 2;
 
		p->ai.state_counter = 0;
 
	} else if (p->ai.state_mode == 2) {
 
		uint i;
 

	
 
		// Terraform some and then try building again.
 
		for (i = 0; i != 4; i++)
 
		for (i = 0; i != 4; i++) {
 
			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
 
		}
 

	
 
		if (++p->ai.state_counter == 4) {
 
			p->ai.state_counter = 0;
 
			p->ai.state_mode = 0;
 
		}
 
	}
 
}
 

	
 
static TileIndex AiGetRoadBlockEdge(byte rule, TileIndex tile, int *dir)
 
{
 
	const AiDefaultBlockData *p = _road_default_block_data[rule]->data;
 
	while (p->mode != 1) p++;
 
	*dir = p->attr;
 
	return TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
 
}
 

	
 

	
 
static void AiStateBuildRoad(Player *p)
 
{
 
	int num;
 
	AiBuildRec *aib;
 
	byte cmd;
 
	TileIndex tile;
 
	int dir;
 
@@ -3135,49 +3123,49 @@ static void AiStateBuildRoad(Player *p)
 
	aib = (&p->ai.src) + (cmd&0xF);
 
	tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
 
	p->ai.start_tile_b = tile;
 
	p->ai.cur_tile_b = tile;
 
	p->ai.start_dir_b = dir;
 
	p->ai.cur_dir_b = dir;
 

	
 
	// And setup state.
 
	p->ai.state_mode = 2;
 
	p->ai.state_counter = 0;
 
	p->ai.banned_tile_count = 0;
 
}
 

	
 
static StationID AiGetStationIdFromRoadBlock(TileIndex tile, int id)
 
{
 
	const AiDefaultBlockData *p = _road_default_block_data[id]->data;
 
	while (p->mode != 1) p++;
 
	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
 
}
 

	
 
static void AiStateBuildRoadVehicles(Player *p)
 
{
 
	const AiDefaultBlockData *ptr;
 
	TileIndex tile;
 
	uint loco_id;
 
	VehicleID loco_id;
 
	EngineID veh;
 
	uint i;
 

	
 
	ptr = _road_default_block_data[p->ai.src.cur_building_rule]->data;
 
	for (; ptr->mode != 0; ptr++) {}
 
	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
 

	
 
	veh = AiChooseRoadVehToBuild(p->ai.cargo_type, p->player_money, tile);
 
	if (veh == INVALID_ENGINE) {
 
		p->ai.state = AIS_0;
 
		return;
 
	}
 

	
 
	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) return;
 

	
 
	loco_id = _new_vehicle_id;
 

	
 
	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
 
		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
 
		bool is_pass = (
 
			p->ai.cargo_type == CT_PASSENGERS ||
 
			p->ai.cargo_type == CT_MAIL ||
 
			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
 
		);
 
@@ -3206,49 +3194,49 @@ static void AiStateDeleteRoadBlocks(Play
 
	int num;
 
	AiBuildRec *aib;
 
	const AiDefaultBlockData *b;
 

	
 
	num = p->ai.num_build_rec;
 
	aib = &p->ai.src;
 
	do {
 
		if (aib->cur_building_rule != 255) {
 
			b = _road_default_block_data[aib->cur_building_rule]->data;
 
			while (b->mode != 4) {
 
				if (b->mode <= 1) {
 
					DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
				}
 
				b++;
 
			}
 
		}
 
	} while (++aib,--num);
 

	
 
	p->ai.state = AIS_0;
 
}
 

	
 

	
 
static void AiStateAirportStuff(Player *p)
 
{
 
	Station *st;
 
	const Station* st;
 
	byte acc_planes;
 
	int i;
 
	AiBuildRec *aib;
 
	byte rule;
 

	
 
	// Here we look for an airport we could use instead of building a new
 
	// one. If we find such an aiport for any waypoint,
 
	// AiStateBuildDefaultAirportBlocks() will kindly skip that one when
 
	// building the waypoints.
 

	
 
	i = 0;
 
	do {
 
		// We do this all twice - once for the source (town in the case
 
		// of oilrig route) and then for the destination (oilrig in the
 
		// case of oilrig route).
 
		aib = &p->ai.src + i;
 

	
 
		FOR_ALL_STATIONS(st) {
 
			// Dismiss ghost stations.
 
			if (st->xy == 0) continue;
 

	
 
			// Is this an airport?
 
			if (!(st->facilities & FACIL_AIRPORT)) continue;
 

	
 
@@ -3428,49 +3416,49 @@ static void AiStateBuildDefaultAirportBl
 
	// check if we're done with all of them
 
	aib = &p->ai.src;
 
	j = p->ai.num_build_rec;
 
	do {
 
		if (aib->cur_building_rule == 255) return;
 
	} while (++aib,--j);
 

	
 
	// yep, all are done. switch state.
 
	p->ai.state = AIS_BUILD_AIRCRAFT_VEHICLES;
 
}
 

	
 
static StationID AiGetStationIdFromAircraftBlock(TileIndex tile, int id)
 
{
 
	const AiDefaultBlockData *p = _airport_default_block_data[id];
 
	while (p->mode != 1) p++;
 
	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
 
}
 

	
 
static void AiStateBuildAircraftVehicles(Player *p)
 
{
 
	const AiDefaultBlockData *ptr;
 
	TileIndex tile;
 
	EngineID veh;
 
	int i;
 
	uint loco_id;
 
	VehicleID loco_id;
 

	
 
	ptr = _airport_default_block_data[p->ai.src.cur_building_rule];
 
	for (;ptr->mode!=0;ptr++) {}
 

	
 
	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
 

	
 
	veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind!=0 ? 1 : 0);
 
	if (veh == INVALID_ENGINE) return;
 

	
 
	/* XXX - Have the AI pick the hangar terminal in an airport. Eg get airport-type
 
	 * and offset to the FIRST depot because the AI picks the st->xy tile */
 
	tile += ToTileIndexDiff(GetAirport(GetStationByTile(tile)->airport_type)->airport_depots[0]);
 
	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) return;
 
	loco_id = _new_vehicle_id;
 

	
 
	for (i=0; p->ai.order_list_blocks[i] != 0xFF; i++) {
 
		AiBuildRec *aib = (&p->ai.src) + p->ai.order_list_blocks[i];
 
		bool is_pass = (p->ai.cargo_type == CT_PASSENGERS || p->ai.cargo_type == CT_MAIL);
 
		Order order;
 

	
 
		order.type = OT_GOTO_STATION;
 
		order.flags = 0;
 
		order.station = AiGetStationIdFromAircraftBlock(aib->use_tile, aib->cur_building_rule);
 

	
 
@@ -3643,69 +3631,62 @@ pos_3:
 
				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) {
 
					p->ai.cur_dir_a = 3;
 
					p->ai.cur_tile_a = tile;
 
					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
 
					return;
 
				}
 
			}
 
		} else {
 
			static const byte _depot_bits[] = {0x19,0x16,0x25,0x2A};
 

	
 
			DiagDirection dir = GetRailDepotDirection(tile);
 

	
 
			if (GetRailTrackStatus(tile + TileOffsByDir(dir)) & _depot_bits[dir])
 
				return;
 

	
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
		}
 
	} else if (IsTileType(tile, MP_STREET)) {
 
		if (!IsTileOwner(tile, _current_player)) return;
 

	
 
		if (IsLevelCrossing(tile)) goto is_rail_crossing;
 

	
 
		if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) {
 
			DiagDirection dir;
 
			TileIndex t;
 

	
 
			// Check if there are any stations around.
 
			if (IsTileType(tile + TileDiffXY(-1, 0), MP_STATION) &&
 
					IsTileOwner(tile + TileDiffXY(-1, 0), _current_player)) {
 
				return;
 
			}
 

	
 
			if (IsTileType(tile + TileDiffXY(1, 0), MP_STATION) &&
 
					IsTileOwner(tile + TileDiffXY(1, 0), _current_player)) {
 
				return;
 
			}
 

	
 
			if (IsTileType(tile + TileDiffXY(0, -1), MP_STATION) &&
 
					IsTileOwner(tile + TileDiffXY(0, -1), _current_player)) {
 
				return;
 
			}
 

	
 
			if (IsTileType(tile + TileDiffXY(0, 1), MP_STATION) &&
 
					IsTileOwner(tile + TileDiffXY(0, 1), _current_player)) {
 
				return;
 
			}
 
			t = tile + TileDiffXY(-1, 0);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(1, 0);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(0, -1);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(0, 1);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			dir = GetRoadDepotDirection(tile);
 

	
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
			DoCommand(
 
				TILE_MASK(tile + TileOffsByDir(dir)),
 
				DiagDirToRoadBits(ReverseDiagDir(dir)),
 
				0,
 
				DC_EXEC,
 
				CMD_REMOVE_ROAD);
 
		}
 
	} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
		if (!IsTileOwner(tile, _current_player) ||
 
				!IsBridge(tile) ||
 
				!IsBridgeRamp(tile) ||
 
				GetBridgeTransportType(tile) != TRANSPORT_RAIL) {
 
			return;
 
		}
 

	
 
		rails = 0;
 

	
 
		switch (GetBridgeRampDirection(tile)) {
 
			default:
 
			case DIAGDIR_NE: goto pos_2;
 
@@ -3860,50 +3841,49 @@ static void AiBuildCompanyHQ(Player *p)
 
{
 
	TileIndex tile;
 

	
 
	if (p->location_of_house == 0 &&
 
			p->last_build_coordinate != 0) {
 
		tile = AdjustTileCoordRandomly(p->last_build_coordinate, 8);
 
		DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
 
	}
 
}
 

	
 

	
 
void AiDoGameLoop(Player *p)
 
{
 
	if (p->bankrupt_asked != 0) {
 
		AiHandleTakeover(p);
 
		return;
 
	}
 

	
 
	// Ugly hack to make sure the service interval of the AI is good, not looking
 
	//  to the patch-setting
 
	// Also, it takes into account the setting if the service-interval is in days
 
	//  or in %
 
	_ai_service_interval = _patches.servint_ispercent?80:180;
 

	
 
	if (IS_HUMAN_PLAYER(_current_player))
 
		return;
 
	if (IS_HUMAN_PLAYER(_current_player)) return;
 

	
 
	AiAdjustLoan(p);
 
	AiBuildCompanyHQ(p);
 

	
 
#if 0
 
	{
 
		static byte old_state = 99;
 
		static bool hasdots = false;
 
		char *_ai_state_names[]={
 
			"AiCase0",
 
			"AiCase1",
 
			"AiStateVehLoop",
 
			"AiStateCheckReplaceVehicle",
 
			"AiStateDoReplaceVehicle",
 
			"AiStateWantNewRoute",
 
			"AiStateBuildDefaultRailBlocks",
 
			"AiStateBuildRail",
 
			"AiStateBuildRailVeh",
 
			"AiStateDeleteRailBlocks",
 
			"AiStateBuildDefaultRoadBlocks",
 
			"AiStateBuildRoad",
 
			"AiStateBuildRoadVehicles",
 
			"AiStateDeleteRoadBlocks",
 
			"AiStateAirportStuff",
ai/trolly/build.c
Show inline comments
 
@@ -47,104 +47,108 @@ int AiNew_Build_Station(Player *p, byte 
 
	return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
 
}
 

	
 

	
 
// Builds a brdige. The second best out of the ones available for this player
 
//  Params:
 
//   tile_a : starting point
 
//   tile_b : end point
 
//   flag : flag passed to DoCommand
 
int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag)
 
{
 
	int bridge_type, bridge_len, type, type2;
 

	
 
	// Find a good bridgetype (the best money can buy)
 
	bridge_len = GetBridgeLength(tile_a, tile_b);
 
	type = type2 = 0;
 
	for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
 
		if (CheckBridge_Stuff(bridge_type, bridge_len)) {
 
			type2 = type;
 
			type = bridge_type;
 
			// We found two bridges, exit
 
			if (type2 != 0) break;
 
		}
 
	}
 
	// There is only one bridge that can be build..
 
	// There is only one bridge that can be built
 
	if (type2 == 0 && type != 0) type2 = type;
 

	
 
	// Now, simply, build the bridge!
 
	if (p->ainew.tbt == AI_TRAIN)
 
		return AI_DoCommand(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
 

	
 
	if (p->ainew.tbt == AI_TRAIN) {
 
		return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
 
	} else {
 
	return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
 
}
 
}
 

	
 

	
 
// Build the route part by part
 
// Basicly what this function do, is build that amount of parts of the route
 
//  that go in the same direction. It sets 'part' to the last part of the route builded.
 
//  The return value is the cost for the builded parts
 
//
 
//  Params:
 
//   PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
 
//   part : Which part we need to build
 
//
 
// TODO: skip already builded road-pieces (e.g.: cityroad)
 
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag)
 
{
 
	int part = PathFinderInfo->position;
 
	byte *route_extra = PathFinderInfo->route_extra;
 
	TileIndex *route = PathFinderInfo->route;
 
	int dir;
 
	int old_dir = -1;
 
	int cost = 0;
 
	int res;
 
	// We need to calculate the direction with the parent of the parent.. so we skip
 
	//  the first pieces and the last piece
 
	if (part < 1) part = 1;
 
	// When we are done, stop it
 
	if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; }
 
	if (part >= PathFinderInfo->route_length - 1) {
 
		PathFinderInfo->position = -2;
 
		return 0;
 
	}
 

	
 

	
 
	if (PathFinderInfo->rail_or_road) {
 
		// Tunnel code
 
		if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
 
			cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
 
			PathFinderInfo->position++;
 
			// TODO: problems!
 
			if (CmdFailed(cost)) {
 
				DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
 
				DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be built!");
 
				return 0;
 
			}
 
			return cost;
 
		}
 
		// Bridge code
 
		if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
 
			cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
 
			PathFinderInfo->position++;
 
			// TODO: problems!
 
			if (CmdFailed(cost)) {
 
				DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
 
				DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be built!");
 
				return 0;
 
			}
 
			return cost;
 
		}
 

	
 
		// Build normal rail
 
		// Keep it doing till we go an other way
 
		if (route_extra[part-1] == 0 && route_extra[part] == 0) {
 
			while (route_extra[part] == 0) {
 
				// Get the current direction
 
				dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
 
				// Is it the same as the last one?
 
				if (old_dir != -1 && old_dir != dir) break;
 
				old_dir = dir;
 
				// Build the tile
 
				res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
 
				if (CmdFailed(res)) {
 
					// Problem.. let's just abort it all!
 
					p->ainew.state = AI_STATE_NOTHING;
 
					return 0;
 
				}
 
				cost += res;
 
				// Go to the next tile
 
				part++;
ai/trolly/pathfinder.c
Show inline comments
 
@@ -36,49 +36,50 @@ static bool TestCanBuildStationHere(Tile
 
	// return true if command succeeded, so the inverse of CmdFailed()
 
	return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
 
}
 

	
 

	
 
static bool IsRoad(TileIndex tile)
 
{
 
	return
 
		// MP_STREET, but not a road depot?
 
		(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
 
		(IsTileType(tile, MP_TUNNELBRIDGE) && (
 
			(IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) ||
 
			(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD)
 
		));
 
}
 

	
 

	
 
// Checks if a tile 'a' is between the tiles 'b' and 'c'
 
#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
 

	
 

	
 
// Check if the current tile is in our end-area
 
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
 
{
 
	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
 
	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
 

	
 
	// It is not allowed to have a station on the end of a bridge or tunnel ;)
 
	if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
 
	if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
 
		if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
 
			if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile, AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
 
				return AYSTAR_FOUND_END_NODE;
 

	
 
	return AYSTAR_DONE;
 
}
 

	
 

	
 
// Calculates the hash
 
//   Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
 
static uint AiPathFinder_Hash(uint key1, uint key2)
 
{
 
	return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
 
}
 

	
 

	
 
// Clear the memory of all the things
 
static void AyStar_AiPathFinder_Free(AyStar *aystar)
 
{
 
	AyStarMain_Free(aystar);
 
	free(aystar);
 
@@ -134,62 +135,65 @@ AyStar *new_AyStar_AiPathFinder(int max_
 
}
 

	
 

	
 
// To reuse AyStar we sometimes have to clean all the memory
 
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo)
 
{
 
	PathNode start_node;
 
	uint x;
 
	uint y;
 

	
 
	aystar->clear(aystar);
 

	
 
	// Set the user_data to the PathFinderInfo
 
	aystar->user_target = PathFinderInfo;
 

	
 
	// Set the start node
 
	start_node.parent = NULL;
 
	start_node.node.direction = 0;
 
	start_node.node.user_data[0] = 0;
 
	start_node.node.tile = PathFinderInfo->start_tile_tl;
 

	
 
	// Now we add all the starting tiles
 
	for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
 
		for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
 
			if (!(IsTileType(TileXY(x, y), MP_CLEAR) || IsTileType(TileXY(x, y), MP_TREES))) continue;
 
			if (!TestCanBuildStationHere(TileXY(x, y), TEST_STATION_NO_DIR)) continue;
 
			start_node.node.tile = TileXY(x, y);
 
			TileIndex tile = TileXY(x, y);
 

	
 
			if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) continue;
 
			if (!TestCanBuildStationHere(tile, TEST_STATION_NO_DIR)) continue;
 
			start_node.node.tile = tile;
 
			aystar->addstart(aystar, &start_node.node, 0);
 
		}
 
	}
 
}
 

	
 

	
 
// The h-value, simple calculation
 
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
 
{
 
	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
 
	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
 
	int r, r2;
 

	
 
	if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
 
		// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
 
		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDir(PathFinderInfo->end_direction));
 
		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDir(PathFinderInfo->end_direction));
 
	} else {
 
		// No direction, so just get the fastest route to the station
 
		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
 
		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br);
 
	}
 
	// See if the bottomright is faster than the topleft..
 
	if (r2 < r) r = r2;
 
	return r * AI_PATHFINDER_H_MULTIPLER;
 
}
 

	
 

	
 
// We found the end.. let's get the route back and put it in an array
 
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current)
 
{
 
	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
 
	uint i = 0;
 
	PathNode *parent = &current->path;
 

	
 
	do {
 
		PathFinderInfo->route_extra[i] = parent->node.user_data[0];
 
@@ -426,72 +430,75 @@ static int32 AyStar_AiPathFinder_Calcula
 
					if (r >= 15 || r == 0)
 
						res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
 
					else
 
						res += AI_PATHFINDER_FOUNDATION_PENALTY;
 
				}
 
			}
 
		}
 
	}
 

	
 
	// Are we part of a tunnel?
 
	if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
 
		// Tunnels are very expensive when build on long routes..
 
		// Ironicly, we are using BridgeCode here ;)
 
		r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
 
		res += r + (r >> 8);
 
	}
 

	
 
	// Are we part of a bridge?
 
	if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
 
		// That means for every length a penalty
 
		res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
 
		// Check if we are going up or down, first for the starting point
 
		// In user_data[0] is at the 8th bit the direction
 
		if (!HASBIT(BRIDGE_NO_FOUNDATION, parent_tileh)) {
 
			if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15)
 
			if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15) {
 
				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
 
		}
 
		}
 
		// Second for the end point
 
		if (!HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
 
			if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15)
 
			if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15) {
 
				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
 
		}
 
		}
 
		if (parent_tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
 
		if (tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
 
	}
 

	
 
	//  To prevent the AI from taking the fastest way in tiles, but not the fastest way
 
	//    in speed, we have to give a good penalty to direction changing
 
	//  This way, we get almost the fastest way in tiles, and a very good speed on the track
 
	if (!PathFinderInfo->rail_or_road) {
 
		if (parent->path.parent != NULL &&
 
				AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
 
			// When road exists, we don't like turning, but its free, so don't be to piggy about it
 
			if (IsRoad(parent->path.node.tile))
 
			if (IsRoad(parent->path.node.tile)) {
 
				res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
 
			else
 
			} else {
 
				res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
 
		}
 
		}
 
	} else {
 
		// For rail we have 1 exeption: diagonal rail..
 
		// So we fetch 2 raildirection. That of the current one, and of the one before that
 
		if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
 
			int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
 
			int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
 
			// First, see if we are on diagonal path, that is better than straight path
 
			if (dir1 > 1) res -= AI_PATHFINDER_DIAGONAL_BONUS;
 

	
 
			// First see if they are different
 
			if (dir1 != dir2) {
 
				// dir 2 and 3 are 1 diagonal track, and 4 and 5.
 
				if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
 
					// It is not, so we changed of direction
 
					res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
 
				}
 
				if (parent->path.parent->parent->parent != NULL) {
 
					int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
 
					// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
 
					if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
 
						res += AI_PATHFINDER_CURVE_PENALTY;
 
					}
 
				}
 
			}
ai/trolly/trolly.c
Show inline comments
 
@@ -107,58 +107,61 @@ static void AiNew_State_WakeUp(Player *p
 
		// Random till we found a place for it!
 
		// TODO: this should not be on a random place..
 
		AiNew_Build_CompanyHQ(p, AI_Random() % MapSize());
 
		// Enough for now, but we want to come back here the next time
 
		//  so we do not change any status
 
		return;
 
	}
 

	
 
	money = p->player_money - AI_MINIMUM_MONEY;
 

	
 
	// Let's pick an action!
 
	if (p->ainew.action == AI_ACTION_NONE) {
 
		c = AI_Random() & 0xFF;
 
		if (p->current_loan > 0 &&
 
				p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN &&
 
				c < 10) {
 
			p->ainew.action = AI_ACTION_REPAY_LOAN;
 
		} else if (p->ainew.last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) {
 
			// Check all vehicles once in a while
 
			p->ainew.action = AI_ACTION_CHECK_ALL_VEHICLES;
 
			p->ainew.last_vehiclecheck_date = _date;
 
		} else if (c < 100 && !_patches.ai_disable_veh_roadveh) {
 
			// Do we have any spots for road-vehicles left open?
 
			if (GetFreeUnitNumber(VEH_Road) <= _patches.max_roadveh) {
 
				if (c < 85)
 
				if (c < 85) {
 
					p->ainew.action = AI_ACTION_TRUCK_ROUTE;
 
				else
 
				} else {
 
					p->ainew.action = AI_ACTION_BUS_ROUTE;
 
			}
 
		}/* else if (c < 200 && !_patches.ai_disable_veh_train) {
 
			}
 
#if 0
 
		} else if (c < 200 && !_patches.ai_disable_veh_train) {
 
			if (GetFreeUnitNumber(VEH_Train) <= _patches.max_trains) {
 
				p->ainew.action = AI_ACTION_TRAIN_ROUTE;
 
			}
 
		}*/
 
#endif
 
		}
 

	
 
		p->ainew.counter = 0;
 
	}
 

	
 
	if (p->ainew.counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) {
 
		p->ainew.action = AI_ACTION_NONE;
 
		return;
 
	}
 

	
 
	if (_patches.ai_disable_veh_roadveh && (
 
				p->ainew.action == AI_ACTION_BUS_ROUTE ||
 
				p->ainew.action == AI_ACTION_TRUCK_ROUTE
 
			)) {
 
		p->ainew.action = AI_ACTION_NONE;
 
		return;
 
	}
 

	
 
	if (p->ainew.action == AI_ACTION_REPAY_LOAN &&
 
			money > AI_MINIMUM_LOAN_REPAY_MONEY) {
 
		// We start repaying some money..
 
		p->ainew.state = AI_STATE_REPAY_MONEY;
 
		return;
 
	}
 

	
 
@@ -187,50 +190,50 @@ static void AiNew_State_WakeUp(Player *p
 
			return;
 
		}
 
		p->ainew.cargo = AI_NEED_CARGO;
 
		p->ainew.last_id = 0;
 
		p->ainew.state = AI_STATE_LOCATE_ROUTE;
 
		p->ainew.tbt = AI_TRUCK;
 
		return;
 
	}
 

	
 
	p->ainew.state = AI_STATE_NOTHING;
 
}
 

	
 

	
 
static void AiNew_State_ActionDone(Player *p)
 
{
 
	p->ainew.action = AI_ACTION_NONE;
 
	p->ainew.state = AI_STATE_NOTHING;
 
}
 

	
 

	
 
// Check if a city or industry is good enough to start a route there
 
static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type)
 
{
 
	if (type == AI_CITY) {
 
		Town *t = GetTown(ic);
 
		Station *st;
 
		const Town* t = GetTown(ic);
 
		const Station* st;
 
		uint count = 0;
 
		int j = 0;
 

	
 
		// We don't like roadconstructions, don't even true such a city
 
		if (t->road_build_months != 0) return false;
 

	
 
		// Check if the rating in a city is high enough
 
		//  If not, take a chance if we want to continue
 
		if (t->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
 

	
 
		if (t->max_pass - t->act_pass < AI_CHECKCITY_NEEDED_CARGO && !AI_CHANCE16(1,AI_CHECKCITY_CITY_CHANCE)) return false;
 

	
 
		// Check if we have build a station in this town the last 6 months
 
		//  else we don't do it. This is done, because stat updates can be slow
 
		//  and sometimes it takes up to 4 months before the stats are corectly.
 
		//  This way we don't get 12 busstations in one city of 100 population ;)
 
		FOR_ALL_STATIONS(st) {
 
			// Is it an active station
 
			if (st->xy == 0) continue;
 
			// Do we own it?
 
			if (st->owner == _current_player) {
 
				// Are we talking busses?
 
				if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) != FACIL_BUS_STOP) continue;
 
				// Is it the same city as we are in now?
 
@@ -249,50 +252,50 @@ static bool AiNew_Check_City_or_Industry
 
				if (DistanceManhattan(st->xy, t->xy) > 10) continue;
 
				// It does take this cargo.. what is his rating?
 
				if (st->goods[CT_PASSENGERS].rating < AI_CHECKCITY_CARGO_RATING) continue;
 
				j++;
 
				// When this is the first station, we build a second with no problem ;)
 
				if (j == 1) continue;
 
				// The rating is high.. second station...
 
				//  a little chance that we still continue
 
				//  But if there are 3 stations of this size, we never go on...
 
				if (j == 2 && AI_CHANCE16(1, AI_CHECKCITY_CARGO_RATING_CHANCE)) continue;
 
				// We don't like this station :(
 
				return false;
 
			}
 
		}
 

	
 
		// We are about to add one...
 
		count++;
 
		// Check if we the city can provide enough cargo for this amount of stations..
 
		if (count * AI_CHECKCITY_CARGO_PER_STATION > t->max_pass) return false;
 

	
 
		// All check are okay, so we can build here!
 
		return true;
 
	}
 
	if (type == AI_INDUSTRY) {
 
		Industry *i = GetIndustry(ic);
 
		Station *st;
 
		const Industry* i = GetIndustry(ic);
 
		const Station* st;
 
		int count = 0;
 
		int j = 0;
 

	
 
		if (i->town != NULL && i->town->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
 

	
 
		// No limits on delevering stations!
 
		//  Or for industry that does not give anything yet
 
		if (i->produced_cargo[0] == CT_INVALID || i->total_production[0] == 0) return true;
 

	
 
		if (i->total_production[0] - i->total_transported[0] < AI_CHECKCITY_NEEDED_CARGO) return false;
 

	
 
		// Check if we have build a station in this town the last 6 months
 
		//  else we don't do it. This is done, because stat updates can be slow
 
		//  and sometimes it takes up to 4 months before the stats are corectly.
 
		FOR_ALL_STATIONS(st) {
 
			// Is it an active station
 
			if (st->xy == 0) continue;
 

	
 
			// Do we own it?
 
			if (st->owner == _current_player) {
 
				// Are we talking trucks?
 
				if (p->ainew.tbt == AI_TRUCK && (FACIL_TRUCK_STOP & st->facilities) != FACIL_TRUCK_STOP) continue;
 
				// Is it the same city as we are in now?
 
				if (st->town != i->town) continue;
 
@@ -358,140 +361,143 @@ static void AiNew_State_LocateRoute(Play
 
			p->ainew.to_type = AI_CITY;
 
		} else if (p->ainew.tbt == AI_TRUCK) {
 
			p->ainew.cargo = AI_NO_CARGO;
 

	
 
			p->ainew.from_type = AI_INDUSTRY;
 
			p->ainew.to_type = AI_INDUSTRY;
 
		}
 

	
 
		// Now we are doing initing, we wait one tick
 
		return;
 
	}
 

	
 
	// Increase the counter and abort if it is taking too long!
 
	p->ainew.counter++;
 
	if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) {
 
		// Switch back to doing nothing!
 
		p->ainew.state = AI_STATE_NOTHING;
 
		return;
 
	}
 

	
 
	// We are going to locate a city from where we are going to connect
 
	if (p->ainew.from_ic == -1) {
 
		if (p->ainew.temp == -1) {
 
			// First, we pick a random spot to search from
 
			if (p->ainew.from_type == AI_CITY)
 
			if (p->ainew.from_type == AI_CITY) {
 
				p->ainew.temp = AI_RandomRange(_total_towns);
 
			else
 
			} else {
 
				p->ainew.temp = AI_RandomRange(_total_industries);
 
		}
 
		}
 

	
 
		if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) {
 
			// It was not a valid city
 
			//  increase the temp with one, and return. We will come back later here
 
			//  to try again
 
			p->ainew.temp++;
 
			if (p->ainew.from_type == AI_CITY) {
 
				if (p->ainew.temp >= (int)_total_towns) p->ainew.temp = 0;
 
			} else {
 
				if (p->ainew.temp >= _total_industries) p->ainew.temp = 0;
 
			}
 

	
 
			// Don't do an attempt if we are trying the same id as the last time...
 
			if (p->ainew.last_id == p->ainew.temp) return;
 
			p->ainew.last_id = p->ainew.temp;
 

	
 
			return;
 
		}
 

	
 
		// We found a good city/industry, save the data of it
 
		p->ainew.from_ic = p->ainew.temp;
 

	
 
		// Start the next tick with finding a to-city
 
		p->ainew.temp = -1;
 
		return;
 
	}
 

	
 
	// Find a to-city
 
	if (p->ainew.temp == -1) {
 
		// First, we pick a random spot to search to
 
		if (p->ainew.to_type == AI_CITY)
 
		if (p->ainew.to_type == AI_CITY) {
 
			p->ainew.temp = AI_RandomRange(_total_towns);
 
		else
 
		} else {
 
			p->ainew.temp = AI_RandomRange(_total_industries);
 
	}
 
	}
 

	
 
	// The same city is not allowed
 
	// Also check if the city is valid
 
	if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) {
 
		// Maybe it is valid..
 

	
 
		// We need to know if they are not to far apart from eachother..
 
		// We do that by checking how much cargo we have to move and how long the route
 
		//   is.
 
		/* We need to know if they are not to far apart from eachother..
 
		 * We do that by checking how much cargo we have to move and how long the
 
		 * route is.
 
		 */
 

	
 
		if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) {
 
			const Town* town_from = GetTown(p->ainew.from_ic);
 
			const Town* town_temp = GetTown(p->ainew.temp);
 
			uint distance = DistanceManhattan(town_from->xy, town_temp->xy);
 
			int max_cargo;
 

	
 
			max_cargo  = town_from->max_pass + town_temp->max_pass;
 
			max_cargo -= town_from->act_pass + town_temp->act_pass;
 

	
 
			// max_cargo is now the amount of cargo we can move between the two cities
 
			// If it is more than the distance, we allow it
 
			if (distance <= max_cargo * AI_LOCATEROUTE_BUS_CARGO_DISTANCE) {
 
				// We found a good city/industry, save the data of it
 
				p->ainew.to_ic = p->ainew.temp;
 
				p->ainew.state = AI_STATE_FIND_STATION;
 

	
 
				DEBUG(ai,1)(
 
					"[AiNew - LocateRoute] Found bus-route of %d tiles long (from %d to %d)",
 
					distance,
 
					p->ainew.from_ic,
 
					p->ainew.temp
 
				);
 

	
 
				p->ainew.from_tile = 0;
 
				p->ainew.to_tile = 0;
 

	
 
				return;
 
			}
 
		} else if (p->ainew.tbt == AI_TRUCK) {
 
			const Industry* ind_from = GetIndustry(p->ainew.from_ic);
 
			const Industry* ind_temp = GetIndustry(p->ainew.temp);
 
			bool found = false;
 
			int max_cargo = 0;
 
			uint i;
 

	
 
			// TODO: in max_cargo, also check other cargo (beside [0])
 
			// First we check if the from_ic produces cargo that this ic accepts
 
			if (ind_from->produced_cargo[0] != CT_INVALID && ind_from->total_production[0] != 0) {
 
				for (i = 0; i < lengthof(ind_temp->accepts_cargo); i++) {
 
					if (ind_temp->accepts_cargo[i] == CT_INVALID) break;
 
					if (ind_from->produced_cargo[0] == ind_temp->accepts_cargo[i]) {
 
						// Found a compatbiel industry
 
						// Found a compatible industry
 
						max_cargo = ind_from->total_production[0] - ind_from->total_transported[0];
 
						found = true;
 
						p->ainew.from_deliver = true;
 
						p->ainew.to_deliver = false;
 
						break;
 
					}
 
				}
 
			}
 
			if (!found && ind_temp->produced_cargo[0] != CT_INVALID && ind_temp->total_production[0] != 0) {
 
				// If not check if the current ic produces cargo that the from_ic accepts
 
				for (i = 0; i < lengthof(ind_from->accepts_cargo); i++) {
 
					if (ind_from->accepts_cargo[i] == CT_INVALID) break;
 
					if (ind_temp->produced_cargo[0] == ind_from->accepts_cargo[i]) {
 
						// Found a compatbiel industry
 
						found = true;
 
						max_cargo = ind_temp->total_production[0] - ind_temp->total_transported[0];
 
						p->ainew.from_deliver = false;
 
						p->ainew.to_deliver = true;
 
						break;
 
					}
 
				}
 
			}
 
			if (found) {
 
				// Yeah, they are compatible!!!
 
@@ -651,49 +657,49 @@ static void AiNew_State_FindStation(Play
 
		// To find a good spot we scan a range from the center, a get the point
 
		//  where we get the most cargo and where it is buildable.
 
		// TODO: also check for station of myself and make sure we are not
 
		//   taking eachothers passangers away (bad result when it does not)
 
		for (x = TileX(tile) - AI_FINDSTATION_TILE_RANGE; x <= TileX(tile) + AI_FINDSTATION_TILE_RANGE; x++) {
 
			for (y = TileY(tile) - AI_FINDSTATION_TILE_RANGE; y <= TileY(tile) + AI_FINDSTATION_TILE_RANGE; y++) {
 
				new_tile = TileXY(x, y);
 
				if (IsTileType(new_tile, MP_CLEAR) || IsTileType(new_tile, MP_TREES)) {
 
					// This tile we can build on!
 
					// Check acceptance
 
					// XXX - Get the catchment area
 
					GetAcceptanceAroundTiles(accepts, new_tile, 1, 1, 4);
 
					// >> 3 == 0 means no cargo
 
					if (accepts[p->ainew.cargo] >> 3 == 0) continue;
 
					// See if we can build the station
 
					r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
 
					if (CmdFailed(r)) continue;
 
					// We can build it, so add it to found_spot
 
					found_spot[i] = new_tile;
 
					found_best[i++] = accepts[p->ainew.cargo];
 
				}
 
			}
 
		}
 

	
 
		// If i is still zero, we did not found anything :(
 
		// If i is still zero, we did not find anything
 
		if (i == 0) {
 
			p->ainew.state = AI_STATE_NOTHING;
 
			return;
 
		}
 

	
 
		// Go through all the found_best and check which has the highest value
 
		best = 0;
 
		new_tile = 0;
 

	
 
		for (x=0;x<i;x++) {
 
			if (found_best[x] > best ||
 
					(found_best[x] == best && DistanceManhattan(tile, new_tile) > DistanceManhattan(tile, found_spot[x]))) {
 
				new_tile = found_spot[x];
 
				best = found_best[x];
 
			}
 
		}
 

	
 
		// See how much it is going to cost us...
 
		r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
 
		p->ainew.new_cost += r;
 

	
 
		direction = AI_PATHFINDER_NO_DIRECTION;
 
	} else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) {
 
		// Truck station locater works differently.. a station can be on any place
 
@@ -732,75 +738,73 @@ static void AiNew_State_FindPath(Player 
 
			const Industry* i = GetIndustry(p->ainew.from_ic);
 

	
 
			// For truck routes we take a range around the industry
 
			p->ainew.path_info.start_tile_tl = i->xy - TileDiffXY(1, 1);
 
			p->ainew.path_info.start_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
 
			p->ainew.path_info.start_direction = p->ainew.from_direction;
 
		} else {
 
			p->ainew.path_info.start_tile_tl = p->ainew.from_tile;
 
			p->ainew.path_info.start_tile_br = p->ainew.from_tile;
 
			p->ainew.path_info.start_direction = p->ainew.from_direction;
 
		}
 

	
 
		if (p->ainew.to_tile == AI_STATION_RANGE) {
 
			const Industry* i = GetIndustry(p->ainew.to_ic);
 

	
 
			p->ainew.path_info.end_tile_tl = i->xy - TileDiffXY(1, 1);
 
			p->ainew.path_info.end_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
 
			p->ainew.path_info.end_direction = p->ainew.to_direction;
 
		} else {
 
			p->ainew.path_info.end_tile_tl = p->ainew.to_tile;
 
			p->ainew.path_info.end_tile_br = p->ainew.to_tile;
 
			p->ainew.path_info.end_direction = p->ainew.to_direction;
 
		}
 

	
 
		if (p->ainew.tbt == AI_TRAIN)
 
			p->ainew.path_info.rail_or_road = true;
 
		else
 
			p->ainew.path_info.rail_or_road = false;
 
		p->ainew.path_info.rail_or_road = (p->ainew.tbt == AI_TRAIN);
 

	
 
		// First, clean the pathfinder with our new begin and endpoints
 
		clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info);
 

	
 
		p->ainew.temp = 0;
 
	}
 

	
 
	// Start the pathfinder
 
	r = p->ainew.pathfinder->main(p->ainew.pathfinder);
 
	// If it return: no match, stop it...
 
	if (r == AYSTAR_NO_PATH) {
 
	switch (r) {
 
		case AYSTAR_NO_PATH:
 
		DEBUG(ai,1)("[AiNew] PathFinder found no route!");
 
		// Start all over again...
 
			// Start all over again
 
		p->ainew.state = AI_STATE_NOTHING;
 
		return;
 
	}
 
	if (r == AYSTAR_FOUND_END_NODE) {
 
		// We found the end-point
 
			break;
 

	
 
		case AYSTAR_FOUND_END_NODE: // We found the end-point
 
		p->ainew.temp = -1;
 
		p->ainew.state = AI_STATE_FIND_DEPOT;
 
		return;
 
			break;
 

	
 
		// In any other case, we are still busy finding the route
 
		default: break;
 
	}
 
	// In any other case, we are still busy finding the route...
 
}
 

	
 

	
 
// This function tries to locate a good place for a depot!
 
static void AiNew_State_FindDepot(Player *p)
 
{
 
	// To place the depot, we walk through the route, and if we find a lovely spot (MP_CLEAR, MP_TREES), we place it there..
 
	// Simple, easy, works!
 
	// To make the depot stand in the middle of the route, we start from the center..
 
	// But first we walk through the route see if we can find a depot that is ours
 
	//  this keeps things nice ;)
 
	int g, i, r;
 
	DiagDirection j;
 
	TileIndex tile;
 
	assert(p->ainew.state == AI_STATE_FIND_DEPOT);
 

	
 
	p->ainew.depot_tile = 0;
 

	
 
	for (i=2;i<p->ainew.path_info.route_length-2;i++) {
 
		tile = p->ainew.path_info.route[i];
 
		for (j = 0; j < 4; j++) {
 
			TileIndex t = tile + TileOffsByDir(j);
 

	
 
			if (IsTileType(t, MP_STREET) &&
 
@@ -879,52 +883,53 @@ static int AiNew_HowManyVehicles(Player 
 
		int length, tiles_a_day;
 
		int amount;
 
		i = AiNew_PickVehicle(p);
 
		if (i == INVALID_ENGINE) return 0;
 
		// Passenger run.. how long is the route?
 
		length = p->ainew.path_info.route_length;
 
		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
 
		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
 
		// We want a vehicle in a station once a month at least, so, calculate it!
 
		// (the * 2 is because we have 2 stations ;))
 
		amount = length * 2 * 2 / tiles_a_day / 30;
 
		if (amount == 0) amount = 1;
 
		return amount;
 
	} else if (p->ainew.tbt == AI_TRUCK) {
 
		// For truck-routes we look at the cargo
 
		EngineID i;
 
		int length, amount, tiles_a_day;
 
		int max_cargo;
 
		i = AiNew_PickVehicle(p);
 
		if (i == INVALID_ENGINE) return 0;
 
		// Passenger run.. how long is the route?
 
		length = p->ainew.path_info.route_length;
 
		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
 
		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
 
		if (p->ainew.from_deliver)
 
		if (p->ainew.from_deliver) {
 
			max_cargo = GetIndustry(p->ainew.from_ic)->total_production[0];
 
		else
 
		} else {
 
			max_cargo = GetIndustry(p->ainew.to_ic)->total_production[0];
 
		}
 

	
 
		// This is because moving 60% is more than we can dream of!
 
		max_cargo *= 0.6;
 
		// We want all the cargo to be gone in a month.. so, we know the cargo it delivers
 
		//  we know what the vehicle takes with him, and we know the time it takes him
 
		//  to get back here.. now let's do some math!
 
		amount = 2 * length * max_cargo / tiles_a_day / 30 / RoadVehInfo(i)->capacity;
 
		amount += 1;
 
		return amount;
 
	} else {
 
		// Currently not supported
 
		return 0;
 
	}
 
}
 

	
 

	
 
// This function checks:
 
//   - If the route went okay
 
//   - Calculates the amount of money needed to build the route
 
//   - Calculates how much vehicles needed for the route
 
static void AiNew_State_VerifyRoute(Player *p)
 
{
 
	int res, i;
 
	assert(p->ainew.state == AI_STATE_VERIFY_ROUTE);
 
@@ -1088,49 +1093,49 @@ static void AiNew_State_BuildPath(Player
 
						if (!CmdFailed(ret)) {
 
							if (IsTileType(tile + dir3 + dir3, MP_CLEAR) || IsTileType(tile + dir3 + dir3, MP_TREES))
 
								AI_DoCommand(tile+dir3+dir3, AiNew_GetRoadDirection(tile+dir3, tile+dir3+dir3, tile+dir3+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
 
						}
 
					}
 
				}
 
			}
 
		}
 

	
 

	
 
		DEBUG(ai,1)("[AiNew] Done building the path (cost: %d)", p->ainew.new_cost);
 
		p->ainew.state = AI_STATE_BUILD_DEPOT;
 
	}
 
}
 

	
 

	
 
// Builds the depot
 
static void AiNew_State_BuildDepot(Player *p)
 
{
 
	int res = 0;
 
	assert(p->ainew.state == AI_STATE_BUILD_DEPOT);
 

	
 
	if (IsTileType(p->ainew.depot_tile, MP_STREET) && GetRoadTileType(p->ainew.depot_tile) == ROAD_TILE_DEPOT) {
 
		if (IsTileOwner(p->ainew.depot_tile, _current_player)) {
 
			// The depot is already builded!
 
			// The depot is already built
 
			p->ainew.state = AI_STATE_BUILD_VEHICLE;
 
			return;
 
		} else {
 
			// There is a depot, but not of our team! :(
 
			p->ainew.state = AI_STATE_NOTHING;
 
			return;
 
		}
 
	}
 

	
 
	// There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p)
 
	if (!EnsureNoVehicle(p->ainew.depot_tile + TileOffsByDir(p->ainew.depot_direction)))
 
		return;
 

	
 
	res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC);
 
	if (CmdFailed(res)) {
 
		DEBUG(ai,0)("[AiNew - BuildDepot] Strange but true... depot can not be build!");
 
		p->ainew.state = AI_STATE_NOTHING;
 
		return;
 
	}
 

	
 
	p->ainew.state = AI_STATE_BUILD_VEHICLE;
 
	p->ainew.idle = 10;
 
	p->ainew.veh_main_id = INVALID_VEHICLE;
 
}
aystar.c
Show inline comments
 
@@ -4,287 +4,293 @@
 
 * This file has the core function for AyStar
 
 *  AyStar is a fast pathfinding routine and is used for things like
 
 *  AI_pathfinding and Train_pathfinding.
 
 *  For more information about AyStar (A* Algorithm), you can look at
 
 *    http://en.wikipedia.org/wiki/A-star_search_algorithm
 
 */
 

	
 
/*
 
 * Friendly reminder:
 
 *  Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
 
 *  And when not free'd, it can cause system-crashes.
 
 * Also remember that when you stop an algorithm before it is finished, your
 
 * should call clear() yourself!
 
 */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "aystar.h"
 

	
 
int _aystar_stats_open_size;
 
int _aystar_stats_closed_size;
 

	
 
// This looks in the Hash if a node exists in ClosedList
 
//  If so, it returns the PathNode, else NULL
 
static PathNode *AyStarMain_ClosedList_IsInList(AyStar *aystar, AyStarNode *node)
 
static PathNode* AyStarMain_ClosedList_IsInList(AyStar* aystar, const AyStarNode* node)
 
{
 
	return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
 
}
 

	
 
// This adds a node to the ClosedList
 
//  It makes a copy of the data
 
static void AyStarMain_ClosedList_Add(AyStar *aystar, PathNode *node)
 
static void AyStarMain_ClosedList_Add(AyStar* aystar, const PathNode* node)
 
{
 
	// Add a node to the ClosedList
 
	PathNode *new_node = malloc(sizeof(PathNode));
 
	PathNode* new_node = malloc(sizeof(*new_node));
 
	*new_node = *node;
 
	Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
 
}
 

	
 
// Checks if a node is in the OpenList
 
//   If so, it returns the OpenListNode, else NULL
 
static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, AyStarNode *node)
 
static OpenListNode* AyStarMain_OpenList_IsInList(AyStar* aystar, const AyStarNode* node)
 
{
 
	return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
 
}
 

	
 
// Gets the best node from OpenList
 
//  returns the best node, or NULL of none is found
 
// Also it deletes the node from the OpenList
 
static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
 
{
 
	// Return the item the Queue returns.. the best next OpenList item.
 
	OpenListNode* res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
 
	if (res != NULL)
 
	if (res != NULL) {
 
		Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
 
	}
 

	
 
	return res;
 
}
 

	
 
// Adds a node to the OpenList
 
//  It makes a copy of node, and puts the pointer of parent in the struct
 
static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g)
 
static void AyStarMain_OpenList_Add(AyStar* aystar, PathNode* parent, const AyStarNode* node, int f, int g)
 
{
 
	// Add a new Node to the OpenList
 
	OpenListNode* new_node = malloc(sizeof(OpenListNode));
 
	OpenListNode* new_node = malloc(sizeof(*new_node));
 
	new_node->g = g;
 
	new_node->path.parent = parent;
 
	new_node->path.node = *node;
 
	Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
 

	
 
	// Add it to the queue
 
	aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
 
}
 

	
 
/*
 
 * Checks one tile and calculate his f-value
 
 *  return values:
 
 *	AYSTAR_DONE : indicates we are done
 
 */
 
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
 
int AyStarMain_CheckTile(AyStar* aystar, AyStarNode* current, OpenListNode* parent)
 
{
 
	int new_f, new_g, new_h;
 
	PathNode *closedlist_parent;
 
	OpenListNode *check;
 

	
 
	// Check the new node against the ClosedList
 
	if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
 

	
 
	// Calculate the G-value for this node
 
	new_g = aystar->CalculateG(aystar, current, parent);
 
	// If the value was INVALID_NODE, we don't do anything with this node
 
	if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
 

	
 
	// There should not be given any other error-code..
 
	assert(new_g >= 0);
 
	// Add the parent g-value to the new g-value
 
	new_g += parent->g;
 
	if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
 

	
 
	// Calculate the h-value
 
	new_h = aystar->CalculateH(aystar, current, parent);
 
	// There should not be given any error-code..
 
	assert(new_h >= 0);
 

	
 
	// The f-value if g + h
 
	new_f = new_g + new_h;
 

	
 
	// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
 
	closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
 

	
 
	// Check if this item is already in the OpenList
 
	if ((check = AyStarMain_OpenList_IsInList(aystar, current)) != NULL) {
 
	check = AyStarMain_OpenList_IsInList(aystar, current);
 
	if (check != NULL) {
 
		uint i;
 
		// Yes, check if this g value is lower..
 
		if (new_g > check->g) return AYSTAR_DONE;
 
		aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
 
		// It is lower, so change it to this item
 
		check->g = new_g;
 
		check->path.parent = closedlist_parent;
 
		/* Copy user data, will probably have changed */
 
		for (i=0;i<lengthof(current->user_data);i++)
 
		for (i = 0; i < lengthof(current->user_data); i++) {
 
			check->path.node.user_data[i] = current->user_data[i];
 
		}
 
		// Readd him in the OpenListQueue
 
		aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
 
	} else {
 
		// A new node, add him to the OpenList
 
		AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g);
 
	}
 

	
 
	return AYSTAR_DONE;
 
}
 

	
 
/*
 
 * This function is the core of AyStar. It handles one item and checks
 
 *  his neighbour items. If they are valid, they are added to be checked too.
 
 *  return values:
 
 *	AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
 
 *	has been found.
 
 *	AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
 
 *	reached.
 
 *	AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
 
 *	AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
 
 */
 
int AyStarMain_Loop(AyStar *aystar) {
 
int AyStarMain_Loop(AyStar* aystar)
 
{
 
	int i, r;
 

	
 
	// Get the best node from OpenList
 
	OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
 
	// If empty, drop an error
 
	if (current == NULL) {
 
		return AYSTAR_EMPTY_OPENLIST;
 
	}
 
	if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
 

	
 
	// Check for end node and if found, return that code
 
	if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
 
		if (aystar->FoundEndNode != NULL)
 
			aystar->FoundEndNode(aystar, current);
 
		free(current);
 
		return AYSTAR_FOUND_END_NODE;
 
	}
 

	
 
	// Add the node to the ClosedList
 
	AyStarMain_ClosedList_Add(aystar, &current->path);
 

	
 
	// Load the neighbours
 
	aystar->GetNeighbours(aystar, current);
 

	
 
	// Go through all neighbours
 
	for (i=0;i<aystar->num_neighbours;i++) {
 
		// Check and add them to the OpenList if needed
 
		r = aystar->checktile(aystar, &aystar->neighbours[i], current);
 
	}
 

	
 
	// Free the node
 
	free(current);
 

	
 
	if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
 
		/* We've expanded enough nodes */
 
		return AYSTAR_LIMIT_REACHED;
 
	} else {
 
		// Return that we are still busy
 
		return AYSTAR_STILL_BUSY;
 
	}
 
}
 

	
 
/*
 
 * This function frees the memory it allocated
 
 */
 
void AyStarMain_Free(AyStar *aystar) {
 
void AyStarMain_Free(AyStar* aystar)
 
{
 
	aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
 
	/* 2nd argument above is false, below is true, to free the values only
 
	 * once */
 
	delete_Hash(&aystar->OpenListHash, true);
 
	delete_Hash(&aystar->ClosedListHash, true);
 
#ifdef AYSTAR_DEBUG
 
	printf("[AyStar] Memory free'd\n");
 
#endif
 
}
 

	
 
/*
 
 * This function make the memory go back to zero
 
 *  This function should be called when you are using the same instance again.
 
 */
 
void AyStarMain_Clear(AyStar *aystar) {
 
void AyStarMain_Clear(AyStar* aystar)
 
{
 
	// Clean the Queue, but not the elements within. That will be done by
 
	// the hash.
 
	aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
 
	// Clean the hashes
 
	clear_Hash(&aystar->OpenListHash, true);
 
	clear_Hash(&aystar->ClosedListHash, true);
 

	
 
#ifdef AYSTAR_DEBUG
 
	printf("[AyStar] Cleared AyStar\n");
 
#endif
 
}
 

	
 
/*
 
 * This is the function you call to run AyStar.
 
 *  return values:
 
 *	AYSTAR_FOUND_END_NODE : indicates we found an end node.
 
 *	AYSTAR_NO_PATH : indicates that there was no path found.
 
 *	AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
 
 * When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
 
 * aystar->clear() is called. Note that when you stop the algorithm halfway,
 
 * you should still call clear() yourself!
 
 */
 
int AyStarMain_Main(AyStar *aystar) {
 
	int r, i = 0;
 
	// Loop through the OpenList
 
	//  Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick
 
	while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
 
#ifdef AYSTAR_DEBUG
 
	if (r == AYSTAR_FOUND_END_NODE)
 
		printf("[AyStar] Found path!\n");
 
	else if (r == AYSTAR_EMPTY_OPENLIST)
 
		printf("[AyStar] OpenList run dry, no path found\n");
 
	else if (r == AYSTAR_LIMIT_REACHED)
 
		printf("[AyStar] Exceeded search_nodes, no path found\n");
 
	switch (r) {
 
		case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
 
		case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
 
		case AYSTAR_LIMIT_REACHED:  printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
 
		default: break;
 
	}
 
#endif
 
	if (r != AYSTAR_STILL_BUSY) {
 
		/* We're done, clean up */
 
		_aystar_stats_open_size = aystar->OpenListHash.size;
 
		_aystar_stats_closed_size = aystar->ClosedListHash.size;
 
		aystar->clear(aystar);
 
	}
 

	
 
	// Check result-value
 
	if (r == AYSTAR_FOUND_END_NODE) return AYSTAR_FOUND_END_NODE;
 
	// Check if we have some left in the OpenList
 
	if (r == AYSTAR_EMPTY_OPENLIST || r == AYSTAR_LIMIT_REACHED) return AYSTAR_NO_PATH;
 

	
 
	// Return we are still busy
 
	return AYSTAR_STILL_BUSY;
 
	switch (r) {
 
		case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
 
		case AYSTAR_EMPTY_OPENLIST:
 
		case AYSTAR_LIMIT_REACHED:  return AYSTAR_NO_PATH;
 
		default:                    return AYSTAR_STILL_BUSY;
 
	}
 
}
 

	
 
/*
 
 * Adds a node from where to start an algorithm. Multiple nodes can be added
 
 * if wanted. You should make sure that clear() is called before adding nodes
 
 * if the AyStar has been used before (though the normal main loop calls
 
 * clear() automatically when the algorithm finishes
 
 * g is the cost for starting with this node.
 
 */
 
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g) {
 
void AyStarMain_AddStartNode(AyStar* aystar, AyStarNode* start_node, uint g)
 
{
 
#ifdef AYSTAR_DEBUG
 
	printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
 
		TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
 
#endif
 
	AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g);
 
}
 

	
 
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) {
 
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets)
 
{
 
	// Allocated the Hash for the OpenList and ClosedList
 
	init_Hash(&aystar->OpenListHash, hash, num_buckets);
 
	init_Hash(&aystar->ClosedListHash, hash, num_buckets);
 

	
 
	// Set up our sorting queue
 
	//  BinaryHeap allocates a block of 1024 nodes
 
	//  When thatone gets full it reserves an otherone, till this number
 
	//  That is why it can stay this high
 
	init_BinaryHeap(&aystar->OpenListQueue, 102400);
 

	
 
	aystar->addstart	= AyStarMain_AddStartNode;
 
	aystar->main		= AyStarMain_Main;
 
	aystar->loop		= AyStarMain_Loop;
 
	aystar->free		= AyStarMain_Free;
 
	aystar->clear		= AyStarMain_Clear;
 
	aystar->checktile	= AyStarMain_CheckTile;
 
}
clear_cmd.c
Show inline comments
 
@@ -121,138 +121,142 @@ static bool TerraformTileHeight(Terrafor
 
	assert(tile < MapSize());
 

	
 
	if (height < 0) {
 
		_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
 
		return false;
 
	}
 

	
 
	_error_message = STR_1004_TOO_HIGH;
 

	
 
	if (height > 15) return false;
 

	
 
	nh = TerraformGetHeightOfTile(ts, tile);
 
	if (nh < 0 || height == nh) return false;
 

	
 
	if (TerraformProc(ts, tile, 0) < 0) return false;
 
	if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
 
	if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
 
	if (TerraformProc(ts, tile + TileDiffXY(-1,  0), 3) < 0) return false;
 

	
 
	mod = ts->modheight;
 
	count = ts->modheight_count;
 

	
 
	for (;;) {
 
		if (count == 0) {
 
			if (ts->modheight_count >= 576)
 
				return false;
 
			if (ts->modheight_count >= 576) return false;
 
			ts->modheight_count++;
 
			break;
 
		}
 
		if (mod->tile == tile) break;
 
		mod++;
 
		count--;
 
	}
 

	
 
	mod->tile = tile;
 
	mod->height = (byte)height;
 

	
 
	ts->cost += _price.terraform;
 

	
 
	{
 
		int direction = ts->direction, r;
 
		const TileIndexDiffC *ttm;
 

	
 
		static const TileIndexDiffC _terraform_tilepos[] = {
 
			{ 1,  0},
 
			{-2,  0},
 
			{ 1,  1},
 
			{ 0, -2}
 
		};
 

	
 
		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
 
			tile += ToTileIndexDiff(*ttm);
 

	
 
			r = TerraformGetHeightOfTile(ts, tile);
 
			if (r != height && r-direction != height && r+direction != height) {
 
				if (!TerraformTileHeight(ts, tile, r+direction))
 
					return false;
 
			}
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
/** Terraform land
 
 * @param tile tile to terraform
 
 * @param p1 corners to terraform.
 
 * @param p2 direction; eg up or down
 
 */
 
int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	TerraformerState ts;
 
	TileIndex t;
 
	int direction;
 

	
 
	TerraformerHeightMod modheight_data[576];
 
	TileIndex tile_table_data[625];
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	_terraform_err_tile = 0;
 

	
 
	ts.direction = direction = p2 ? 1 : -1;
 
	ts.flags = flags;
 
	ts.modheight_count = ts.tile_table_count = 0;
 
	ts.cost = 0;
 
	ts.modheight = modheight_data;
 
	ts.tile_table = tile_table_data;
 

	
 
	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
 
	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
 

	
 
	if (p1 & 1) {
 
		if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 0),
 
				TileHeight(tile + TileDiffXY(1, 0)) + direction))
 
		t = tile + TileDiffXY(1, 0);
 
		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
 
					return CMD_ERROR;
 
	}
 
	}
 

	
 
	if (p1 & 2) {
 
		if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 1),
 
				TileHeight(tile + TileDiffXY(1, 1)) + direction))
 
		t = tile + TileDiffXY(1, 1);
 
		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
 
					return CMD_ERROR;
 
	}
 
	}
 

	
 
	if (p1 & 4) {
 
		if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 1),
 
				TileHeight(tile + TileDiffXY(0, 1)) + direction))
 
		t = tile + TileDiffXY(0, 1);
 
		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
 
					return CMD_ERROR;
 
	}
 
	}
 

	
 
	if (p1 & 8) {
 
		if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 0),
 
				TileHeight(tile + TileDiffXY(0, 0)) + direction))
 
		t = tile + TileDiffXY(0, 0);
 
		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
 
					return CMD_ERROR;
 
	}
 
	}
 

	
 
	{ /* Check if tunnel or track would take damage */
 
		int count;
 
		TileIndex *ti = ts.tile_table;
 

	
 
		for (count = ts.tile_table_count; count != 0; count--, ti++) {
 
			uint a, b, c, d, r, min;
 
			TileIndex tile = *ti;
 

	
 
			_terraform_err_tile = tile;
 

	
 
			a = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
 
			b = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
 
			c = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
 
			d = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
 

	
 
			r = GetTileh(a, b, c, d, &min);
 

	
 
			if (IsTileType(tile, MP_RAILWAY)) {
 
				if (IsSteepSlope(r)) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
 

	
 
				if (IsPlainRailTile(tile)) {
 
					extern const TrackBits _valid_tileh_slopes[2][15];
 
					if (GetTrackBits(tile) & ~_valid_tileh_slopes[0][r]) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
 
@@ -409,50 +413,49 @@ static int32 ClearTile_Clear(TileIndex t
 
		price = *clear_price_table[GetClearGround(tile)];
 
	}
 

	
 
	if (flags & DC_EXEC) DoClearSquare(tile);
 

	
 
	return price;
 
}
 

	
 
/** Sell a land area. Actually you only sell one tile, so
 
 * the name is a bit confusing ;p
 
 * @param tile the tile the player is selling
 
 * @param p1 unused
 
 * @param p2 unused
 
 */
 
int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	if (!IsOwnedLandTile(tile)) return CMD_ERROR;
 
	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
 

	
 

	
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC)
 
		DoClearSquare(tile);
 
	if (flags & DC_EXEC) DoClearSquare(tile);
 

	
 
	return - _price.purchase_land * 2;
 
}
 

	
 

	
 
#include "table/clear_land.h"
 

	
 

	
 
void DrawClearLandTile(const TileInfo *ti, byte set)
 
{
 
	DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
 
}
 

	
 
void DrawHillyLandTile(const TileInfo *ti)
 
{
 
	if (ti->tileh != SLOPE_FLAT) {
 
		DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
 
	} else {
 
		DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
 
	}
 
}
 

	
 
void DrawClearLandFence(const TileInfo *ti)
 
{
command.c
Show inline comments
 
@@ -293,80 +293,85 @@ static const Command _command_proc_table
 

	
 
	{CmdRefitRailVehicle,                    0}, /* 106 */
 
	{CmdRestoreOrderIndex,                   0}, /* 107 */
 
	{CmdBuildLock,                           0}, /* 108 */
 
	{NULL,                                   0}, /* 109 */
 
	{CmdBuildSignalTrack,                    0}, /* 110 */
 
	{CmdRemoveSignalTrack,                   0}, /* 111 */
 
	{NULL,                                   0}, /* 112 */
 
	{CmdGiveMoney,                           0}, /* 113 */
 
	{CmdChangePatchSetting,         CMD_SERVER}, /* 114 */
 
	{CmdReplaceVehicle,                      0}, /* 115 */
 
	{CmdCloneVehicle,                        0}, /* 116 */
 
};
 

	
 
/* This function range-checks a cmd, and checks if the cmd is not NULL */
 
bool IsValidCommand(uint cmd)
 
{
 
	cmd &= 0xFF;
 

	
 
	return
 
		cmd < lengthof(_command_proc_table) &&
 
		_command_proc_table[cmd].proc != NULL;
 
}
 

	
 
byte GetCommandFlags(uint cmd) {return _command_proc_table[cmd & 0xFF].flags;}
 
byte GetCommandFlags(uint cmd)
 
{
 
	return _command_proc_table[cmd & 0xFF].flags;
 
}
 

	
 

	
 
static int _docommand_recursive;
 

	
 
int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
 
{
 
	int32 res;
 
	CommandProc *proc;
 

	
 
	/* Do not even think about executing out-of-bounds tile-commands */
 
	if (tile >= MapSize()) {
 
		_cmd_text = NULL;
 
		return CMD_ERROR;
 
	}
 

	
 
	proc = _command_proc_table[procc].proc;
 

	
 
	if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
 

	
 
	_docommand_recursive++;
 

	
 
	// only execute the test call if it's toplevel, or we're not execing.
 
	if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) {
 
		res = proc(tile, flags & ~DC_EXEC, p1, p2);
 
		if (CmdFailed(res)) {
 
			if (res & 0xFFFF) _error_message = res & 0xFFFF;
 
			goto error;
 
		}
 

	
 
		if (_docommand_recursive == 1) {
 
			if (!(flags&DC_QUERY_COST) && res != 0 && !CheckPlayerHasMoney(res))
 
		if (_docommand_recursive == 1 &&
 
				!(flags & DC_QUERY_COST) &&
 
				res != 0 &&
 
				!CheckPlayerHasMoney(res)) {
 
				goto error;
 
		}
 

	
 
		if (!(flags & DC_EXEC)) {
 
			_docommand_recursive--;
 
			_cmd_text = NULL;
 
			return res;
 
		}
 
	}
 

	
 
	/* Execute the command here. All cost-relevant functions set the expenses type
 
	 * themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */
 
	res = proc(tile, flags, p1, p2);
 
	if (CmdFailed(res)) {
 
		if (res & 0xFFFF) _error_message = res & 0xFFFF;
 
error:
 
		_docommand_recursive--;
 
		_cmd_text = NULL;
 
		return CMD_ERROR;
 
	}
 

	
 
	// if toplevel, subtract the money.
 
	if (--_docommand_recursive == 0) {
 
		SubtractMoneyFromPlayer(res);
 
@@ -475,71 +480,72 @@ bool DoCommandP(TileIndex tile, uint32 p
 
			goto show_error;
 
		}
 
		// no money? Only check if notest is off
 
		if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
 
	}
 

	
 
#ifdef ENABLE_NETWORK
 
	/** If we are in network, and the command is not from the network
 
	 * send it to the command-queue and abort execution
 
	 * If we are a dedicated server temporarily switch local player, otherwise
 
	 * the other parties won't be able to execute our command and will desync.
 
	 * @todo Rewrite dedicated server to something more than a dirty hack!
 
	 */
 
	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
 
		if (_network_dedicated) _local_player = 0;
 
		NetworkSend_Command(tile, p1, p2, cmd, callback);
 
		if (_network_dedicated) _local_player = OWNER_SPECTATOR;
 
		_docommand_recursive = 0;
 
		_cmd_text = NULL;
 
		return true;
 
	}
 
#endif /* ENABLE_NETWORK */
 

	
 
	// update last build coordinate of player.
 
	if ( tile != 0 && _current_player < MAX_PLAYERS) GetPlayer(_current_player)->last_build_coordinate = tile;
 
	if (tile != 0 && _current_player < MAX_PLAYERS) {
 
		GetPlayer(_current_player)->last_build_coordinate = tile;
 
	}
 

	
 
	/* Actually try and execute the command. If no cost-type is given
 
	 * use the construction one */
 
	_yearly_expenses_type = EXPENSES_CONSTRUCTION;
 
	res2 = proc(tile, flags|DC_EXEC, p1, p2);
 

	
 
	// If notest is on, it means the result of the test can be different than
 
	//   the real command.. so ignore the test
 
	if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
 
		assert(res == res2); // sanity check
 
	} else {
 
		if (CmdFailed(res2)) {
 
			if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
 
			goto show_error;
 
		}
 
	}
 

	
 
	SubtractMoneyFromPlayer(res2);
 

	
 
	if (IsLocalPlayer() && _game_mode != GM_EDITOR) {
 
		if (res2 != 0)
 
			ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
 
		if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
 
		if (_additional_cash_required) {
 
			SetDParam(0, _additional_cash_required);
 
			ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y);
 
			if (res2 == 0) goto callb_err;
 
		}
 
	}
 

	
 
	_docommand_recursive = 0;
 

	
 
	if (callback) callback(true, tile, p1, p2);
 
	_cmd_text = NULL;
 
	return true;
 

	
 
show_error:
 
	// show error message if the command fails?
 
	if (IsLocalPlayer() && error_part1 != 0) {
 
		ShowErrorMessage(_error_message, error_part1, x,y);
 
	}
 

	
 
callb_err:
 
	_docommand_recursive = 0;
 

	
 
	if (callback) callback(false, tile, p1, p2);
 
	_cmd_text = NULL;
depot.h
Show inline comments
 
@@ -51,50 +51,49 @@ static inline bool IsDepotIndex(uint ind
 
/** Get the service interval domain.
 
 * Get the new proposed service interval for the vehicle is indeed, clamped
 
 * within the given bounds. @see MIN_SERVINT_PERCENT ,etc.
 
 * @param index proposed service interval
 
 */
 
static inline uint16 GetServiceIntervalClamped(uint index)
 
{
 
	return (_patches.servint_ispercent) ? clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
 
}
 

	
 

	
 
/**
 
 * Check if a depot really exists.
 
 */
 
static inline bool IsValidDepot(const Depot* depot)
 
{
 
	return depot->xy != 0; /* XXX: Replace by INVALID_TILE someday */
 
}
 

	
 
/**
 
 * Check if a tile is a depot of the given type.
 
 */
 
static inline bool IsTileDepotType(TileIndex tile, TransportType type)
 
{
 
	switch (type)
 
	{
 
	switch (type) {
 
		case TRANSPORT_RAIL:
 
			return IsTileType(tile, MP_RAILWAY) && (_m[tile].m5 & 0xFC) == 0xC0;
 

	
 
		case TRANSPORT_ROAD:
 
			return IsTileType(tile, MP_STREET) && (_m[tile].m5 & 0xF0) == 0x20;
 

	
 
		case TRANSPORT_WATER:
 
			return IsTileType(tile, MP_WATER) && (_m[tile].m5 & ~3) == 0x80;
 

	
 
		default:
 
			assert(0);
 
			return false;
 
	}
 
}
 

	
 

	
 
/**
 
	Find out if the slope of the tile is suitable to build a depot of given direction
 
	@param direction The direction in which the depot's exit points. Starts with 0 as NE and goes Clockwise
 
	@param tileh The slope of the tile in question
 
	@return true if the construction is possible
 

	
 

	
 
    This is checked by the ugly 0x4C >> direction magic, which does the following:
elrail.c
Show inline comments
 
@@ -173,50 +173,51 @@ static void DrawCatenaryRailway(const Ti
 

	
 
	AdjustTileh(ti->tile, &tileh[TS_HOME]);
 

	
 
	for (i = DIAGDIR_NE; i < DIAGDIR_END; i++) {
 
		TileIndex neighbour = ti->tile + TileOffsByDir(i);
 
		uint foundation = 0;
 
		int k;
 

	
 
		/* Here's one of the main headaches. GetTileSlope does not correct for possibly
 
		   existing foundataions, so we do have to do that manually later on.*/
 
		tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour, NULL);
 
		trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL);
 
		if (IsTunnelTile(neighbour) && i != GetTunnelDirection(neighbour)) trackconfig[TS_NEIGHBOUR] = 0;
 
		isflat[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] & (TRACK_BIT_HORZ | TRACK_BIT_VERT);
 

	
 
		PPPpreferred[i] = 0xFF; /* We start with preferring everything (end-of-line in any direction) */
 
		PPPallowed[i] = AllowedPPPonPCP[i];
 

	
 
		/* We cycle through all the existing tracks at a PCP and see what
 
		   PPPs we want to have, or may not have at all */
 
		for (k = 0; k < NUM_TRACKS_AT_PCP; k++) {
 
			/* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */
 
			if (TrackSourceTile[i][k] == TS_NEIGHBOUR &&
 
			    IsBridgeTile(neighbour) && IsBridgeRamp(neighbour) &&
 
			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)
 
			   ) continue;
 
			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)) {
 
				continue;
 
			}
 

	
 
			/* We check whether the track in question (k) is present in the tile
 
			   (TrackSourceTile) */
 
			if (HASBIT(trackconfig[TrackSourceTile[i][k]], TracksAtPCP[i][k])) {
 
				/* track found, if track is in the neighbour tile, adjust the number
 
				   of the PCP for preferred/allowed determination*/
 
				DiagDirection PCPpos = (TrackSourceTile[i][k] == TS_HOME) ? i : ReverseDiagDir(i);
 
				SETBIT(PCPstatus, i); /* This PCP is in use */
 

	
 
				PPPpreferred[i] &= PreferredPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
 
				PPPallowed[i] &= ~DisallowedPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
 
			}
 
		}
 

	
 
		/* Deactivate all PPPs if PCP is not used */
 
		PPPpreferred[i] *= HASBIT(PCPstatus, i);
 
		PPPallowed[i] *= HASBIT(PCPstatus, i);
 

	
 
		/* A station is always "flat", so adjust the tileh accordingly */
 
		if (IsTileType(neighbour, MP_STATION)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
 

	
 
		/* Read the foundataions if they are present, and adjust the tileh */
 
		if (IsTileType(neighbour, MP_RAILWAY)) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
 
		if (IsBridgeTile(neighbour) && IsBridgeRamp(neighbour)) {
functions.h
Show inline comments
 
@@ -184,49 +184,49 @@ void DeleteWindowById(WindowClass cls, W
 
void DeleteWindowByClass(WindowClass cls);
 

	
 
void SetObjectToPlaceWnd(CursorID icon, byte mode, Window *w);
 
void SetObjectToPlace(CursorID icon, byte mode, WindowClass window_class, WindowNumber window_num);
 

	
 
void ResetObjectToPlace(void);
 

	
 
bool ScrollWindowTo(int x, int y, Window * w);
 

	
 
bool ScrollMainWindowToTile(TileIndex tile);
 
bool ScrollMainWindowTo(int x, int y);
 
void DrawSprite(uint32 img, int x, int y);
 
bool EnsureNoVehicle(TileIndex tile);
 
bool EnsureNoVehicleOnGround(TileIndex tile);
 
void MarkAllViewportsDirty(int left, int top, int right, int bottom);
 
void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost);
 
void ShowFeederIncomeAnimation(int x, int y, int z, int32 cost);
 

	
 
void DrawFoundation(TileInfo *ti, uint f);
 

	
 
bool CheckIfAuthorityAllows(TileIndex tile);
 
Town *ClosestTownFromTile(TileIndex tile, uint threshold);
 
void ChangeTownRating(Town *t, int add, int max);
 

	
 
int GetTownRadiusGroup(const Town *t, TileIndex tile);
 
uint GetTownRadiusGroup(const Town* t, TileIndex tile);
 
void ShowNetworkChatQueryWindow(byte desttype, byte dest);
 
void ShowNetworkGiveMoneyWindow(byte player);
 
void ShowNetworkNeedGamePassword(void);
 
void ShowNetworkNeedCompanyPassword(void);
 
int FindFirstBit(uint32 x);
 
void ShowHighscoreTable(int difficulty, int8 rank);
 
void ShowEndGameChart(void);
 
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
 

	
 
void AfterLoadTown(void);
 
void UpdatePatches(void);
 
void GenRandomNewGame(uint32 rnd1, uint32 rnd2);
 
void StartScenarioEditor(uint32 rnd1, uint32 rnd2);
 
void AskExitGame(void);
 
void AskExitToGameMenu(void);
 

	
 
void RedrawAutosave(void);
 

	
 
StringID RemapOldStringID(StringID s);
 

	
 
void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str);
 

	
 
enum {
 
	SLD_LOAD_GAME = 0,
landscape.c
Show inline comments
 
@@ -374,49 +374,49 @@ void RunTileLoop(void)
 
		tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
 
	_cur_tileloop_tile = tile;
 
}
 

	
 
void InitializeLandscape(void)
 
{
 
	uint maxx = MapMaxX();
 
	uint maxy = MapMaxY();
 
	uint sizex = MapSizeX();
 
	uint x;
 
	uint y;
 

	
 
	for (y = 0; y < maxy; y++) {
 
		for (x = 0; x < maxx; x++) {
 
			MakeClear(sizex * y + x, CLEAR_GRASS, 3);
 
			SetTileHeight(sizex * y + x, 0);
 
		}
 
		MakeVoid(sizex * y + x);
 
	}
 
	for (x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
 
}
 

	
 
void ConvertGroundTilesIntoWaterTiles(void)
 
{
 
	TileIndex tile = 0;
 
	TileIndex tile;
 

	
 
	for (tile = 0; tile < MapSize(); ++tile) {
 
		if (IsTileType(tile, MP_CLEAR) && GetTileMaxZ(tile) == 0) {
 
			MakeWater(tile);
 
		}
 
	}
 
}
 

	
 
static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
 
static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
 

	
 
static void GenerateTerrain(int type, int flag)
 
{
 
	uint32 r;
 
	uint x;
 
	uint y;
 
	uint w;
 
	uint h;
 
	const Sprite* template;
 
	const byte *p;
 
	Tile* tile;
 
	byte direction;
 

	
 
	r = Random();
map.h
Show inline comments
 
@@ -46,53 +46,53 @@ uint ScaleByMapSize(uint); // Scale rela
 
uint ScaleByMapSize1D(uint); // Scale relative to the circumference of the map
 

	
 
typedef uint32 TileIndex;
 
typedef int32 TileIndexDiff;
 

	
 
static inline TileIndex TileXY(uint x, uint y)
 
{
 
	return (y * MapSizeX()) + x;
 
}
 

	
 
static inline TileIndexDiff TileDiffXY(int x, int y)
 
{
 
	// Multiplication gives much better optimization on MSVC than shifting.
 
	// 0 << shift isn't optimized to 0 properly.
 
	// Typically x and y are constants, and then this doesn't result
 
	// in any actual multiplication in the assembly code..
 
	return (y * MapSizeX()) + x;
 
}
 

	
 
static inline TileIndex TileVirtXY(uint x, uint y)
 
{
 
	return (y >> 4 << MapLogX()) + (x >> 4);
 
}
 

	
 
typedef enum {
 
	OWNER_TOWN			= 0xf,	// a town owns the tile
 
typedef enum Owner {
 
	OWNER_TOWN      = 0x0F, // a town owns the tile
 
	OWNER_NONE			= 0x10,	// nobody owns the tile
 
	OWNER_WATER			= 0x11,	// "water" owns the tile
 
	OWNER_SPECTATOR	= 0xff,	// spectator in MP or in scenario editor
 
	OWNER_SPECTATOR = 0xFF, // spectator in MP or in scenario editor
 
} Owner;
 

	
 
enum {
 
	INVALID_TILE = (TileIndex)-1
 
};
 

	
 
enum {
 
	TILE_SIZE   = 16,   /* Tiles are 16x16 "units" in size */
 
	TILE_PIXELS = 32,   /* a tile is 32x32 pixels */
 
	TILE_HEIGHT = 8,    /* The standard height-difference between tiles on two levels is 8 (z-diff 8) */
 
};
 

	
 

	
 
static inline uint TileX(TileIndex tile)
 
{
 
	return tile & MapMaxX();
 
}
 

	
 
static inline uint TileY(TileIndex tile)
 
{
 
	return tile >> MapLogX();
 
}
 

	
 

	
misc_gui.c
Show inline comments
 
@@ -709,49 +709,50 @@ static void DrawStationCoverageText(cons
 
	DrawStringMultiLine(str_x, str_y, STR_SPEC_USERSTRING, 144);
 
}
 

	
 
void DrawStationCoverageAreaText(int sx, int sy, uint mask, int rad) {
 
	TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
 
	AcceptedCargo accepts;
 
	if (tile < MapSize()) {
 
		GetAcceptanceAroundTiles(accepts, tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE , rad);
 
		DrawStationCoverageText(accepts, sx, sy, mask);
 
	}
 
}
 

	
 
void CheckRedrawStationCoverage(const Window* w)
 
{
 
	if (_thd.dirty & 1) {
 
		_thd.dirty &= ~1;
 
		SetWindowDirty(w);
 
	}
 
}
 

	
 

	
 
void UnclickSomeWindowButtons(Window *w, uint32 mask)
 
{
 
	uint32 x = w->click_state & mask;
 
	int i = 0;
 
	uint i = 0;
 

	
 
	w->click_state ^= x;
 
	do {
 
		if (x & 1) InvalidateWidget(w, i);
 
	} while (i++, x >>= 1);
 
}
 

	
 

	
 
void UnclickWindowButtons(Window *w)
 
{
 
	UnclickSomeWindowButtons(w, (uint32)-1);
 
}
 

	
 

	
 
void SetVScrollCount(Window *w, int num)
 
{
 
	w->vscroll.count = num;
 
	num -= w->vscroll.cap;
 
	if (num < 0) num = 0;
 
	if (num < w->vscroll.pos) w->vscroll.pos = num;
 
}
 

	
 
void SetVScroll2Count(Window *w, int num)
 
{
 
	w->vscroll2.count = num;
 
@@ -1230,82 +1231,82 @@ static void SaveLoadDlgWndProc(Window *w
 
{
 
	static FiosItem o_dir;
 

	
 
	switch (e->event) {
 
	case WE_CREATE: { /* Set up OPENTTD button */
 
		o_dir.type = FIOS_TYPE_DIRECT;
 
		switch (_saveload_mode) {
 
			case SLD_SAVE_GAME:
 
			case SLD_LOAD_GAME:
 
				ttd_strlcpy(&o_dir.name[0], _path.save_dir, sizeof(o_dir.name));
 
				break;
 

	
 
			case SLD_SAVE_SCENARIO:
 
			case SLD_LOAD_SCENARIO:
 
				ttd_strlcpy(&o_dir.name[0], _path.scenario_dir, sizeof(o_dir.name));
 
				break;
 

	
 
			default:
 
				ttd_strlcpy(&o_dir.name[0], _path.personal_dir, sizeof(o_dir.name));
 
		}
 
		break;
 
		}
 

	
 
	case WE_PAINT: {
 
		int y,pos;
 
		const FiosItem *item;
 
		int pos;
 
		int y;
 

	
 
		SetVScrollCount(w, _fios_num);
 
		DrawWindowWidgets(w);
 
		DrawFiosTexts(w->width);
 

	
 
		if (_savegame_sort_dirty) {
 
			_savegame_sort_dirty = false;
 
			MakeSortedSaveGameList();
 
		}
 

	
 
		GfxFillRect(w->widget[7].left + 1, w->widget[7].top + 1, w->widget[7].right, w->widget[7].bottom, 0xD7);
 
		DoDrawString(
 
			_savegame_sort_order & SORT_DESCENDING ? DOWNARROW : UPARROW,
 
			_savegame_sort_order & SORT_BY_NAME ? w->widget[2].right - 9 : w->widget[3].right - 9,
 
			15, 16
 
		);
 

	
 
		y = w->widget[7].top + 1;
 
		pos = w->vscroll.pos;
 
		while (pos < _fios_num) {
 
			item = _fios_list + pos;
 
		for (pos = w->vscroll.pos; pos < _fios_num; pos++) {
 
			const FiosItem* item = _fios_list + pos;
 

	
 
			DoDrawStringTruncated(item->title, 4, y, _fios_colors[item->type], w->width - 18);
 
			pos++;
 
			y += 10;
 
			if (y >= w->vscroll.cap * 10 + w->widget[7].top + 1) break;
 
		}
 

	
 
		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
 
			DrawEditBox(w, &WP(w,querystr_d), 10);
 
		}
 
		break;
 
	}
 

	
 
	case WE_CLICK:
 
		switch (e->click.widget) {
 
		case 2: /* Sort save names by name */
 
			_savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ?
 
				SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME;
 
			_savegame_sort_dirty = true;
 
			SetWindowDirty(w);
 
			break;
 

	
 
		case 3: /* Sort save names by date */
 
			_savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ?
 
				SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE;
 
			_savegame_sort_dirty = true;
 
			SetWindowDirty(w);
 
			break;
 

	
 
		case 6: /* OpenTTD 'button', jumps to OpenTTD directory */
 
			FiosBrowseTo(&o_dir);
 
			SetWindowDirty(w);
 
			BuildFileList();
 
			break;
 

	
 
		case 7: { /* Click the listbox */
 
			int y = (e->click.pt.y - w->widget[e->click.widget].top - 1) / 10;
music/qtmidi.c
Show inline comments
 
@@ -45,171 +45,166 @@
 
#include <fcntl.h>
 

	
 
// we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2
 
#include "../debug.h"
 

	
 

	
 
enum {
 
	midiType = 'Midi' /**< OSType code for MIDI songs. */
 
};
 

	
 

	
 
/**
 
 * Converts a Unix-like pathname to a @c FSSpec structure which may be
 
 * used with functions from several MacOS X frameworks (Carbon, QuickTime,
 
 * etc). The pointed file or directory must exist.
 
 *
 
 * @param *path A string containing a Unix-like path.
 
 * @param *spec Pointer to a @c FSSpec structure where the result will be
 
 *              stored.
 
 * @return Wether the conversion was successful.
 
 */
 
static bool PathToFSSpec(const char *path, FSSpec *spec)
 
{
 
	FSRef ref;
 
	assert(spec);
 
	assert(path);
 
	assert(spec != NULL);
 
	assert(path != NULL);
 

	
 
	if (noErr != FSPathMakeRef((UInt8*) path, &ref, NULL))
 
		return false;
 

	
 
	return (noErr ==
 
			FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL));
 
	return
 
		FSPathMakeRef((UInt8*)path, &ref, NULL) == noErr &&
 
		FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL) == noErr;
 
}
 

	
 

	
 
/**
 
 * Sets the @c OSType of a given file to @c 'Midi', but only if it's not
 
 * already set.
 
 *
 
 * @param *spec A @c FSSpec structure referencing a file.
 
 */
 
static void SetMIDITypeIfNeeded(const FSSpec *spec)
 
{
 
	FInfo info;
 
	assert(spec);
 

	
 
	if (noErr != FSpGetFInfo(spec, &info)) return;
 

	
 
	/* Set file type to 'Midi' if the file is _not_ an alias. */
 
	if ((info.fdType != midiType) && !(info.fdFlags & kIsAlias)) {
 
	if (info.fdType != midiType && !(info.fdFlags & kIsAlias)) {
 
		info.fdType = midiType;
 
		FSpSetFInfo(spec, &info);
 
		DEBUG(driver, 3) ("qtmidi: changed filetype to 'Midi'");
 
	}
 
}
 

	
 

	
 
/**
 
 * Loads a MIDI file and returns it as a QuickTime Movie structure.
 
 *
 
 * @param *path String with the path of an existing MIDI file.
 
 * @param *moov Pointer to a @c Movie where the result will be stored.
 
 * @return Wether the file was loaded and the @c Movie successfully created.
 
 */
 
static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
 
{
 
	int fd;
 
	int ret;
 
	char magic[4];
 
	FSSpec fsspec;
 
	short refnum = 0;
 
	short resid  = 0;
 

	
 
	assert(path);
 
	assert(moov);
 
	assert(path != NULL);
 
	assert(moov != NULL);
 

	
 
	DEBUG(driver, 2) ("qtmidi: begin loading '%s'...", path);
 

	
 
	/*
 
	 * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
 
	 * QuickTime load MIDI files without a .mid suffix without knowing it's
 
	 * a MIDI file and setting the OSType of the file to the 'Midi' value.
 
	 * Perhahaps ugly, but it seems that it does the Right Thing(tm).
 
	 */
 
	if ((fd = open(path, O_RDONLY, 0)) == -1)
 
		return false;
 
	fd = open(path, O_RDONLY, 0);
 
	if (fd == -1) return false;
 
	ret = read(fd, magic, 4);
 
	close(fd);
 
	if (ret < 4) return false;
 

	
 
	DEBUG(driver, 3) ("qtmidi: header is '%c%c%c%c'",
 
			magic[0], magic[1], magic[2], magic[3]);
 
	DEBUG(driver, 3) ("qtmidi: header is '%.4s'", magic);
 
	if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd')
 
		return false;
 

	
 
	if (!PathToFSSpec(path, &fsspec))
 
		return false;
 
	if (!PathToFSSpec(path, &fsspec)) return false;
 
	SetMIDITypeIfNeeded(&fsspec);
 

	
 
	if (noErr != OpenMovieFile(&fsspec, &refnum, fsRdPerm))
 
		return false;
 
	if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
 
	DEBUG(driver, 1) ("qtmidi: '%s' successfully opened", path);
 

	
 
	if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
 
				newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL))
 
	{
 
		CloseMovieFile(refnum);
 
		return false;
 
	}
 
	DEBUG(driver, 2) ("qtmidi: movie container created");
 

	
 
	CloseMovieFile(refnum);
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Flag which has the @c true value when QuickTime is available and
 
 * initialized.
 
 */
 
static bool _quicktime_started = false;
 

	
 

	
 
/**
 
 * Initialize QuickTime if needed. This function sets the
 
 * #_quicktime_started flag to @c true if QuickTime is present in the system
 
 * and it was initialized properly.
 
 */
 
static void InitQuickTimeIfNeeded(void)
 
{
 
	OSStatus dummy;
 

	
 
	if (_quicktime_started) return;
 

	
 
	DEBUG(driver, 2) ("qtmidi: trying to initialize Quicktime");
 
	/* Be polite: check wether QuickTime is available and initialize it. */
 
	_quicktime_started =
 
		(noErr == Gestalt(gestaltQuickTime, &dummy)) &&
 
		(noErr == EnterMovies());
 
	DEBUG(driver, 1) ("qtmidi: Quicktime was %s initialized",
 
			_quicktime_started ? "successfully" : "NOT");
 
		_quicktime_started ? "successfully" : "NOT"
 
	);
 
}
 

	
 

	
 
/** Possible states of the QuickTime music driver. */
 
enum
 
{
 
enum {
 
	QT_STATE_IDLE, /**< No file loaded. */
 
	QT_STATE_PLAY, /**< File loaded, playing. */
 
	QT_STATE_STOP, /**< File loaded, stopped. */
 
};
 

	
 

	
 
static Movie _quicktime_movie;                  /**< Current QuickTime @c Movie. */
 
static byte  _quicktime_volume = 127;           /**< Current volume. */
 
static int   _quicktime_state  = QT_STATE_IDLE; /**< Current player state. */
 

	
 

	
 
/**
 
 * Maps OpenTTD volume to QuickTime notion of volume.
 
 */
 
#define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
 

	
 

	
 
static void StopSong(void);
 

	
 

	
 
/**
 
 * Initialized the MIDI player, including QuickTime initialization.
 
 *
 
 * @todo Give better error messages by inspecting error codes returned by
 
@@ -226,49 +221,49 @@ static const char* StartDriver(const cha
 
/**
 
 * Checks wether the player is active.
 
 *
 
 * This function is called at regular intervals from OpenTTD's main loop, so
 
 * we call @c MoviesTask() from here to let QuickTime do its work.
 
 */
 
static bool SongIsPlaying(void)
 
{
 
	if (!_quicktime_started) return true;
 

	
 
	switch (_quicktime_state) {
 
		case QT_STATE_IDLE:
 
		case QT_STATE_STOP:
 
			/* Do nothing. */
 
			break;
 
		case QT_STATE_PLAY:
 
			MoviesTask(_quicktime_movie, 0);
 
			/* Check wether movie ended. */
 
			if (IsMovieDone(_quicktime_movie) ||
 
					(GetMovieTime(_quicktime_movie, NULL) >=
 
					 GetMovieDuration(_quicktime_movie)))
 
				_quicktime_state = QT_STATE_STOP;
 
	}
 

	
 
	return (_quicktime_state == QT_STATE_PLAY);
 
	return _quicktime_state == QT_STATE_PLAY;
 
}
 

	
 

	
 
/**
 
 * Stops the MIDI player.
 
 *
 
 * Stops playing and frees any used resources before returning. As it
 
 * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false.
 
 */
 
static void StopDriver(void)
 
{
 
	if (!_quicktime_started) return;
 

	
 
	DEBUG(driver, 2) ("qtmidi: trying to stop driver...");
 
	switch (_quicktime_state) {
 
		case QT_STATE_IDLE:
 
			DEBUG(driver, 3) ("qtmidi: nothing to do (already idle)");
 
			/* Do nothing. */
 
			break;
 
		case QT_STATE_PLAY:
 
			StopSong();
 
		case QT_STATE_STOP:
 
			DisposeMovie(_quicktime_movie);
 
	}
network.c
Show inline comments
 
@@ -1221,53 +1221,51 @@ static bool NetworkDoClientLoop(void)
 
			//   frame as he is.. so we can start playing!
 
			if (_network_first_time) {
 
				_network_first_time = false;
 
				SEND_COMMAND(PACKET_CLIENT_ACK)();
 
			}
 

	
 
			_sync_frame = 0;
 
		} else if (_sync_frame < _frame_counter) {
 
			DEBUG(net, 1)("[NET] Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
 
			_sync_frame = 0;
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
// We have to do some UDP checking
 
void NetworkUDPGameLoop(void)
 
{
 
	if (_network_udp_server) {
 
		NetworkUDPReceive(_udp_server_socket);
 
		if (_udp_master_socket != INVALID_SOCKET) {
 
			NetworkUDPReceive(_udp_master_socket);
 
		}
 
	}
 
	else if (_udp_client_socket != INVALID_SOCKET) {
 
	} else if (_udp_client_socket != INVALID_SOCKET) {
 
		NetworkUDPReceive(_udp_client_socket);
 
		if (_network_udp_broadcast > 0)
 
			_network_udp_broadcast--;
 
		if (_network_udp_broadcast > 0) _network_udp_broadcast--;
 
	}
 
}
 

	
 
// The main loop called from ttd.c
 
//  Here we also have to do StateGameLoop if needed!
 
void NetworkGameLoop(void)
 
{
 
	if (!_networking) return;
 

	
 
	if (!NetworkReceive()) return;
 

	
 
	if (_network_server) {
 
		bool send_frame = false;
 

	
 
		// We first increase the _frame_counter
 
		_frame_counter++;
 
		// Update max-frame-counter
 
		if (_frame_counter > _frame_counter_max) {
 
			_frame_counter_max = _frame_counter + _network_frame_freq;
 
			send_frame = true;
 
		}
 

	
 
		NetworkHandleLocalQueue();
 

	
news_gui.c
Show inline comments
 
@@ -200,63 +200,60 @@ static void NewsWindowProc(Window *w, Wi
 
			case WE_DESTROY: w->message.msg = 0; break;
 
		}
 
		break;
 

	
 
	case WE_TICK: { /* Scroll up newsmessages from the bottom in steps of 4 pixels */
 
		int diff;
 
		int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg);
 
		if (y == w->top) return;
 

	
 
		if (w->viewport != NULL)
 
			w->viewport->top += y - w->top;
 

	
 
		diff = abs(w->top - y);
 
		w->top = y;
 

	
 
		SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
 
	} break;
 
	}
 
}
 

	
 
// returns the correct index in the array
 
// (to deal with overflows)
 
static byte increaseIndex(byte i)
 
{
 
	if (i == INVALID_NEWS)
 
		return 0;
 
	if (i == INVALID_NEWS) return 0;
 
	i++;
 
	if (i >= MAX_NEWS)
 
		i = i % MAX_NEWS;
 
	if (i >= MAX_NEWS) i = i % MAX_NEWS;
 
	return i;
 
}
 

	
 
void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b)
 
{
 
	NewsItem *ni;
 
	Window *w;
 

	
 
	if (_game_mode == GM_MENU)
 
		return;
 
	if (_game_mode == GM_MENU) return;
 

	
 
	// check the rare case that the oldest (to be overwritten) news item is open
 
	if (_total_news==MAX_NEWS && (_oldest_news == _current_news || _oldest_news == _forced_news))
 
		MoveToNexItem();
 

	
 
	_forced_news = INVALID_NEWS;
 
	if (_total_news < MAX_NEWS) _total_news++;
 

	
 
	// make sure our pointer isn't overflowing
 
	_latest_news = increaseIndex(_latest_news);
 

	
 
	// overwrite oldest news entry
 
	if (_oldest_news == _latest_news && _news_items[_oldest_news].string_id != 0)
 
		_oldest_news = increaseIndex(_oldest_news); // but make sure we're not overflowing here
 

	
 
	// add news to _latest_news
 
	ni = &_news_items[_latest_news];
 
	memset(ni, 0, sizeof(*ni));
 

	
 
	ni->string_id = string;
 
	ni->display_mode = (byte)flags;
 
	ni->flags = (byte)(flags >> 8) | NF_NOEXPIRE;
 

	
 
	// show this news message in color?
npf.c
Show inline comments
 
@@ -256,50 +256,49 @@ static int32 NPFWaterPathCost(AyStar* as
 
	/* TODO More penalties? */
 

	
 
	return cost;
 
}
 

	
 
/* Determine the cost of this node, for road tracks */
 
static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
 
{
 
	TileIndex tile = current->tile;
 
	int32 cost = 0;
 

	
 
	/* Determine base length */
 
	switch (GetTileType(tile)) {
 
		case MP_TUNNELBRIDGE:
 
			if (IsTunnel(tile)) {
 
				cost = NPFTunnelCost(current);
 
			} else {
 
				cost = NPF_TILE_LENGTH;
 
			}
 
			break;
 

	
 
		case MP_STREET:
 
			cost = NPF_TILE_LENGTH;
 
			/* Increase the cost for level crossings */
 
			if (IsLevelCrossing(tile))
 
				cost += _patches.npf_crossing_penalty;
 
			if (IsLevelCrossing(tile)) cost += _patches.npf_crossing_penalty;
 
			break;
 

	
 
		default:
 
			break;
 
	}
 

	
 
	/* Determine extra costs */
 

	
 
	/* Check for slope */
 
	cost += NPFSlopeCost(current);
 

	
 
	/* Check for turns. Road vehicles only really drive diagonal, turns are
 
	 * represented by non-diagonal tracks */
 
	if (!IsDiagonalTrackdir(current->direction))
 
		cost += _patches.npf_road_curve_penalty;
 

	
 
	NPFMarkTile(tile);
 
	DEBUG(npf, 4)("Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
 
	return cost;
 
}
 

	
 

	
 
/* Determine the cost of this node, for railway tracks */
 
static int32 NPFRailPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
 
@@ -386,57 +385,52 @@ static int32 NPFRailPathCost(AyStar* as,
 
	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
 
		cost += _patches.npf_rail_curve_penalty;
 
	//TODO, with realistic acceleration, also the amount of straight track between
 
	//      curves should be taken into account, as this affects the speed limit.
 

	
 
	/* Check for reverse in depot */
 
	if (IsTileDepotType(tile, TRANSPORT_RAIL) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
 
		/* Penalise any depot tile that is not the last tile in the path. This
 
		 * _should_ penalise every occurence of reversing in a depot (and only
 
		 * that) */
 
		cost += _patches.npf_rail_depot_reverse_penalty;
 
	}
 

	
 
	/* Check for occupied track */
 
	//TODO
 

	
 
	NPFMarkTile(tile);
 
	DEBUG(npf, 4)("Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
 
	return cost;
 
}
 

	
 
/* Will find any depot */
 
static int32 NPFFindDepot(AyStar* as, OpenListNode *current)
 
{
 
	TileIndex tile = current->path.node.tile;
 

	
 
	/* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below,
 
	 * since checking the cache not that much faster than the actual check */
 
	if (IsTileDepotType(tile, as->user_data[NPF_TYPE])) {
 
		return AYSTAR_FOUND_END_NODE;
 
	} else {
 
		return AYSTAR_DONE;
 
	}
 
	return IsTileDepotType(current->path.node.tile, as->user_data[NPF_TYPE]) ?
 
		AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
 
}
 

	
 
/* Will find a station identified using the NPFFindStationOrTileData */
 
static int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current)
 
{
 
	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
 
	AyStarNode *node = &current->path.node;
 
	TileIndex tile = node->tile;
 

	
 
	/* If GetNeighbours said we could get here, we assume the station type
 
	 * is correct */
 
	if (
 
		(fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) || /* We've found the tile, or */
 
		(IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) /* the station */
 
	) {
 
		return AYSTAR_FOUND_END_NODE;
 
	} else {
 
		return AYSTAR_DONE;
 
	}
 
}
 

	
 
/* To be called when current contains the (shortest route to) the target node.
 
 * Will fill the contents of the NPFFoundTargetData using
 
 * AyStarNode[NPF_TRACKDIR_CHOICE].
 
@@ -661,56 +655,54 @@ static void NPFFollowTrack(AyStar* aysta
 
	}
 
	aystar->num_neighbours = i;
 
}
 

	
 
/*
 
 * Plan a route to the specified target (which is checked by target_proc),
 
 * from start1 and if not NULL, from start2 as well. The type of transport we
 
 * are checking is in type. reverse_penalty is applied to all routes that
 
 * originate from the second start node.
 
 * When we are looking for one specific target (optionally multiple tiles), we
 
 * should use a good heuristic to perform aystar search. When we search for
 
 * multiple targets that are spread around, we should perform a breadth first
 
 * search by specifiying CalcZero as our heuristic.
 
 */
 
static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start2, NPFFindStationOrTileData* target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, Owner owner, RailTypeMask railtypes, uint reverse_penalty)
 
{
 
	int r;
 
	NPFFoundTargetData result;
 

	
 
	/* Initialize procs */
 
	_npf_aystar.CalculateH = heuristic_proc;
 
	_npf_aystar.EndNodeCheck = target_proc;
 
	_npf_aystar.FoundEndNode = NPFSaveTargetData;
 
	_npf_aystar.GetNeighbours = NPFFollowTrack;
 
	if (type == TRANSPORT_RAIL)
 
		_npf_aystar.CalculateG = NPFRailPathCost;
 
	else if (type == TRANSPORT_ROAD)
 
		_npf_aystar.CalculateG = NPFRoadPathCost;
 
	else if (type == TRANSPORT_WATER)
 
		_npf_aystar.CalculateG = NPFWaterPathCost;
 
	else
 
		assert(0);
 
	switch (type) {
 
		default: NOT_REACHED();
 
		case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
 
		case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
 
		case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
 
	}
 

	
 
	/* Initialize Start Node(s) */
 
	start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
 
	start1->user_data[NPF_NODE_FLAGS] = 0;
 
	_npf_aystar.addstart(&_npf_aystar, start1, 0);
 
	if (start2) {
 
		start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
 
		start2->user_data[NPF_NODE_FLAGS] = 0;
 
		NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
 
		_npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty);
 
	}
 

	
 
	/* Initialize result */
 
	result.best_bird_dist = (uint)-1;
 
	result.best_path_dist = (uint)-1;
 
	result.best_trackdir = INVALID_TRACKDIR;
 
	_npf_aystar.user_path = &result;
 

	
 
	/* Initialize target */
 
	_npf_aystar.user_target = target;
 

	
 
	/* Initialize user_data */
 
	_npf_aystar.user_data[NPF_TYPE] = type;
 
	_npf_aystar.user_data[NPF_OWNER] = owner;
oldloader.c
Show inline comments
 
@@ -167,54 +167,53 @@ static byte ReadByte(LoadgameState *ls)
 

	
 
	return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
 
}
 

	
 
static inline uint16 ReadUint16(LoadgameState *ls)
 
{
 
	byte x = ReadByte(ls);
 
	return x | ReadByte(ls) << 8;
 
}
 

	
 
static inline uint32 ReadUint32(LoadgameState *ls)
 
{
 
	uint16 x = ReadUint16(ls);
 
	return x | ReadUint16(ls) << 16;
 
}
 

	
 
/**
 
 *
 
 * Loads a chunk from the old savegame
 
 *
 
 */
 
static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
 
{
 
	const OldChunks *chunk = chunks;
 
	byte *ptr;
 
	byte *base_ptr = base;
 
	uint i;
 

	
 
	while (chunk->type != OC_END) {
 
		ptr = chunk->ptr;
 
		byte* ptr = chunk->ptr;
 
		uint i;
 

	
 
		for (i = 0; i < chunk->amount; i++) {
 
			if (ls->failed) return false;
 

	
 
			/* Handle simple types */
 
			if (GetOldChunkType(chunk->type) != 0) {
 
				switch (GetOldChunkType(chunk->type)) {
 
					/* Just read the byte and forget about it */
 
					case OC_NULL: ReadByte(ls); break;
 

	
 
					case OC_CHUNK:
 
						/* Call function, with 'i' as parameter to tell which item we
 
						 * are going to read */
 
						if (!chunk->proc(ls, i)) return false;
 
						break;
 

	
 
					case OC_ASSERT:
 
						DEBUG(oldloader, 4)("[OldLoader] Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
 
						if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
 
					default: break;
 
				}
 
			} else {
 
				uint32 res = 0;
 

	
openttd.c
Show inline comments
 
@@ -992,56 +992,60 @@ void GameLoop(void)
 

	
 
	if (!_pause || _cheats.build_in_pause.value) MoveAllTextEffects();
 

	
 
	InputLoop();
 

	
 
	MusicLoop();
 
}
 

	
 
void BeforeSaveGame(void)
 
{
 
	const Window* w = FindWindowById(WC_MAIN_WINDOW, 0);
 

	
 
	if (w != NULL) {
 
		_saved_scrollpos_x = WP(w, const vp_d).scrollpos_x;
 
		_saved_scrollpos_y = WP(w, const vp_d).scrollpos_y;
 
		_saved_scrollpos_zoom = w->viewport->zoom;
 
	}
 
}
 

	
 
static void ConvertTownOwner(void)
 
{
 
	TileIndex tile;
 

	
 
	for (tile = 0; tile != MapSize(); tile++) {
 
		if (IsTileType(tile, MP_STREET)) {
 
		switch (GetTileType(tile)) {
 
			case MP_STREET:
 
			if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) & 0x80) {
 
				SetCrossingRoadOwner(tile, OWNER_TOWN);
 
			}
 
				/* FALLTHROUGH */
 

	
 
			case MP_TUNNELBRIDGE:
 
			if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
 
		} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
			if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
 
				break;
 

	
 
			default: break;
 
		}
 
	}
 
}
 

	
 
// before savegame version 4, the name of the company determined if it existed
 
static void CheckIsPlayerActive(void)
 
{
 
	Player* p;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->name_1 != 0) p->is_active = true;
 
	}
 
}
 

	
 
// since savegame version 4.1, exclusive transport rights are stored at towns
 
static void UpdateExclusiveRights(void)
 
{
 
	Town* t;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		if (t->xy != 0) t->exclusivity = (byte)-1;
 
	}
 

	
 
	/* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete)
order_cmd.c
Show inline comments
 
@@ -168,49 +168,49 @@ static void DeleteOrderWarnings(const Ve
 
 *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
 
 * @param p2 packed order to insert
 
 */
 
int32 CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Vehicle *v;
 
	VehicleID veh   = GB(p1,  0, 16);
 
	OrderID sel_ord = GB(p1, 16, 16);
 
	Order new_order = UnpackOrder(p2);
 

	
 
	if (!IsVehicleIndex(veh)) return CMD_ERROR;
 
	v = GetVehicle(veh);
 
	if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	/* Check if the inserted order is to the correct destination (owner, type),
 
	 * and has the correct flags if any */
 
	switch (new_order.type) {
 
		case OT_GOTO_STATION: {
 
			const Station *st;
 

	
 
			if (!IsStationIndex(new_order.station)) return CMD_ERROR;
 
			st = GetStation(new_order.station);
 

	
 
			if (!IsValidStation(st) ||
 
					(st->airport_type != AT_OILRIG && !(IsBuoy(st)) && !CheckOwnership(st->owner))) {
 
					(st->airport_type != AT_OILRIG && !IsBuoy(st) && !CheckOwnership(st->owner))) {
 
				return CMD_ERROR;
 
			}
 

	
 
			switch (v->type) {
 
				case VEH_Train:
 
					if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
 
					break;
 

	
 
				case VEH_Road:
 
					if (v->cargo_type == CT_PASSENGERS) {
 
						if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
 
					} else {
 
						if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
 
					}
 
					break;
 

	
 
				case VEH_Ship:
 
					if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
 
					break;
 

	
 
				case VEH_Aircraft:
 
					if (!(st->facilities & FACIL_AIRPORT)) return CMD_ERROR;
 
					break;
 

	
order_gui.c
Show inline comments
 
@@ -447,51 +447,49 @@ static void OrdersWndProc(Window *w, Win
 
			OrderClick_Goto(w, v);
 
			break;
 

	
 
		case 8: /* full load button */
 
			OrderClick_FullLoad(w, v);
 
			break;
 

	
 
		case 9: /* unload button */
 
			OrderClick_Unload(w, v);
 
			break;
 
		case 10: /* transfer button */
 
			OrderClick_Transfer(w, v);
 
			break;
 
		}
 
	} break;
 

	
 
	case WE_KEYPRESS: {
 
		Vehicle *v = GetVehicle(w->window_number);
 
		uint i;
 

	
 
		for (i = 0; i < lengthof(_order_keycodes); i++) {
 
			if (e->keypress.keycode == _order_keycodes[i]) {
 
				e->keypress.cont = false;
 
				//see if the button is disabled
 
				if (!(HASBIT(w->disabled_state, (i + 4)))) {
 
					_order_button_proc[i](w, v);
 
				}
 
				if (!HASBIT(w->disabled_state, i + 4)) _order_button_proc[i](w, v);
 
				break;
 
			}
 
		}
 
		break;
 
	}
 

	
 
	case WE_RCLICK: {
 
		const Vehicle* v = GetVehicle(w->window_number);
 
		int s = OrderGetSel(w);
 

	
 
		if (e->click.widget != 8) break;
 
		if (s == v->num_orders || GetVehicleOrder(v, s)->type != OT_GOTO_DEPOT) {
 
			GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);
 
		} else {
 
			GuiShowTooltips(STR_SERVICE_HINT);
 
		}
 
	} break;
 

	
 
	case WE_4: {
 
		if (FindWindowById(WC_VEHICLE_VIEW, w->window_number) == NULL)
 
			DeleteWindow(w);
 
	} break;
 

	
 
	case WE_PLACE_OBJ: {
pathfind.c
Show inline comments
 
@@ -159,49 +159,49 @@ static void TPFMode2(TrackPathFinder* tp
 
		/* only one direction */
 
		i = 0;
 
		while (!(bits&1))
 
			i++, bits>>=1;
 

	
 
		rd = tpf->rd;
 
		goto continue_here;
 
	}
 
	/* several directions */
 
	i=0;
 
	do {
 
		if (!(bits & 1)) continue;
 
		rd = tpf->rd;
 

	
 
		// Change direction 4 times only
 
		if ((byte)i != tpf->rd.pft_var6) {
 
			if (++tpf->rd.depth > 4) {
 
				tpf->rd = rd;
 
				return;
 
			}
 
			tpf->rd.pft_var6 = (byte)i;
 
		}
 

	
 
continue_here:;
 
		tpf->the_dir = HASBIT(_otherdir_mask[direction],i) ? (i+8) : i;
 
		tpf->the_dir = i + (HASBIT(_otherdir_mask[direction], i) ? 8 : 0);
 

	
 
		if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
 
			TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
 
		}
 

	
 
		tpf->rd = rd;
 
	} while (++i, bits>>=1);
 

	
 
}
 

	
 

	
 
/* Returns the end tile and the length of a tunnel. The length does not
 
 * include the starting tile (entry), it does include the end tile (exit).
 
 */
 
FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, DiagDirection dir)
 
{
 
	TileIndexDiff delta = TileOffsByDir(dir);
 
	uint z = GetTileZ(tile);
 
	FindLengthOfTunnelResult flotr;
 

	
 
	flotr.length = 0;
 

	
 
	dir = ReverseDiagDir(dir);
 
	do {
 
@@ -733,50 +733,49 @@ start_at:
 
		// a rail net and find the first intersection
 
		tile_org = tile;
 
		for (;;) {
 
			assert(direction <= 3);
 
			tile += TileOffsByDir(direction);
 

	
 
			// too long search length? bail out.
 
			if (si.cur_length >= tpf->maxlength) {
 
				DEBUG(ntp,1) ("[NTP] cur_length too big");
 
				bits = 0;
 
				break;
 
			}
 

	
 
			// Not a regular rail tile?
 
			// Then we can't use the code below, but revert to more general code.
 
			if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
 
				// We found a tile which is not a normal railway tile.
 
				// Determine which tracks that exist on this tile.
 
				bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
 
				bits = (bits | (bits >> 8)) & 0x3F;
 

	
 
				// Check that the tile contains exactly one track
 
				if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break;
 

	
 
				/* Check the rail type only if the train is *NOT* on top of
 
				 * a bridge. */
 
				/* Check the rail type only if the train is *NOT* on top of a bridge. */
 
				if (!(IsBridgeTile(tile) && IsBridgeMiddle(tile) && GetBridgeAxis(tile) == DiagDirToAxis(direction))) {
 
					if (IsTileType(tile, MP_STREET) ? !HASBIT(tpf->railtypes, GetRailTypeCrossing(tile)) : !HASBIT(tpf->railtypes, GetRailType(tile))) {
 
						bits = 0;
 
						break;
 
					}
 
				}
 

	
 
				///////////////////
 
				// If we reach here, the tile has exactly one track.
 
				//   tile - index to a tile that is not rail tile, but still straight (with optional signals)
 
				//   bits - bitmask of which track that exist on the tile (exactly one bit is set)
 
				//   direction - which direction are we moving in?
 
				///////////////////
 
				si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
 
				si.cur_length += _length_of_track[si.track];
 
				goto callback_and_continue;
 
			}
 

	
 
			/* Regular rail tile, determine which tracks exist. */
 
			allbits = GetTrackBits(tile);
 
			/* Which tracks are reachable? */
 
			bits = allbits & DiagdirReachesTracks(direction);
 

	
 
			/* The tile has no reachable tracks => End of rail segment
pathfind.h
Show inline comments
 
@@ -16,49 +16,48 @@ typedef bool NTPEnumProc(TileIndex tile,
 

	
 
#define PATHFIND_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
 
#define PATHFIND_GET_LINK_PTR(tpf, link_offs) (TrackPathFinderLink*)((byte*)tpf->links + (link_offs))
 

	
 
/* y7 y6 y5 y4 y3 y2 y1 y0 x7 x6 x5 x4 x3 x2 x1 x0
 
 * y7 y6 y5 y4 y3 y2 y1 y0 x4 x3 x2 x1 x0  0  0  0
 
 *  0  0 y7 y6 y5 y4 y3 y2 y1 y0 x4 x3 x2 x1 x0  0
 
 *  0  0  0  0 y5 y4 y3 y2 y1 y0 x4 x3 x2 x1 x0  0
 
 */
 
#define PATHFIND_HASH_TILE(tile) (TileX(tile) & 0x1F) + ((TileY(tile) & 0x1F) << 5)
 

	
 
typedef struct TrackPathFinderLink {
 
	TileIndex tile;
 
	uint16 flags;
 
	uint16 next;
 
} TrackPathFinderLink;
 

	
 
typedef struct RememberData {
 
	uint16 cur_length;
 
	byte depth;
 
	byte pft_var6;
 
} RememberData;
 

	
 
struct TrackPathFinder {
 

	
 
	int num_links_left;
 
	TrackPathFinderLink *new_link;
 

	
 
	TPFEnumProc *enum_proc;
 

	
 
	void *userdata;
 

	
 
	RememberData rd;
 

	
 
	int the_dir;
 

	
 
	byte tracktype;
 
	byte var2;
 
	bool disable_tile_hash;
 
	bool hasbit_13;
 

	
 
	uint16 hash_head[0x400];
 
	TileIndex hash_tile[0x400]; /* stores the link index when multi link. */
 

	
 
	TrackPathFinderLink links[0x400]; /* hopefully, this is enough. */
 
};
 

	
 
void FollowTrack(TileIndex tile, uint16 flags, DiagDirection direction, TPFEnumProc* enum_proc, TPFAfterProc* after_proc, void* data);
 

	
player_gui.c
Show inline comments
 
@@ -250,49 +250,49 @@ static void SelectPlayerColorWndProc(Win
 
	case WE_PAINT: {
 
		const Player* p;
 
		uint used_colors = 0;
 
		int num_free = 16;
 
		int x,y,pos;
 
		int i;
 

	
 
		FOR_ALL_PLAYERS(p) {
 
			if (p->is_active) {
 
				SETBIT(used_colors, p->player_color);
 
				num_free--;
 
			}
 
		}
 
		WP(w,def_d).data_1 = used_colors;
 
		SetVScrollCount(w, num_free);
 
		DrawWindowWidgets(w);
 

	
 
		x = 2;
 
		y = 17;
 
		pos = w->vscroll.pos;
 

	
 
		for (i = 0; i != 16; i++) {
 
			if (!(used_colors & 1) && --pos < 0 && pos >= -8) {
 
				DrawString(x + 30, y, STR_00D1_DARK_BLUE + i, 2);
 
				DrawSprite(((GENERAL_SPRITE_COLOR(i) | PALETTE_MODIFIER_COLOR) | SPR_VEH_BUS_SIDE_VIEW), x + 14, y + 4);
 
				DrawSprite(GENERAL_SPRITE_COLOR(i) | PALETTE_MODIFIER_COLOR | SPR_VEH_BUS_SIDE_VIEW, x + 14, y + 4);
 
				y += 14;
 
			}
 
			used_colors >>= 1;
 
		}
 
	} break;
 

	
 
	case WE_CLICK:
 
		if (e->click.widget == 2) {
 
			int item = (e->click.pt.y - 13) / 14;
 
			uint used_colors;
 
			int i;
 

	
 
			if ((uint)item >= 8)
 
				return;
 
			item += w->vscroll.pos;
 
			used_colors = WP(w,def_d).data_1;
 

	
 
			for (i = 0; i != 16; i++) {
 
				if (!(used_colors & 1) && --item < 0) {
 
					DoCommandP(0, 0, i, NULL, CMD_SET_PLAYER_COLOR);
 
					DeleteWindow(w);
 
					break;
 
				}
 
				used_colors >>= 1;
players.c
Show inline comments
 
@@ -245,49 +245,49 @@ void SubtractMoneyFromPlayerFract(Player
 
		cost++;
 
	if (cost != 0)
 
		SubtractMoneyFromAnyPlayer(p, cost);
 
}
 

	
 
// the player_money field is kept as it is, but money64 contains the actual amount of money.
 
void UpdatePlayerMoney32(Player *p)
 
{
 
	if (p->money64 < -2000000000)
 
		p->player_money = -2000000000;
 
	else if (p->money64 > 2000000000)
 
		p->player_money = 2000000000;
 
	else
 
		p->player_money = (int32)p->money64;
 
}
 

	
 
void GetNameOfOwner(PlayerID owner, TileIndex tile)
 
{
 
	SetDParam(2, owner);
 

	
 
	if (owner != OWNER_TOWN) {
 
		if (owner >= 8)
 
			SetDParam(0, STR_0150_SOMEONE);
 
		else {
 
			Player *p = GetPlayer(owner);
 
			const Player* p = GetPlayer(owner);
 
			SetDParam(0, p->name_1);
 
			SetDParam(1, p->name_2);
 
		}
 
	} else {
 
		Town *t = ClosestTownFromTile(tile, (uint)-1);
 
		SetDParam(0, STR_TOWN);
 
		SetDParam(1, t->index);
 
	}
 
}
 

	
 

	
 
bool CheckOwnership(PlayerID owner)
 
{
 
	assert(owner <= OWNER_WATER);
 

	
 
	if (owner == _current_player)
 
		return true;
 
	_error_message = STR_013B_OWNED_BY;
 
	GetNameOfOwner(owner, 0);
 
	return false;
 
}
 

	
 
bool CheckTileOwnership(TileIndex tile)
 
{
 
@@ -458,50 +458,49 @@ restart:;
 
		return;
 
	}
 
}
 

	
 
static Player *AllocatePlayer(void)
 
{
 
	Player *p;
 
	// Find a free slot
 
	FOR_ALL_PLAYERS(p) {
 
		if (!p->is_active) {
 
			int i = p->index;
 
			memset(p, 0, sizeof(Player));
 
			p->index = i;
 
			return p;
 
		}
 
	}
 
	return NULL;
 
}
 

	
 
Player *DoStartupNewPlayer(bool is_ai)
 
{
 
	Player *p;
 

	
 
	p = AllocatePlayer();
 
	if (p == NULL)
 
		return NULL;
 
	if (p == NULL) return NULL;
 

	
 
	// Make a color
 
	p->player_color = GeneratePlayerColor();
 
	_player_colors[p->index] = p->player_color;
 
	p->name_1 = STR_SV_UNNAMED;
 
	p->is_active = true;
 

	
 
	p->money64 = p->player_money = p->current_loan = 100000;
 

	
 
	p->is_ai = is_ai;
 
	p->ai.state = 5; /* AIS_WANT_NEW_ROUTE */
 
	p->share_owners[0] = p->share_owners[1] = p->share_owners[2] = p->share_owners[3] = OWNER_SPECTATOR;
 

	
 
	p->avail_railtypes = GetPlayerRailtypes(p->index);
 
	p->inaugurated_year = _cur_year;
 
	p->face = Random();
 

	
 
	/* Engine renewal settings */
 
	p->engine_renew_list = NULL;
 
	p->renew_keep_length = false;
 
	p->engine_renew = false;
 
	p->engine_renew_months = -6;
 
	p->engine_renew_money = 100000;
 

	
 
@@ -510,78 +509,81 @@ Player *DoStartupNewPlayer(bool is_ai)
 
	InvalidateWindow(WC_GRAPH_LEGEND, 0);
 
	InvalidateWindow(WC_TOOLBAR_MENU, 0);
 
	InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
	if (is_ai && (!_networking || _network_server) && _ai.enabled)
 
		AI_StartNewAI(p->index);
 

	
 
	return p;
 
}
 

	
 
void StartupPlayers(void)
 
{
 
	// The AI starts like in the setting with +2 month max
 
	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + RandomRange(60 * DAY_TICKS) + 1;
 
}
 

	
 
static void MaybeStartNewPlayer(void)
 
{
 
	uint n;
 
	Player *p;
 

	
 
	// count number of competitors
 
	n = 0;
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active && p->is_ai)
 
			n++;
 
		if (p->is_active && p->is_ai) n++;
 
	}
 

	
 
	// when there's a lot of computers in game, the probability that a new one starts is lower
 
	if (n < (uint)_opt.diff.max_no_competitors)
 
		if (n < (_network_server ? InteractiveRandomRange(_opt.diff.max_no_competitors + 2) : RandomRange(_opt.diff.max_no_competitors + 2)) )
 
			/* Send a command to all clients to start  up a new AI. Works fine for Multiplayer and Singleplayer */
 
	if (n < (uint)_opt.diff.max_no_competitors &&
 
			n < (_network_server ?
 
				InteractiveRandomRange(_opt.diff.max_no_competitors + 2) :
 
				RandomRange(_opt.diff.max_no_competitors + 2)
 
			)) {
 
		/* Send a command to all clients to start up a new AI.
 
		 * Works fine for Multiplayer and Singleplayer */
 
			DoCommandP(0, 1, 0, NULL, CMD_PLAYER_CTRL);
 
	}
 

	
 
	// The next AI starts like the difficulty setting said, with +2 month max
 
	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + 1;
 
	_next_competitor_start += _network_server ? InteractiveRandomRange(60 * DAY_TICKS) : RandomRange(60 * DAY_TICKS);
 
}
 

	
 
void InitializePlayers(void)
 
{
 
	int i;
 
	uint i;
 

	
 
	memset(_players, 0, sizeof(_players));
 
	for (i = 0; i != MAX_PLAYERS; i++)
 
		_players[i].index=i;
 
	for (i = 0; i != MAX_PLAYERS; i++) _players[i].index = i;
 
	_cur_player_tick_index = 0;
 
}
 

	
 
void OnTick_Players(void)
 
{
 
	Player *p;
 

	
 
	if (_game_mode == GM_EDITOR)
 
		return;
 
	if (_game_mode == GM_EDITOR) return;
 

	
 
	p = GetPlayer(_cur_player_tick_index);
 
	_cur_player_tick_index = (_cur_player_tick_index + 1) % MAX_PLAYERS;
 
	if (p->name_1 != 0) GenerateCompanyName(p);
 

	
 
	if (AI_AllowNewAI() && _game_mode != GM_MENU && !--_next_competitor_start)
 
		MaybeStartNewPlayer();
 
}
 

	
 
// index is the next parameter in _decode_parameters to set up
 
StringID GetPlayerNameString(PlayerID player, uint index)
 
{
 
	if (IS_HUMAN_PLAYER(player) && player < MAX_PLAYERS) {
 
		SetDParam(index, player+1);
 
		return STR_7002_PLAYER;
 
	}
 
	return STR_EMPTY;
 
}
 

	
 
extern void ShowPlayerFinances(int player);
 

	
 
void PlayersYearlyLoop(void)
 
{
 
	Player *p;
 
@@ -795,57 +797,62 @@ int32 CmdReplaceVehicle(TileIndex tile, 
 
 * - p1 = 2 - PlayerID of the that is getting deleted
 
 * - p1 = 3 - #1 p2 = (bit  0-15) - player to merge (p2 & 0xFFFF)
 
 *          - #2 p2 = (bit 16-31) - player to be merged into ((p2>>16)&0xFFFF)
 
 * @todo In the case of p1=0, create new player, the clientID of the new player is in parameter
 
 * p2. This parameter is passed in at function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
 
 * on the server itself. First of all this is unbelievably ugly; second of all, well,
 
 * it IS ugly! <b>Someone fix this up :)</b> So where to fix?@n
 
 * @arg - network_server.c:838 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)@n
 
 * @arg - network_client.c:536 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) from where the map has been received
 
 */
 
int32 CmdPlayerCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	if (flags & DC_EXEC) _current_player = OWNER_NONE;
 

	
 
	switch (p1) {
 
	case 0: { /* Create a new player */
 
		Player *p;
 
		PlayerID pid = p2;
 

	
 
		if (!(flags & DC_EXEC) || pid >= MAX_PLAYERS) return 0;
 

	
 
		p = DoStartupNewPlayer(false);
 

	
 
#ifdef ENABLE_NETWORK
 
		if (_networking && !_network_server && _local_player == OWNER_SPECTATOR)
 
		if (_networking && !_network_server && _local_player == OWNER_SPECTATOR) {
 
			/* In case we are a client joining a server... */
 
			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 
		}
 
#endif /* ENABLE_NETWORK */
 

	
 
		if (p != NULL) {
 
			if (_local_player == OWNER_SPECTATOR && (!_ai.network_client || _ai.network_playas == OWNER_SPECTATOR)) {
 
			if (_local_player == OWNER_SPECTATOR &&
 
					(!_ai.network_client || _ai.network_playas == OWNER_SPECTATOR)) {
 
				/* Check if we do not want to be a spectator in network */
 
				if (!_networking || (_network_server && !_network_dedicated) || _network_playas != OWNER_SPECTATOR || _ai.network_client) {
 
				if (!_networking ||
 
						(_network_server && !_network_dedicated) ||
 
						_network_playas != OWNER_SPECTATOR ||
 
						_ai.network_client) {
 
					if (_ai.network_client) {
 
						/* As ai-network-client, we have our own rulez (disable GUI and stuff) */
 
						_ai.network_playas = p->index;
 
						_local_player      = OWNER_SPECTATOR;
 
						if (_ai.network_playas != OWNER_SPECTATOR) {
 
							/* If we didn't join the game as a spectator, activate the AI */
 
							AI_StartNewAI(_ai.network_playas);
 
						}
 
					} else {
 
						_local_player = p->index;
 
					}
 
					MarkWholeScreenDirty();
 
				}
 
			} else if (p->index == _local_player) {
 
				DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_REPLACE_VEHICLE);
 
			}
 
#ifdef ENABLE_NETWORK
 
			if (_network_server) {
 
				/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at server-side
 
				 * in network_server.c:838, function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
 
				NetworkClientInfo *ci = &_network_client_info[pid];
 
				ci->client_playas = p->index + 1;
 
				NetworkUpdateClientInfo(ci->client_index);
 

	
 
@@ -961,50 +968,49 @@ StringID EndGameGetPerformanceTitleFromV
 
}
 

	
 
/* Return true if any cheat has been used, false otherwise */
 
static bool CheatHasBeenUsed(void)
 
{
 
	const Cheat* cht = (Cheat*) &_cheats;
 
	const Cheat* cht_last = &cht[sizeof(_cheats) / sizeof(Cheat)];
 

	
 
	for (; cht != cht_last; cht++) {
 
		if (cht->been_used)
 
			return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
/* Save the highscore for the player */
 
int8 SaveHighScoreValue(const Player *p)
 
{
 
	HighScore *hs = _highscore_table[_opt.diff_level];
 
	uint i;
 
	uint16 score = p->old_economy[0].performance_history;
 

	
 
	/* Exclude cheaters from the honour of being in the highscore table */
 
	if (CheatHasBeenUsed())
 
		return -1;
 
	if (CheatHasBeenUsed()) return -1;
 

	
 
	for (i = 0; i < lengthof(_highscore_table[0]); i++) {
 
		/* You are in the TOP5. Move all values one down and save us there */
 
		if (hs[i].score <= score) {
 
			// move all elements one down starting from the replaced one
 
			memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1));
 
			SetDParam(0, p->president_name_1);
 
			SetDParam(1, p->president_name_2);
 
			SetDParam(2, p->name_1);
 
			SetDParam(3, p->name_2);
 
			GetString(hs[i].company, STR_HIGHSCORE_NAME); // get manager/company name string
 
			hs[i].score = score;
 
			hs[i].title = EndGameGetPerformanceTitleFromValue(score);
 
			return i;
 
		}
 
	}
 

	
 
	return -1; // too bad; we did not make it into the top5
 
}
 

	
 
/* Sort all players given their performance */
 
static int CDECL HighScoreSorter(const void *a, const void *b)
 
{
 
	const Player *pa = *(const Player* const*)a;
 
@@ -1226,51 +1232,52 @@ static const SaveLoad _player_ai_build_r
 
	SLE_CONDVAR(AiBuildRec,spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec,spec_tile, SLE_UINT32, 6, SL_MAX_VERSION),
 
	SLE_CONDVAR(AiBuildRec,use_tile,  SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec,use_tile,  SLE_UINT32, 6, SL_MAX_VERSION),
 
	SLE_VAR(AiBuildRec,rand_rng,			SLE_UINT8),
 
	SLE_VAR(AiBuildRec,cur_building_rule,SLE_UINT8),
 
	SLE_VAR(AiBuildRec,unk6,					SLE_UINT8),
 
	SLE_VAR(AiBuildRec,unk7,					SLE_UINT8),
 
	SLE_VAR(AiBuildRec,buildcmd_a,		SLE_UINT8),
 
	SLE_VAR(AiBuildRec,buildcmd_b,		SLE_UINT8),
 
	SLE_VAR(AiBuildRec,direction,			SLE_UINT8),
 
	SLE_VAR(AiBuildRec,cargo,					SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static void SaveLoad_PLYR(Player* p)
 
{
 
	int i;
 

	
 
	SlObject(p, _player_desc);
 

	
 
	// Write AI?
 
	if (!IS_HUMAN_PLAYER(p->index)) {
 
		SlObject(&p->ai, _player_ai_desc);
 
		for (i = 0; i != p->ai.num_build_rec; i++)
 
		for (i = 0; i != p->ai.num_build_rec; i++) {
 
			SlObject(&p->ai.src + i, _player_ai_build_rec_desc);
 
	}
 
	}
 

	
 
	// Write economy
 
	SlObject(&p->cur_economy, _player_economy_desc);
 

	
 
	// Write old economy entries.
 
	for (i = 0; i < p->num_valid_stat_ent; i++) {
 
		SlObject(&p->old_economy[i], _player_economy_desc);
 
	}
 
}
 

	
 
static void Save_PLYR(void)
 
{
 
	Player *p;
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active) {
 
			SlSetArrayIndex(p->index);
 
			SlAutolength((AutolengthProc*)SaveLoad_PLYR, p);
 
		}
 
	}
 
}
 

	
 
static void Load_PLYR(void)
 
{
 
	int index;
rail_cmd.c
Show inline comments
 
@@ -704,49 +704,49 @@ int32 CmdBuildSingleSignal(TileIndex til
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**	Build many signals by dragging; AutoSignals
 
 * @param tile start tile of drag
 
 * @param p1  end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit  0)    - 0 = build, 1 = remove signals
 
 * - p2 = (bit  3)    - 0 = signals, 1 = semaphores
 
 * - p2 = (bit  4- 6) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit 24-31) - user defined signals_density
 
 */
 
static int32 CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	int32 ret, total_cost, signal_ctr;
 
	byte signals;
 
	bool error = true;
 
	TileIndex end_tile;
 

	
 
	int mode = p2 & 0x1;
 
	Track track = GB(p2, 4, 3);
 
	Trackdir trackdir = TrackToTrackdir(track);
 
	byte semaphores = (HASBIT(p2, 3)) ? 8 : 0;
 
	byte semaphores = (HASBIT(p2, 3) ? 8 : 0);
 
	byte signal_density = (p2 >> 24);
 

	
 
	if (p1 >= MapSize()) return CMD_ERROR;
 
	end_tile = p1;
 
	if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
 

	
 
	if (!IsTileType(tile, MP_RAILWAY)) return CMD_ERROR;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	/* for vertical/horizontal tracks, double the given signals density
 
	* since the original amount will be too dense (shorter tracks) */
 
	if (!IsDiagonalTrack(track))
 
		signal_density *= 2;
 

	
 
	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
 

	
 
	track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */
 

	
 
	// copy the signal-style of the first rail-piece if existing
 
	if (GetRailTileType(tile) == RAIL_TILE_SIGNALS && GetTrackBits(tile) != 0) { /* XXX: GetTrackBits check useless? */
 
		signals = _m[tile].m3 & SignalOnTrack(track);
 
		if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */
 

	
road_cmd.c
Show inline comments
 
@@ -720,115 +720,110 @@ static void DrawRoadBits(TileInfo* ti, R
 

	
 
	DrawGroundSprite(image);
 

	
 
	// Return if full detail is disabled, or we are zoomed fully out.
 
	if (!(_display_opt & DO_FULL_DETAIL) || _cur_dpi->zoom == 2) return;
 

	
 
	if (HasRoadWorks(ti->tile)) {
 
		// Road works
 
		DrawGroundSprite(road & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y);
 
		return;
 
	}
 

	
 
	// Draw extra details.
 
	for (drts = _road_display_table[GetGroundType(ti->tile)][road]; drts->image != 0; drts++) {
 
		int x = ti->x | drts->subcoord_x;
 
		int y = ti->y | drts->subcoord_y;
 
		byte z = ti->z;
 
		if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y);
 
		AddSortableSpriteToDraw(drts->image, x, y, 2, 2, 0x10, z);
 
	}
 
}
 

	
 
static void DrawTile_Road(TileInfo *ti)
 
{
 
	PalSpriteID image;
 

	
 
	switch (GetRoadTileType(ti->tile)) {
 
		case ROAD_TILE_NORMAL:
 
			DrawRoadBits(ti, GetRoadBits(ti->tile));
 
			break;
 

	
 
		case ROAD_TILE_CROSSING: {
 
			PalSpriteID image;
 

	
 
			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
 

	
 
			image = GetRailTypeInfo(GetRailTypeCrossing(ti->tile))->base_sprites.crossing;
 

	
 
			if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++;
 

	
 
			if (IsCrossingBarred(ti->tile)) image += 2;
 

	
 
			if (IsOnSnow(ti->tile)) {
 
				image += 8;
 
			} else {
 
				if (GetGroundType(ti->tile) == RGT_BARREN) image |= PALETTE_TO_BARE_LAND;
 
				if (HasPavement(ti->tile)) image += 4;
 
			}
 

	
 
			DrawGroundSprite(image);
 
			if (GetRailTypeCrossing(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
 
			break;
 
		}
 

	
 
		default:
 
		case ROAD_TILE_DEPOT: {
 
			uint32 ormod;
 
			PlayerID player;
 
			const DrawRoadSeqStruct* drss;
 

	
 
			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
 

	
 
			ormod = PALETTE_TO_GREY;	//was this a bug/problem?
 
			player = GetTileOwner(ti->tile);
 
			if (player < MAX_PLAYERS) ormod = PLAYER_SPRITE_COLOR(player);
 

	
 
			drss = _road_display_datas[GetRoadDepotDirection(ti->tile)];
 

	
 
			DrawGroundSprite(drss++->image);
 

	
 
			for (; drss->image != 0; drss++) {
 
				uint32 image = drss->image;
 

	
 
				if (image & PALETTE_MODIFIER_COLOR) image |= ormod;
 
				if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
 

	
 
				AddSortableSpriteToDraw(image, ti->x | drss->subcoord_x,
 
					ti->y | drss->subcoord_y, drss->width, drss->height, 0x14, ti->z
 
				);
 
			}
 
			break;
 
		}
 
	}
 
}
 

	
 
void DrawRoadDepotSprite(int x, int y, int image)
 
{
 
	uint32 ormod;
 
	const DrawRoadSeqStruct *dtss;
 

	
 
	ormod = PLAYER_SPRITE_COLOR(_local_player);
 

	
 
	dtss = _road_display_datas[image];
 
	const DrawRoadSeqStruct* dtss = _road_display_datas[image];
 
	uint32 ormod = PLAYER_SPRITE_COLOR(_local_player);
 

	
 
	x += 33;
 
	y += 17;
 

	
 
	DrawSprite(dtss++->image, x, y);
 

	
 
	for (; dtss->image != 0; dtss++) {
 
		Point pt = RemapCoords(dtss->subcoord_x, dtss->subcoord_y, 0);
 

	
 
		image = dtss->image;
 
		if (image & PALETTE_MODIFIER_COLOR) image |= ormod;
 

	
 
		DrawSprite(image, x + pt.x, y + pt.y);
 
	}
 
}
 

	
 
static uint GetSlopeZ_Road(const TileInfo* ti)
 
{
 
	Slope tileh = ti->tileh;
 
	uint z = ti->z;
 

	
 
	if (tileh == SLOPE_FLAT) return z;
 
	if (GetRoadTileType(ti->tile) == ROAD_TILE_NORMAL) {
 
		uint f = GetRoadFoundation(tileh, GetRoadBits(ti->tile));
road_map.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef ROAD_MAP_H
 
#define ROAD_MAP_H
 

	
 
#include "macros.h"
 
#include "rail.h"
 
#include "road.h"
 
#include "tile.h"
 

	
 

	
 
typedef enum RoadTileType {
 
	ROAD_TILE_NORMAL,
 
	ROAD_TILE_CROSSING,
 
	ROAD_TILE_DEPOT
 
} RoadTileType;
 

	
 
static inline RoadTileType GetRoadTileType(TileIndex t)
 
{
 
	assert(IsTileType(t, MP_STREET));
 
	return (RoadTileType)(GB(_m[t].m5, 4, 4));
 
	return (RoadTileType)GB(_m[t].m5, 4, 4);
 
}
 

	
 
static inline bool IsLevelCrossing(TileIndex t)
 
{
 
	return GetRoadTileType(t) == ROAD_TILE_CROSSING;
 
}
 

	
 
static inline bool IsLevelCrossingTile(TileIndex t)
 
{
 
	return IsTileType(t, MP_STREET) && IsLevelCrossing(t);
 
}
 

	
 
static inline RoadBits GetRoadBits(TileIndex t)
 
{
 
	assert(GetRoadTileType(t) == ROAD_TILE_NORMAL);
 
	return (RoadBits)(GB(_m[t].m5, 0, 4));
 
	return (RoadBits)GB(_m[t].m5, 0, 4);
 
}
 

	
 
static inline void SetRoadBits(TileIndex t, RoadBits r)
 
{
 
	assert(GetRoadTileType(t) == ROAD_TILE_NORMAL); // XXX incomplete
 
	SB(_m[t].m5, 0, 4, r);
 
}
 

	
 

	
 
static inline Axis GetCrossingRoadAxis(TileIndex t)
 
{
 
	assert(GetRoadTileType(t) == ROAD_TILE_CROSSING);
 
	return (Axis)GB(_m[t].m5, 3, 1);
 
}
 

	
 
static inline RoadBits GetCrossingRoadBits(TileIndex tile)
 
{
 
	return GetCrossingRoadAxis(tile) == AXIS_X ? ROAD_X : ROAD_Y;
 
}
 

	
 
static inline TrackBits GetCrossingRailBits(TileIndex tile)
 
{
 
	return GetCrossingRoadAxis(tile) == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X;
 
}
roadveh_gui.c
Show inline comments
 
@@ -394,52 +394,51 @@ static void RoadVehViewWndProc(Window *w
 
		case 11: /* clone vehicle */
 
			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneRoadVeh, CMD_CLONE_VEHICLE | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
 
			break;
 
		case 12: /* Refit vehicle */
 
			ShowRoadVehRefitWindow(v);
 
			break;
 
		}
 
	} break;
 

	
 
	case WE_RESIZE:
 
		w->viewport->width  += e->sizing.diff.x;
 
		w->viewport->height += e->sizing.diff.y;
 
		w->viewport->virtual_width  += e->sizing.diff.x;
 
		w->viewport->virtual_height += e->sizing.diff.y;
 
		break;
 

	
 
	case WE_DESTROY:
 
		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
 
		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
 
		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
 
		break;
 

	
 
	case WE_MOUSELOOP:
 
		{
 
			Vehicle *v;
 
			uint32 h;
 
			v = GetVehicle(w->window_number);
 
			h = IsRoadVehInDepotStopped(v) ? (1 << 7) | (1 << 8) : (1 << 11) | (1 << 12);
 
			const Vehicle* v = GetVehicle(w->window_number);
 
			uint32 h = IsRoadVehInDepotStopped(v) ? 1 << 7 | 1 << 8 : 1 << 11 | 1 << 12;
 

	
 
			if (h != w->hidden_state) {
 
				w->hidden_state = h;
 
				SetWindowDirty(w);
 
			}
 
		}
 
	}
 
}
 

	
 
static const Widget _roadveh_view_widgets[] = {
 
{ WWT_CLOSEBOX,   RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5, STR_018B_CLOSE_WINDOW },
 
{ WWT_CAPTION,    RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_9002, STR_018C_WINDOW_TITLE_DRAG_THIS },
 
{ WWT_STICKYBOX,  RESIZE_LR,    14, 238, 249,   0,  13, 0x0,      STR_STICKY_BUTTON },
 
{ WWT_IMGBTN,     RESIZE_RB,    14,   0, 231,  14, 103, 0x0,      STR_NULL },
 
{ WWT_6,          RESIZE_RB,    14,   2, 229,  16, 101, 0x0,      STR_NULL },
 
{ WWT_PUSHIMGBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,      STR_901C_CURRENT_VEHICLE_ACTION },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, 0x2AB,    STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, 0x2AE,    STR_901F_SEND_VEHICLE_TO_DEPOT },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, 0x2CB,    STR_9020_FORCE_VEHICLE_TO_TURN_AROUND },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, 0x2B2,    STR_901D_SHOW_VEHICLE_S_ORDERS },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, 0x2B3,    STR_9021_SHOW_ROAD_VEHICLE_DETAILS },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_ROADVEH,      STR_CLONE_ROAD_VEHICLE_INFO },
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, 0x2B4,    STR_REFIT_ROAD_VEHICLE_TO_CARRY },
 
{ WWT_PANEL,      RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,      STR_NULL },
 
{ WWT_RESIZEBOX,  RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,      STR_NULL },
 
@@ -986,52 +985,53 @@ static void PlayerRoadVehWndProc(Window 
 
			} else {
 
				/* Station Name -- (###) Road vehicles */
 
				SetDParam(0, station);
 
				SetDParam(1, w->vscroll.count);
 
				w->widget[1].unkA = STR_SCHEDULED_ROAD_VEHICLES;
 
			}
 
			DrawWindowWidgets(w);
 
		}
 
		/* draw sorting criteria string */
 
		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
 
		/* draw arrow pointing up/down for ascending/descending sorting */
 
		DoDrawString(vl->flags & VL_DESC ? DOWNARROW : UPARROW, 69, 15, 0x10);
 

	
 
		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
 
		for (i = w->vscroll.pos; i < max; ++i) {
 
			Vehicle *v = GetVehicle(vl->sort_list[i].index);
 
			StringID str;
 

	
 
			assert(v->type == VEH_Road && v->owner == owner);
 

	
 
			DrawRoadVehImage(v, x + 22, y + 6, INVALID_VEHICLE);
 
			DrawVehicleProfitButton(v, x, y + 13);
 

	
 
			SetDParam(0, v->unitnumber);
 
			if (IsRoadVehInDepot(v))
 
			if (IsRoadVehInDepot(v)) {
 
				str = STR_021F;
 
			else
 
			} else {
 
				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
			}
 
			DrawString(x, y + 2, str, 0);
 

	
 
			SetDParam(0, v->profit_this_year);
 
			SetDParam(1, v->profit_last_year);
 
			DrawString(x + 24, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 

	
 
			if (v->string_id != STR_SV_ROADVEH_NAME) {
 
				SetDParam(0, v->string_id);
 
				DrawString(x + 24, y, STR_01AB, 0);
 
			}
 

	
 
			y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 
		}
 
		}	break;
 

	
 
	case WE_CLICK: {
 
		switch (e->click.widget) {
 
		case 3: /* Flip sorting method ascending/descending */
 
			vl->flags ^= VL_DESC;
 
			vl->flags |= VL_RESORT;
 
			_sorting.roadveh.order = !!(vl->flags & VL_DESC);
 
			SetWindowDirty(w);
 
			break;
 

	
settings.c
Show inline comments
 
@@ -691,51 +691,53 @@ static void ini_load_settings(IniFile *i
 
				case SLE_VAR_STRB:
 
				case SLE_VAR_STRQ:
 
					if (p != NULL) ttd_strlcpy((char*)ptr, p, sld->length);
 
					break;
 
				case SLE_VAR_CHAR: *(char*)ptr = *(char*)p; break;
 
				default: NOT_REACHED(); break;
 
			}
 
			break;
 

	
 
		case SDT_INTLIST: {
 
			if (!load_intlist(p, ptr, sld->length, GetVarMemType(sld->conv)))
 
				ShowInfoF("ini: error in array '%s'", sdb->name);
 
			break;
 
		}
 
		default: NOT_REACHED(); break;
 
		}
 
	}
 
}
 

	
 
/** Save the values of settings to the inifile.
 
 * @param ini pointer to IniFile structure
 
 * @param sd read-only SettingDesc structure which contains the unmodified,
 
 *        loaded values of the configuration file and various information about it
 
 * @param grpname holds the name of the group (eg. [network]) where these will be saved
 
 * The function works as follows: for each item in the SettingDesc structure we have
 
 * a look if the value has changed since we started the game (the original values
 
 * are reloaded when saving). If settings indeed have changed, we get these and save them.*/
 
 * The function works as follows: for each item in the SettingDesc structure we
 
 * have a look if the value has changed since we started the game (the original
 
 * values are reloaded when saving). If settings indeed have changed, we get
 
 * these and save them.
 
 */
 
static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
 
{
 
	IniGroup *group_def = NULL, *group;
 
	IniItem *item;
 
	char buf[512];
 
	const char *s;
 
	void *ptr;
 

	
 
	for (; sd->save.cmd != SL_END; sd++) {
 
		const SettingDescBase *sdb = &sd->desc;
 
		const SaveLoad        *sld = &sd->save;
 

	
 
		/* If the setting is not saved to the configuration
 
		 * file, just continue with the next setting */
 
		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
 
		if (sld->conv & SLF_CONFIG_NO) continue;
 

	
 
		// XXX - wtf is this?? (group override?)
 
		s = strchr(sdb->name, '.');
 
		if (s != NULL) {
 
			group = ini_getgroup(ini, sdb->name, s - sdb->name);
 
			s++;
 
		} else {
 
			if (group_def == NULL) group_def = ini_getgroup(ini, grpname, -1);
 
@@ -873,70 +875,70 @@ static void ini_save_setting_list(IniFil
 
		if (entry == NULL || *entry == '\0') continue;
 

	
 
		if (first) { // add first item to the head of the group
 
			item = ini_item_alloc(group, entry, strlen(entry));
 
			item->value = item->name;
 
			group->item = item;
 
			first = false;
 
		} else { // all other items are attached to the previous one
 
			item->next = ini_item_alloc(group, entry, strlen(entry));
 
			item = item->next;
 
			item->value = item->name;
 
		}
 
	}
 
}
 

	
 
//***************************
 
// OTTD specific INI stuff
 
//***************************
 

	
 
/** Settings-macro usage:
 
 * The list might look daunting at first, but is in general easy to understand.
 
 * We have two types of list:
 
 * 1. SDTG_something
 
 * 2. SDT_something
 
 * The 'G' stands for global, so this is the one you will use for a SettingDescGlobVarList
 
 * section meaning global variables. The other uses a Base/Offset and runtime variable
 
 * selection mechanism, known from the saveload convention (it also has global so it
 
 * should not be hard).
 
 * Of each type there are again two versions, the normal one and one prefixed with 'COND'.
 
 * COND means that the setting is only valid in certain savegame versions (since patches
 
 * are saved to the savegame, this bookkeeping is necessary.
 
 * The 'G' stands for global, so this is the one you will use for a
 
 * SettingDescGlobVarList section meaning global variables. The other uses a
 
 * Base/Offset and runtime variable selection mechanism, known from the saveload * convention (it also has global so it should not be hard).
 
 * Of each type there are again two versions, the normal one and one prefixed
 
 * with 'COND'.
 
 * COND means that the setting is only valid in certain savegame versions
 
 * (since patches are saved to the savegame, this bookkeeping is necessary.
 
 * Now there are a lot of types. Easy ones are:
 
 * - VAR:  any number type, 'type' field specifies what number. eg int8 or uint32
 
 * - BOOL: a boolean number type
 
 * - STR:  a string or character. 'type' field specifies what string. Normal, string, or quoted
 
 * A bit more difficult to use are MMANY (meaning ManyOfMany) and OMANY (OneOfMany)
 
 * These are actually normal numbers, only bitmasked. In MMANY several bits can be
 
 * set, in the other only one.
 
 * These are actually normal numbers, only bitmasked. In MMANY several bits can
 
 * be set, in the other only one.
 
 * The most complex type is INTLIST. This is basically an array of numbers. If
 
 * the intlist is only valid in certain savegame versions because for example
 
 * it has grown in size its length cannot be automatically be calculated so
 
 * use SDT(G)_CONDLISTO() meaning Old.
 
 * If nothing fits you, you can use the GENERAL macros, but it exposes the internal
 
 * structure somewhat so it needs a little looking. There are _NULL() macros as
 
 * well, these fill up space so you can add more patches there (in place) and you
 
 * DON'T have to increase the savegame version. */
 
 * If nothing fits you, you can use the GENERAL macros, but it exposes the
 
 * internal structure somewhat so it needs a little looking. There are _NULL()
 
 * macros as well, these fill up space so you can add more patches there (in
 
 * place) and you DON'T have to increase the savegame version. */
 

	
 
#define NSD_GENERAL(name, def, cmd, guiflags, min, max, many, str, proc)\
 
	{name, (const void*)(def), cmd, guiflags, min, max, many, str, proc}
 

	
 
/* Macros for various objects to go in the configuration file.
 
 * This section is for global variables */
 
#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, full, str, proc, from, to)\
 
{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, full, str, proc), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
 

	
 
#define SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, str, proc, from, to)\
 
	SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, NULL, str, proc, from, to)
 
#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, str, proc)\
 
	SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, str, proc, 0, SL_MAX_VERSION)
 

	
 
#define SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, from, to)\
 
	SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_UINT8, flags, guiflags, var, 0, def, 0, 1, NULL, str, proc, from, to)
 
#define SDTG_BOOL(name, flags, guiflags, var, def, str, proc)\
 
	SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, 0, SL_MAX_VERSION)
 

	
 
#define SDTG_CONDLIST(name, type, length, flags, guiflags, var, def, str, proc, from, to)\
 
	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, NULL, str, proc, from, to)
 
#define SDTG_LIST(name, type, flags, guiflags, var, def, str, proc)\
 
	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, lengthof(var), def, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
 

	
 
@@ -1197,53 +1199,53 @@ static const SettingDesc _gameopt_settin
 
	 * town attitude towards demolishing. Needs special handling because some dimwit thought
 
	 * it funny to have the GameDifficulty struct be an array while it is a struct of
 
	 * same-sized members
 
	 * XXX - To save file-space and since values are never bigger than about 10? only
 
	 * save the first 16 bits in the savegame. Question is why the values are still int32
 
	 * and why not byte for example? */
 
	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 17, 0, 0, 0, NULL, STR_NULL, NULL, 0, 3),
 
	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 18, 0, 0, 0, NULL, STR_NULL, NULL, 4, SL_MAX_VERSION),
 
	    SDT_VAR(GameOptions, diff_level,SLE_UINT8, 0, 0, 9,0, 9, STR_NULL, NULL),
 
	  SDT_OMANY(GameOptions, currency,  SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SEK|custom", STR_NULL, NULL),
 
	  SDT_OMANY(GameOptions, units,     SLE_UINT8, N, 0, 1,   2, "imperial|metric|si", STR_NULL, NULL),
 
	  SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0,  18, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish", STR_NULL, NULL),
 
	  SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0,   3, "normal|hilly|desert|candy", STR_NULL, NULL),
 
	    SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 1,0,56, STR_NULL, NULL),
 
	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8, 0, 22,             N, 0, 0, 0, "", STR_NULL, NULL),
 
	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8,23, SL_MAX_VERSION, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL),
 
	  SDT_OMANY(GameOptions, road_side, SLE_UINT8, 0, 0, 1,   1, "left|right", STR_NULL, NULL),
 
	    SDT_END()
 
};
 

	
 
/* Some patches do not need to be synchronised when playing in multiplayer.
 
 * These include for example the GUI settings and will not be saved with the
 
 * savegame.
 
 * It is also a bit tricky since you would think that service_interval
 
 * for example doesn't need to be synched. Every client assigns the service_interval
 
 * value to the v->service_interval, meaning that every client assigns his value. If
 
 * the setting was player-based, that would mean that vehicles could decide on
 
 * different moments that they are heading back to a service depot, causing desyncs
 
 * on a massive scale. */
 
 * for example doesn't need to be synched. Every client assigns the
 
 * service_interval value to the v->service_interval, meaning that every client
 
 * assigns his value. If the setting was player-based, that would mean that
 
 * vehicles could decide on different moments that they are heading back to a
 
 * service depot, causing desyncs on a massive scale. */
 
const SettingDesc _patch_settings[] = {
 
	/***************************************************************************/
 
	/* User-interface section of the GUI-configure patches window */
 
	SDT_BOOL(Patches, vehicle_speed,                 S, 0,  true,    STR_CONFIG_PATCHES_VEHICLESPEED,          NULL),
 
	SDT_BOOL(Patches, status_long_date,              S, 0,  true,    STR_CONFIG_PATCHES_LONGDATE,              NULL),
 
	SDT_BOOL(Patches, show_finances,                 S, 0,  true,    STR_CONFIG_PATCHES_SHOWFINANCES,          NULL),
 
	SDT_BOOL(Patches, autoscroll,                    S, 0, false,    STR_CONFIG_PATCHES_AUTOSCROLL,            NULL),
 
	SDT_BOOL(Patches, reverse_scroll,                S, 0, false,    STR_CONFIG_PATCHES_REVERSE_SCROLLING,     NULL),
 
	 SDT_VAR(Patches, errmsg_duration,    SLE_UINT8, S, 0,  5, 0,20, STR_CONFIG_PATCHES_ERRMSG_DURATION,       NULL),
 
	 SDT_VAR(Patches, toolbar_pos,        SLE_UINT8, S,MS,  0, 0, 2, STR_CONFIG_PATCHES_TOOLBAR_POS,           v_PositionMainToolbar),
 
	 SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1,32, STR_CONFIG_PATCHES_SNAP_RADIUS,           NULL),
 
	SDT_BOOL(Patches, invisible_trees,               S, 0, false,    STR_CONFIG_PATCHES_INVISIBLE_TREES,       InvisibleTreesActive),
 
	SDT_BOOL(Patches, population_in_label,           S, 0,  true,    STR_CONFIG_PATCHES_POPULATION_IN_LABEL,   PopulationInLabelActive),
 
	 SDT_VAR(Patches, map_x,              SLE_UINT8, S, 0,  8, 6,11, STR_CONFIG_PATCHES_MAP_X,                 NULL),
 
	 SDT_VAR(Patches, map_y,              SLE_UINT8, S, 0,  8, 6,11, STR_CONFIG_PATCHES_MAP_Y,                 NULL),
 
	SDT_BOOL(Patches, link_terraform_toolbar,        S, 0, false,    STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL),
 

	
 
	/***************************************************************************/
 
	/* Construction section of the GUI-configure patches window */
 
	SDT_BOOL(Patches, build_on_slopes,               0, 0,  true,    STR_CONFIG_PATCHES_BUILDONSLOPES,       NULL),
 
	SDT_BOOL(Patches, extra_dynamite,                0, 0, false,    STR_CONFIG_PATCHES_EXTRADYNAMITE,       NULL),
 
	SDT_BOOL(Patches, longbridges,                   0, 0,  true,    STR_CONFIG_PATCHES_LONGBRIDGES,         NULL),
 
	SDT_BOOL(Patches, signal_side,                   N, 0,  true,    STR_CONFIG_PATCHES_SIGNALSIDE,          NULL),
 
	SDT_BOOL(Patches, always_small_airport,          0, 0, false,    STR_CONFIG_PATCHES_SMALL_AIRPORTS,      NULL),
 
@@ -1327,50 +1329,50 @@ const SettingDesc _patch_settings[] = {
 
	 SDT_VAR(Patches, dist_local_authority,SLE_UINT8, 0, 0, 20, 5,  60, STR_NULL, NULL),
 
	 SDT_VAR(Patches, wait_oneway_signal,  SLE_UINT8, 0, 0, 15, 2, 100, STR_NULL, NULL),
 
	 SDT_VAR(Patches, wait_twoway_signal,  SLE_UINT8, 0, 0, 41, 2, 100, STR_NULL, NULL),
 

	
 
	/***************************************************************************/
 
	/* New Pathfinding patch settings */
 
	SDT_VAR(Patches, pf_maxlength,      SLE_UINT16, 0, 0, 4096, 64, 65535, STR_NULL, NULL),
 
	SDT_VAR(Patches, pf_maxdepth,        SLE_UINT8, 0, 0,   48,  4,   255, STR_NULL, NULL),
 
	/* The maximum number of nodes to search */
 
	SDT_VAR(Patches, npf_max_search_nodes,SLE_UINT, 0, 0,10000,500,100000, STR_NULL, NULL),
 

	
 
	/* When a red signal is encountered, a small detour can be made around
 
	* it. This specifically occurs when a track is doubled, in which case
 
	* the detour is typically 2 tiles. It is also often used at station
 
	* entrances, when there is a choice of multiple platforms. If we take
 
	* a typical 4 platform station, the detour is 4 tiles. To properly
 
	* support larger stations we increase this value.
 
	* We want to prevent that trains that want to leave at one side of a
 
	* station, leave through the other side, turn around, enter the
 
	* station on another platform and exit the station on the right side
 
	* again, just because the sign at the right side was red. If we take
 
	* a typical 5 length station, this detour is 10 or 11 tiles (not
 
	* sure), so we set the default penalty at 10 (the station tile
 
	* penalty will further prevent this.
 
	* We give presignal exits (and combo's) a different (larger) penalty, because we really
 
	* don't want trains waiting in front of a presignal exit. */
 
	 * We give presignal exits (and combo's) a different (larger) penalty, because
 
	 * we really don't want trains waiting in front of a presignal exit. */
 
	SDT_VAR(Patches, npf_rail_firstred_penalty,     SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, STR_NULL, NULL),
 
	SDT_VAR(Patches, npf_rail_firstred_exit_penalty,SLE_UINT, 0, 0, (100 * NPF_TILE_LENGTH),0, 100000, STR_NULL, NULL),
 
	/* This penalty is for when the last signal before the target is red.
 
	 * This is useful for train stations, where there are multiple
 
	 * platforms to choose from, which lie in different signal blocks.
 
	 * Every target in a occupied signal block (ie an occupied platform)
 
	 * will get this penalty. */
 
	SDT_VAR(Patches, npf_rail_lastred_penalty, SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, STR_NULL, NULL),
 
	/* When a train plans a route over a station tile, this penalty is
 
	 * applied. We want that trains plan a route around a typical, 4x5
 
	 * station, which means two tiles to the right, and two tiles back to
 
	 * the left around it, or 5 tiles of station through it. If we assign
 
	 * a penalty of 1 tile for every station tile passed, the route will
 
	 * be around it. */
 
	SDT_VAR(Patches, npf_rail_station_penalty, SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, STR_NULL, NULL),
 
	SDT_VAR(Patches, npf_rail_slope_penalty,   SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, STR_NULL, NULL),
 
	/* This penalty is applied when a train makes a turn. Its value of 1 makes
 
	 * sure that it has a minimal impact on the pathfinding, only when two
 
	 * paths have equal length it will make a difference */
 
	SDT_VAR(Patches, npf_rail_curve_penalty,        SLE_UINT, 0, 0, 1,                      0, 100000, STR_NULL, NULL),
 
	/* Ths penalty is applied when a vehicle reverses inside a depot (doesn't
 
	 * apply to ships, as they can just come out the other end). XXX: Is this a
 
	 * good value? */
 
	SDT_VAR(Patches, npf_rail_depot_reverse_penalty,SLE_UINT, 0, 0, (NPF_TILE_LENGTH * 50), 0, 100000, STR_NULL, NULL),
ship_gui.c
Show inline comments
 
@@ -543,52 +543,51 @@ static void ShipViewWndProc(Window *w, W
 
					ShowShipDetailsWindow(v);
 
					break;
 
				case 11: {
 
					/* clone vehicle */
 
					DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneShip, CMD_CLONE_VEHICLE | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
 
				} break;
 
			}
 
		} break;
 

	
 
		case WE_RESIZE:
 
			w->viewport->width  += e->sizing.diff.x;
 
			w->viewport->height += e->sizing.diff.y;
 
			w->viewport->virtual_width  += e->sizing.diff.x;
 
			w->viewport->virtual_height += e->sizing.diff.y;
 
			break;
 

	
 
		case WE_DESTROY:
 
			DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
 
			DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
 
			DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
 
			break;
 

	
 
		case WE_MOUSELOOP:
 
		{
 
			Vehicle *v;
 
			uint32 h;
 
			v = GetVehicle(w->window_number);
 
			h = IsShipInDepot(v) ? 1 << 7 : 1 << 11;
 
			const Vehicle* v = GetVehicle(w->window_number);
 
			uint32 h = IsShipInDepot(v) ? 1 << 7 : 1 << 11;
 

	
 
			if (h != w->hidden_state) {
 
				w->hidden_state = h;
 
				SetWindowDirty(w);
 
			}
 
		}
 
	}
 
}
 

	
 
static const Widget _ship_view_widgets[] = {
 
{ WWT_CLOSEBOX,   RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{ WWT_CAPTION,    RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_980F, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{ WWT_STICKYBOX,  RESIZE_LR,    14, 238, 249,   0,  13, 0x0,      STR_STICKY_BUTTON},
 
{ WWT_IMGBTN,     RESIZE_RB,    14,   0, 231,  14, 103, 0x0,      STR_NULL},
 
{ WWT_6,          RESIZE_RB,    14,   2, 229,  16, 101, 0x0,      STR_NULL},
 
{ WWT_PUSHIMGBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,      STR_9827_CURRENT_SHIP_ACTION_CLICK},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, 0x2AB,    STR_9829_CENTER_MAIN_VIEW_ON_SHIP},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, 0x2B0,    STR_982A_SEND_SHIP_TO_DEPOT},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, 0x2B4,    STR_983A_REFIT_CARGO_SHIP_TO_CARRY},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, 0x2B2,    STR_9828_SHOW_SHIP_S_ORDERS},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, 0x2B3,    STR_982B_SHOW_SHIP_DETAILS},
 
{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_SHIP,      STR_CLONE_SHIP_INFO},
 
{ WWT_PANEL,      RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,      STR_NULL },
 
{ WWT_RESIZEBOX,  RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,      STR_NULL },
 
{ WIDGETS_END }
 
@@ -991,52 +990,53 @@ static void PlayerShipsWndProc(Window *w
 
			} else {
 
				/* Station Name -- (###) Trains */
 
				SetDParam(0, station);
 
				SetDParam(1, w->vscroll.count);
 
				w->widget[1].unkA = STR_SCHEDULED_SHIPS;
 
			}
 
			DrawWindowWidgets(w);
 
		}
 
		/* draw sorting criteria string */
 
		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
 
		/* draw arrow pointing up/down for ascending/descending sorting */
 
		DoDrawString(vl->flags & VL_DESC ? DOWNARROW : UPARROW, 69, 15, 0x10);
 

	
 
		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
 
		for (i = w->vscroll.pos; i < max; ++i) {
 
			Vehicle *v = GetVehicle(vl->sort_list[i].index);
 
			StringID str;
 

	
 
			assert(v->type == VEH_Ship);
 

	
 
			DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE);
 
			DrawVehicleProfitButton(v, x, y + 13);
 

	
 
			SetDParam(0, v->unitnumber);
 
			if (IsShipInDepot(v))
 
			if (IsShipInDepot(v)) {
 
				str = STR_021F;
 
			else
 
			} else {
 
				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
			}
 
			DrawString(x, y + 2, str, 0);
 

	
 
			SetDParam(0, v->profit_this_year);
 
			SetDParam(1, v->profit_last_year);
 
			DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 

	
 
			if (v->string_id != STR_SV_SHIP_NAME) {
 
				SetDParam(0, v->string_id);
 
				DrawString(x + 12, y, STR_01AB, 0);
 
			}
 

	
 
			DrawSmallOrderList(v, x + 138, y);
 

	
 
			y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
 
		}
 
		}	break;
 

	
 
	case WE_CLICK: {
 
		switch (e->click.widget) {
 
		case 3: /* Flip sorting method ascending/descending */
 
			vl->flags ^= VL_DESC;
 
			vl->flags |= VL_RESORT;
 
			_sorting.ship.order = !!(vl->flags & VL_DESC);
 
			SetWindowDirty(w);
smallmap_gui.c
Show inline comments
 
@@ -917,88 +917,86 @@ void ShowSmallMap(void)
 

	
 
/* Extra ViewPort Window Stuff */
 
static const Widget _extra_view_port_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,	STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   287,     0,    13, STR_EXTRA_VIEW_PORT_TITLE,				STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{  WWT_STICKYBOX,     RESIZE_LR,    14,   288,   299,     0,    13, 0x0,       STR_STICKY_BUTTON},
 
{      WWT_PANEL,     RESIZE_RB,    14,     0,   299,    14,   233, 0x0,				STR_NULL},
 
{          WWT_6,     RESIZE_RB,    14,     2,   297,    16,   231, 0x0,				STR_NULL},
 
{      WWT_PANEL,     RESIZE_TB,    14,     0,    21,   234,   255, 0x2DF,			STR_017F_ZOOM_THE_VIEW_IN},
 
{      WWT_PANEL,     RESIZE_TB,    14,    22,    43,   234,   255, 0x2E0,			STR_0180_ZOOM_THE_VIEW_OUT},
 
{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,    44,   171,   234,   255, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW,STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT},
 
{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   172,   298,   234,   255, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN,STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT},
 
{      WWT_PANEL,    RESIZE_RTB,    14,   299,   299,   234,   255, 0x0,				STR_NULL},
 
{      WWT_PANEL,    RESIZE_RTB,    14,     0,   287,   256,   267, 0x0,				STR_NULL},
 
{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   288,   299,   256,   267, 0x0,				STR_RESIZE_BUTTON},
 
{   WIDGETS_END},
 
};
 

	
 
static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
 
{
 
	switch (e->event) {
 
	case WE_CREATE: /* Disable zoom in button */
 
		w->disabled_state = (1 << 5);
 
		break;
 

	
 
	case WE_PAINT:
 
		// set the number in the title bar
 
		SetDParam(0, (w->window_number+1));
 
		SetDParam(0, w->window_number + 1);
 

	
 
		DrawWindowWidgets(w);
 
		DrawWindowViewport(w);
 
		break;
 

	
 
	case WE_CLICK: {
 
	case WE_CLICK:
 
		switch (e->click.widget) {
 
		case 5: /* zoom in */
 
			DoZoomInOutWindow(ZOOM_IN, w);
 
			break;
 
		case 6: /* zoom out */
 
			DoZoomInOutWindow(ZOOM_OUT, w);
 
			break;
 
			case 5: DoZoomInOutWindow(ZOOM_IN,  w); break;
 
			case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
 

	
 
		case 7: { /* location button (move main view to same spot as this view) 'Paste Location' */
 
			Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
 
			int x = WP(w, vp_d).scrollpos_x; // Where is the main looking at
 
			int y = WP(w, vp_d).scrollpos_y;
 

	
 
			// set this view to same location. Based on the center, adjusting for zoom
 
			WP(w2, vp_d).scrollpos_x =  x - (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
 
			WP(w2, vp_d).scrollpos_y =  y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
 
		} break;
 

	
 
		case 8: { /* inverse location button (move this view to same spot as main view) 'Copy Location' */
 
			const Window* w2 = FindWindowById(WC_MAIN_WINDOW, 0);
 
			int x = WP(w2, const vp_d).scrollpos_x;
 
			int y = WP(w2, const vp_d).scrollpos_y;
 

	
 
			WP(w, vp_d).scrollpos_x =  x + (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
 
			WP(w, vp_d).scrollpos_y =  y + (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
 
		} break;
 
		}
 
	} break;
 
		break;
 

	
 
	case WE_RESIZE:
 
		w->viewport->width  += e->sizing.diff.x;
 
		w->viewport->height += e->sizing.diff.y;
 

	
 
		w->viewport->virtual_width  += e->sizing.diff.x;
 
		w->viewport->virtual_height += e->sizing.diff.y;
 
		break;
 
	}
 
}
 

	
 
static const WindowDesc _extra_view_port_desc = {
 
	-1,-1, 300, 268,
 
	WC_EXTRA_VIEW_PORT,0,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 
	_extra_view_port_widgets,
 
	ExtraViewPortWndProc
 
};
 

	
 
void ShowExtraViewPortWindow(void)
 
{
 
	Window *w, *v;
 
	int i = 0;
 

	
 
	// find next free window number for extra viewport
 
	while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++;
 

	
 
	w = AllocateWindowDescFront(&_extra_view_port_desc, i);
 
	if (w != NULL) {
station_cmd.c
Show inline comments
 
@@ -1893,49 +1893,49 @@ int32 CmdBuildDock(TileIndex tile, uint3
 
	switch (GetTileSlope(tile, NULL)) {
 
		case SLOPE_SW: direction = DIAGDIR_NE; break;
 
		case SLOPE_SE: direction = DIAGDIR_NW; break;
 
		case SLOPE_NW: direction = DIAGDIR_SE; break;
 
		case SLOPE_NE: direction = DIAGDIR_SW; break;
 
		default: return_cmd_error(STR_304B_SITE_UNSUITABLE);
 
	}
 

	
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 

	
 
	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(cost)) return CMD_ERROR;
 

	
 
	tile_cur = tile + TileOffsByDir(direction);
 

	
 
	if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
 

	
 
	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
 
		return_cmd_error(STR_304B_SITE_UNSUITABLE);
 
	}
 

	
 
	cost = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(cost)) return CMD_ERROR;
 

	
 
	tile_cur = tile_cur + TileOffsByDir(direction);
 
	tile_cur += TileOffsByDir(direction);
 
	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
 
		return_cmd_error(STR_304B_SITE_UNSUITABLE);
 
	}
 

	
 
	/* middle */
 
	st = GetStationAround(
 
		tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
 
		_dock_w_chk[direction], _dock_h_chk[direction], -1);
 
	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
 

	
 
	/* Find a station close to us */
 
	if (st == NULL) {
 
		st = GetClosestStationFromTile(tile, 8, _current_player);
 
		if (st!=NULL && st->facilities) st = NULL;
 
	}
 

	
 
	if (st != NULL) {
 
		if (st->owner != OWNER_NONE && st->owner != _current_player)
 
			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
 

	
 
		if (!CheckStationSpreadOut(st, tile, 1, 1)) return CMD_ERROR;
 

	
 
		if (st->dock_tile != 0) return_cmd_error(STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK);
 
	} else {
stdafx.h
Show inline comments
 
@@ -48,53 +48,51 @@
 
# ifdef AMIGA
 
#  undef AMIGA
 
# endif
 
# ifdef amiga
 
#  undef amiga
 
# endif
 
#endif /* __MORPHOS__ */
 

	
 
#ifdef __APPLE__
 
# include "os/macosx/osx_stdafx.h"
 
// make endian swapping use Apple's macros to increase speed
 
# define BSWAP32(x) Endian32_Swap(x)
 
# define BSWAP16(x) Endian16_Swap(x)
 
#else
 
# define BSWAP32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) << 8) & 0xFF0000) | (((x) << 24) & 0xFF000000))
 
# define BSWAP16(x) ((x) >> 8 | (x) << 8)
 
#endif /* __APPLE__ */
 

	
 
// by default we use [] var arrays
 
#define VARARRAY_SIZE
 

	
 

	
 
// Stuff for GCC
 
#if defined(__GNUC__)
 
# define NORETURN              __attribute((noreturn))
 
# define NORETURN __attribute__ ((noreturn))
 
# define FORCEINLINE inline
 
# define CDECL
 
//#include <alloca.h>
 
//#include <malloc.h>
 
# define __int64 long long
 
# define NOT_REACHED() assert(0)
 
# define GCC_PACK __attribute__((packed))
 

	
 
# if (__GNUC__ == 2)
 
#  undef VARARRAY_SIZE
 
#  define VARARRAY_SIZE 0
 
# endif
 
#endif /* __GNUC__ */
 

	
 
#if defined(__WATCOMC__)
 
# define NORETURN
 
# define FORCEINLINE inline
 
# define CDECL
 
# define NOT_REACHED() assert(0)
 
# define GCC_PACK
 
# include <malloc.h>
 
#endif /* __WATCOMC__ */
 

	
 
#if defined(__MINGW32__) || defined(__CYGWIN__)
 
# include <malloc.h> // alloca()
 
#endif
 

	
 
// Stuff for MSVC
town_cmd.c
Show inline comments
 
@@ -1042,147 +1042,148 @@ Town *CreateRandomTown(uint attempts, ui
 
		// Check not too close to a town
 
		if (IsCloseToTown(tile, 20)) continue;
 

	
 
		// Get a unique name for the town.
 
		if (!CreateTownName(&townnameparts)) break;
 

	
 
		// Allocate a town struct
 
		t = AllocateTown();
 
		if (t == NULL) break;
 

	
 
		DoCreateTown(t, tile, townnameparts, size_mode);
 
		return t;
 
	} while (--attempts);
 
	return NULL;
 
}
 

	
 
static const byte _num_initial_towns[3] = {11, 23, 46};
 

	
 
bool GenerateTowns(void)
 
{
 
	uint num = 0;
 
	uint n = ScaleByMapSize(_num_initial_towns[_opt.diff.number_towns] + (Random() & 7));
 

	
 
	do {
 
		if (CreateRandomTown(20, 0) != NULL) 	//try 20 times to create a random-sized town for the first loop.
 
			num++;
 
		// try 20 times to create a random-sized town for the first loop.
 
		if (CreateRandomTown(20, 0) != NULL) num++;
 
	} while (--n);
 

	
 
	// give it a last try, but now more aggressive
 
	if (num == 0 && CreateRandomTown(10000, 0) == NULL) {
 
		Town *t;
 
		FOR_ALL_TOWNS(t) { if (IsValidTown(t)) {num = 1; break;}}
 
		const Town* t;
 

	
 
		FOR_ALL_TOWNS(t) if (IsValidTown(t)) return true;
 

	
 
		//XXX can we handle that more gracefully?
 
		if (num == 0 && _game_mode != GM_EDITOR) error("Could not generate any town");
 
		if (num == 0 && _game_mode != GM_EDITOR) {
 
			error("Could not generate any town");
 
		}
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static bool CheckBuildHouseMode(TileIndex tile, Slope tileh, int mode)
 
{
 
	int b;
 
	Slope slope;
 

	
 
	static const byte _masks[8] = {
 
		0xC,0x3,0x9,0x6,
 
		0x3,0xC,0x6,0x9,
 
	};
 

	
 
	slope = GetTileSlope(tile, NULL);
 
	if (IsSteepSlope(slope)) return false;
 

	
 
	b = 0;
 
	if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
 
	if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b;
 
	if (b)
 
		return false;
 

	
 
	return !CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
 
}
 

	
 
int GetTownRadiusGroup(const Town *t, TileIndex tile)
 

	
 
uint GetTownRadiusGroup(const Town* t, TileIndex tile)
 
{
 
	uint dist;
 
	int i,smallest;
 
	uint dist = DistanceSquare(tile, t->xy);
 
	uint smallest;
 
	uint i;
 

	
 
	dist = DistanceSquare(tile, t->xy);
 
	if (t->fund_buildings_months && dist <= 25)
 
		return 4;
 
	if (t->fund_buildings_months && dist <= 25) return 4;
 

	
 
	smallest = 0;
 
	for (i = 0; i != lengthof(t->radius); i++) {
 
		if (dist < t->radius[i])
 
			smallest = i;
 
		if (dist < t->radius[i]) smallest = i;
 
	}
 

	
 
	return smallest;
 
}
 

	
 
static bool CheckFree2x2Area(TileIndex tile)
 
{
 
	int i;
 

	
 
	static const TileIndexDiffC _tile_add[] = {
 
		{0    , 0    },
 
		{0 - 0, 1 - 0},
 
		{1 - 0, 0 - 1},
 
		{1 - 1, 1 - 0}
 
	};
 

	
 
	for (i = 0; i != 4; i++) {
 
		tile += ToTileIndexDiff(_tile_add[i]);
 

	
 
		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
 

	
 
		if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
 
			return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static void DoBuildTownHouse(Town *t, TileIndex tile)
 
{
 
	int i;
 
	uint bitmask;
 
	int house;
 
	Slope slope;
 
	uint z;
 
	uint oneof = 0;
 

	
 
	// Above snow?
 
	slope = GetTileSlope(tile, &z);
 

	
 
	// Get the town zone type
 
	{
 
		uint rad = GetTownRadiusGroup(t, tile);
 

	
 
		int land = _opt.landscape;
 
		if (land == LT_HILLY && z >= _opt.snow_line)
 
			land = -1;
 
		if (land == LT_HILLY && z >= _opt.snow_line) land = -1;
 

	
 
		bitmask = (1 << rad) + (1 << (land + 12));
 
	}
 

	
 
	// bits 0-4 are used
 
	// bits 11-15 are used
 
	// bits 5-10 are not used.
 
	{
 
		byte houses[lengthof(_housetype_flags)];
 
		int num = 0;
 

	
 
		// Generate a list of all possible houses that can be built.
 
		for (i=0; i!=lengthof(_housetype_flags); i++) {
 
			if ((~_housetype_flags[i] & bitmask) == 0)
 
				houses[num++] = (byte)i;
 
		}
 

	
 
		for (;;) {
 
			house = houses[RandomRange(num)];
 

	
 
			if (_cur_year < _housetype_years[house].min || _cur_year > _housetype_years[house].max)
 
				continue;
 

	
 
			// Special houses that there can be only one of.
 
@@ -1238,50 +1239,48 @@ static void DoBuildTownHouse(Town *t, Ti
 

	
 
	t->num_houses++;
 

	
 
	// Special houses that there can be only one of.
 
	t->flags12 |= oneof;
 

	
 
	{
 
		byte construction_counter = 0, construction_stage = 0, size_flags;
 

	
 
		if (_generating_world) {
 
			uint32 r = Random();
 

	
 
			construction_stage = TOWN_HOUSE_COMPLETED;
 
			if (CHANCE16(1, 7)) construction_stage = GB(r, 0, 2);
 

	
 
			if (construction_stage == TOWN_HOUSE_COMPLETED) {
 
				ChangePopulation(t, _housetype_population[house]);
 
			} else {
 
				construction_counter = GB(r, 2, 2);
 
			}
 
		}
 
		size_flags = GB(_housetype_extra_flags[house], 2, 3);
 
		MakeTownHouse(tile, t->index, construction_counter, construction_stage, size_flags, house);
 
	}
 

	
 
	// ENDING
 
}
 

	
 
static bool BuildTownHouse(Town *t, TileIndex tile)
 
{
 
	int32 r;
 

	
 
	// make sure it's possible
 
	if (!EnsureNoVehicle(tile)) return false;
 
	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
 

	
 
	r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(r)) return false;
 

	
 
	DoBuildTownHouse(t, tile);
 
	return true;
 
}
 

	
 

	
 
static void DoClearTownHouseHelper(TileIndex tile)
 
{
 
	assert(IsTileType(tile, MP_HOUSE));
 
	DoClearSquare(tile);
 
	DeleteAnimatedTile(tile);
 
}
 
@@ -1689,69 +1688,65 @@ static void UpdateTownGrowRate(Town *t)
 

	
 
	SETBIT(t->flags12, TOWN_IS_FUNDED);
 
}
 

	
 
static void UpdateTownAmounts(Town *t)
 
{
 
	// Using +1 here to prevent overflow and division by zero
 
	t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
 

	
 
	t->max_pass = t->new_max_pass; t->new_max_pass = 0;
 
	t->act_pass = t->new_act_pass; t->new_act_pass = 0;
 
	t->act_food = t->new_act_food; t->new_act_food = 0;
 
	t->act_water = t->new_act_water; t->new_act_water = 0;
 

	
 
	// Using +1 here to prevent overflow and division by zero
 
	t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
 
	t->max_mail = t->new_max_mail; t->new_max_mail = 0;
 
	t->act_mail = t->new_act_mail; t->new_act_mail = 0;
 

	
 
	InvalidateWindow(WC_TOWN_VIEW, t->index);
 
}
 

	
 
static void UpdateTownUnwanted(Town *t)
 
{
 
	Player *p;
 
	const Player* p;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (t->unwanted[p->index] > 0)
 
			t->unwanted[p->index]--;
 
		if (t->unwanted[p->index] > 0) t->unwanted[p->index]--;
 
	}
 
}
 

	
 
bool CheckIfAuthorityAllows(TileIndex tile)
 
{
 
	Town *t;
 

	
 
	if (_current_player >= MAX_PLAYERS)
 
		return true;
 
	if (_current_player >= MAX_PLAYERS) return true;
 

	
 
	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 
	if (t == NULL)
 
		return true;
 
	if (t == NULL) return true;
 

	
 
	if (t->ratings[_current_player] > -200)
 
		return true;
 
	if (t->ratings[_current_player] > -200) return true;
 

	
 
	_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
 
	SetDParam(0, t->index);
 

	
 
	return false;
 
}
 

	
 

	
 
Town* CalcClosestTownFromTile(TileIndex tile, uint threshold)
 
{
 
	Town *t;
 
	uint dist, best = threshold;
 
	Town *best_town = NULL;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		if (t->xy != 0) {
 
			dist = DistanceManhattan(tile, t->xy);
 
			if (dist < best) {
 
				best = dist;
 
				best_town = t;
 
			}
 
		}
 
	}
 

	
 
@@ -1816,54 +1811,52 @@ bool CheckforTownRating(uint32 flags, To
 
	//	if magic_bulldozer cheat is active, town doesn't restrict your destructive actions
 
	if (t == NULL || _current_player >= MAX_PLAYERS || _cheats.magic_bulldozer.value)
 
		return true;
 

	
 
	/*	check if you're allowed to remove the street/bridge/tunnel/industry
 
	 *	owned by a town	no removal if rating is lower than ... depends now on
 
	 *	difficulty setting. Minimum town rating selected by difficulty level
 
	 */
 
	modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type];
 

	
 
	if (t->ratings[_current_player] < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) {
 
		SetDParam(0, t->index);
 
		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
void TownsMonthlyLoop(void)
 
{
 
	Town *t;
 

	
 
	FOR_ALL_TOWNS(t) if (t->xy != 0) {
 
		if (t->road_build_months != 0)
 
			t->road_build_months--;
 
		if (t->road_build_months != 0) t->road_build_months--;
 

	
 
		if (t->exclusive_counter != 0)
 
			if (--t->exclusive_counter == 0)
 
				t->exclusivity = (byte)-1;
 
			if (--t->exclusive_counter == 0) t->exclusivity = (byte)-1;
 

	
 
		UpdateTownGrowRate(t);
 
		UpdateTownAmounts(t);
 
		UpdateTownUnwanted(t);
 
	}
 
}
 

	
 
void InitializeTowns(void)
 
{
 
	Subsidy *s;
 

	
 
	/* Clean the town pool and create 1 block in it */
 
	CleanPool(&_town_pool);
 
	AddBlockToPool(&_town_pool);
 

	
 
	memset(_subsidies, 0, sizeof(_subsidies));
 
	for (s=_subsidies; s != endof(_subsidies); s++)
 
		s->cargo_type = CT_INVALID;
 

	
 
	_cur_town_ctr = 0;
 
	_cur_town_iter = 0;
 
	_total_towns = 0;
 
	_town_sort_dirty = true;
 
}
train_gui.c
Show inline comments
 
@@ -319,49 +319,49 @@ static const Widget _new_rail_vehicle_wi
 
{  WWT_RESIZEBOX,     RESIZE_TB,    14,   216,   227,   198,   209, 0x0,											STR_RESIZE_BUTTON},
 
{   WIDGETS_END},
 
};
 

	
 
static const WindowDesc _new_rail_vehicle_desc = {
 
	-1, -1, 228, 210,
 
	WC_BUILD_VEHICLE,0,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 
	_new_rail_vehicle_widgets,
 
	NewRailVehicleWndProc
 
};
 

	
 
static void ShowBuildTrainWindow(TileIndex tile)
 
{
 
	Window *w;
 

	
 
	DeleteWindowById(WC_BUILD_VEHICLE, tile);
 

	
 
	w = AllocateWindowDesc(&_new_rail_vehicle_desc);
 
	w->window_number = tile;
 
	w->vscroll.cap = 8;
 
	w->widget[2].unkA = (w->vscroll.cap << 8) + 1;
 

	
 
	w->resize.step_height = 14;
 
	w->resize.height = w->height - 14 * 4; /* Minimum of 4 vehicles in the display */
 
	w->resize.height = w->height - 14 * 4; // Minimum of 4 vehicles in the display
 

	
 
	if (tile != 0) {
 
		w->caption_color = GetTileOwner(tile);
 
		WP(w,buildtrain_d).railtype = GetRailType(tile);
 
	} else {
 
		w->caption_color = _local_player;
 
		WP(w,buildtrain_d).railtype = GetBestRailtype(GetPlayer(_local_player));
 
	}
 
}
 

	
 
/**
 
 * Get the number of pixels for the given wagon length.
 
 * @param len Length measured in 1/8ths of a standard wagon.
 
 * @return Number of pixels across.
 
 */
 
static int WagonLengthToPixels(int len) {
 
	return (len * _traininfo_vehicle_width) / 8;
 
}
 

	
 
static void DrawTrainImage(const Vehicle *v, int x, int y, int count, int skip, VehicleID selection)
 
{
 
	DrawPixelInfo tmp_dpi, *old_dpi;
 
	int dx = -(skip * 8) / _traininfo_vehicle_width;
 

	
 
@@ -1028,52 +1028,51 @@ static void TrainViewWndProc(Window *w, 
 
			break;
 
		case 12:
 
			ShowRailVehicleRefitWindow(v);
 
			break;
 
		case 13:
 
			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, NULL, CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
 
			break;
 
		}
 
	} break;
 

	
 
	case WE_RESIZE:
 
		w->viewport->width  += e->sizing.diff.x;
 
		w->viewport->height += e->sizing.diff.y;
 
		w->viewport->virtual_width  += e->sizing.diff.x;
 
		w->viewport->virtual_height += e->sizing.diff.y;
 
		break;
 

	
 
	case WE_DESTROY:
 
		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
 
		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
 
		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
 
		break;
 

	
 
	case WE_MOUSELOOP: {
 
		Vehicle *v;
 
		const Vehicle* v = GetVehicle(w->window_number);
 
		uint32 h;
 

	
 
		v = GetVehicle(w->window_number);
 
		assert(v->type == VEH_Train);
 
		h = CheckTrainStoppedInDepot(v) >= 0 ? (1 << 9)| (1 << 7) : (1 << 12) | (1 << 13);
 
		if (h != w->hidden_state) {
 
			w->hidden_state = h;
 
			SetWindowDirty(w);
 
		}
 
		break;
 
	}
 

	
 
	}
 
}
 

	
 
static const WindowDesc _train_view_desc = {
 
	-1,-1, 250, 134,
 
	WC_VEHICLE_VIEW,0,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 
	_train_view_widgets,
 
	TrainViewWndProc
 
};
 

	
 
void ShowTrainViewWindow(const Vehicle* v)
 
{
 
	Window* w = AllocateWindowDescFront(&_train_view_desc,v->index);
 

	
tunnelbridge_cmd.c
Show inline comments
 
@@ -217,55 +217,57 @@ int32 CmdBuildBridge(TileIndex end_tile,
 
	} else {
 
		if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR;
 
		railtype = GB(p2, 8, 8);
 
		transport = TRANSPORT_RAIL;
 
	}
 

	
 
	x = TileX(end_tile);
 
	y = TileY(end_tile);
 
	sx = TileX(p1);
 
	sy = TileY(p1);
 

	
 
	/* check if valid, and make sure that (x,y) are smaller than (sx,sy) */
 
	if (x == sx) {
 
		if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
 
		direction = AXIS_Y;
 
		if (y > sy) uintswap(y,sy);
 
	} else if (y == sy) {
 
		direction = AXIS_X;
 
		if (x > sx) uintswap(x,sx);
 
	} else {
 
		return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
 
	}
 

	
 
	/* set and test bridge length, availability */
 
	bridge_len = (sx + sy - x - y) - 1;
 
	bridge_len = sx + sy - x - y - 1;
 
	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
 

	
 
	/* retrieve landscape height and ensure it's on land */
 
	tile_start = TileXY(x, y);
 
	tile_end = TileXY(sx, sy);
 
	if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
 
	if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) {
 
		return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
 
	}
 

	
 
	tileh_start = GetTileSlope(tile_start, &z_start);
 
	tileh_end = GetTileSlope(tile_end, &z_end);
 

	
 
	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) {
 
		z_start += TILE_HEIGHT;
 
		tileh_start = SLOPE_FLAT;
 
	}
 

	
 
	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) {
 
		z_end += TILE_HEIGHT;
 
		tileh_end = SLOPE_FLAT;
 
	}
 

	
 
	if (z_start != z_end) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
 

	
 
	// Towns are not allowed to use bridges on slopes.
 
	allow_on_slopes = (!_is_old_ai_player
 
	                   && _current_player != OWNER_TOWN && _patches.build_on_slopes);
 

	
 
	/* Try and clear the start landscape */
 

	
 
	ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(ret)) return ret;
 
@@ -304,49 +306,49 @@ int32 CmdBuildBridge(TileIndex end_tile,
 
		MarkTileDirtyByTile(tile_start);
 
		MarkTileDirtyByTile(tile_end);
 
	}
 

	
 
	// position of middle part of the odd bridge (larger than MAX(i) otherwise)
 
	odd_middle_part = (bridge_len % 2) ? (bridge_len / 2) : bridge_len;
 

	
 
	tile = tile_start;
 
	delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 
	for (i = 0; i != bridge_len; i++) {
 
		TransportType transport_under;
 
		Owner owner_under = OWNER_NONE;
 
		RailType rail_under = INVALID_RAILTYPE;
 
		uint z;
 

	
 
		tile += delta;
 

	
 
		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) {
 
			return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
 
		}
 

	
 
		switch (GetTileType(tile)) {
 
			case MP_WATER:
 
				if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
 
				if (!(IsWater(tile) || IsCoast(tile))) goto not_valid_below;
 
				if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
 
				transport_under = TRANSPORT_WATER;
 
				owner_under = GetTileOwner(tile);
 
				break;
 

	
 
			case MP_RAILWAY:
 
				if (GetRailTileType(tile) != RAIL_TILE_NORMAL ||
 
						GetTrackBits(tile) != (direction == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X)) {
 
					goto not_valid_below;
 
				}
 
				transport_under = TRANSPORT_RAIL;
 
				owner_under = GetTileOwner(tile);
 
				rail_under = GetRailType(tile);
 
				break;
 

	
 
			case MP_STREET:
 
				if (GetRoadTileType(tile) != ROAD_TILE_NORMAL ||
 
						GetRoadBits(tile) != (direction == AXIS_X ? ROAD_Y : ROAD_X)) {
 
					goto not_valid_below;
 
				}
 
				transport_under = TRANSPORT_ROAD;
 
				owner_under = GetTileOwner(tile);
 
				break;
 

	
 
			default:
 
@@ -487,49 +489,48 @@ int32 CmdBuildTunnel(TileIndex start_til
 

	
 
	// if the command fails from here on we want the end tile to be highlighted
 
	_build_tunnel_endtile = end_tile;
 

	
 
	// slope of end tile must be complementary to the slope of the start tile
 
	if (end_tileh != ComplementSlope(start_tileh)) {
 
		ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
 
		if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
 
	} else {
 
		ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
		if (CmdFailed(ret)) return ret;
 
	}
 
	cost += _price.build_tunnel + ret;
 

	
 
	if (flags & DC_EXEC) {
 
		if (GB(p1, 9, 1) == TRANSPORT_RAIL) {
 
			MakeRailTunnel(start_tile, _current_player, direction,                 GB(p1, 0, 4));
 
			MakeRailTunnel(end_tile,   _current_player, ReverseDiagDir(direction), GB(p1, 0, 4));
 
			UpdateSignalsOnSegment(start_tile, direction);
 
			YapfNotifyTrackLayoutChange(start_tile, DiagDirToAxis(direction) == AXIS_X ? TRACK_X : TRACK_Y);
 
		} else {
 
			MakeRoadTunnel(start_tile, _current_player, direction);
 
			MakeRoadTunnel(end_tile,   _current_player, ReverseDiagDir(direction));
 
		}
 

	
 
	}
 

	
 
	return cost;
 
}
 

	
 
TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
 
{
 
	uint z = GetTileZ(tile);
 
	DiagDirection dir = GetTunnelDirection(tile);
 
	TileIndexDiff delta = TileOffsByDir(dir);
 
	uint len = 0;
 
	TileIndex starttile = tile;
 
	Vehicle *v;
 

	
 
	do {
 
		tile += delta;
 
		len++;
 
	} while (
 
		!IsTunnelTile(tile) ||
 
		ReverseDiagDir(GetTunnelDirection(tile)) != dir ||
 
		GetTileZ(tile) != z
 
	);
 

	
 
	v = FindVehicleBetween(starttile, tile, z);
 
@@ -640,50 +641,51 @@ static int32 DoClearBridge(TileIndex til
 
			if (flags & DC_EXEC) {
 
				SetClearUnderBridge(tile);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			return _price.clear_water;
 
		}
 

	
 
		tile = GetSouthernBridgeEnd(tile);
 
	}
 

	
 
	// floods, scenario editor can always destroy bridges
 
	if (_current_player != OWNER_WATER && _game_mode != GM_EDITOR && !CheckTileOwnership(tile)) {
 
		if (!(_patches.extra_dynamite || _cheats.magic_bulldozer.value) || !IsTileOwner(tile, OWNER_TOWN))
 
			return CMD_ERROR;
 
	}
 

	
 
	endtile = GetOtherBridgeEnd(tile);
 

	
 
	if (!EnsureNoVehicle(tile) || !EnsureNoVehicle(endtile)) return CMD_ERROR;
 

	
 
	direction = GetBridgeRampDirection(tile);
 
	delta = TileOffsByDir(direction);
 

	
 
	/*	Make sure there's no vehicle on the bridge
 
			Omit tile and endtile, since these are already checked, thus solving the problem
 
			of bridges over water, or higher bridges, where z is not increased, eg level bridge
 
	 * Omit tile and endtile, since these are already checked, thus solving the
 
	 * problem of bridges over water, or higher bridges, where z is not increased,
 
	 * eg level bridge
 
	*/
 
	/* Bridges on slopes might have their Z-value offset..correct this */
 
	v = FindVehicleBetween(
 
		tile    + delta,
 
		endtile - delta,
 
		GetBridgeHeightRamp(tile) + TILE_HEIGHT
 
	);
 
	if (v != NULL) return_cmd_error(VehicleInTheWayErrMsg(v));
 

	
 
	t = ClosestTownFromTile(tile, (uint)-1); //needed for town rating penalty
 
	// check if you're allowed to remove the bridge owned by a town.
 
	// removal allowal depends on difficulty settings
 
	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
 
		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) return CMD_ERROR;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		TileIndex c;
 

	
 
		//checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
 
		// you have a "Poor" (0) town rating
 
		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
 
			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
 

	
 
@@ -716,142 +718,142 @@ static int32 DoClearBridge(TileIndex til
 
		UpdateSignalsOnSegment(endtile, direction);
 
		YapfNotifyTrackLayoutChange(tile, DiagDirToAxis(direction) == AXIS_X ? TRACK_X : TRACK_Y);
 
		YapfNotifyTrackLayoutChange(endtile, DiagDirToAxis(direction) == AXIS_X ? TRACK_X : TRACK_Y);
 
	}
 

	
 
	return (DistanceManhattan(tile, endtile) + 1) * _price.clear_bridge;
 
}
 

	
 
static int32 ClearTile_TunnelBridge(TileIndex tile, byte flags)
 
{
 
	if (IsTunnel(tile)) {
 
		if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
 
		return DoClearTunnel(tile, flags);
 
	} else if (IsBridge(tile)) { // XXX Is this necessary?
 
		if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
 
		return DoClearBridge(tile, flags);
 
	}
 

	
 
	return CMD_ERROR;
 
}
 

	
 
int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
 
{
 
	TileIndex endtile;
 
	uint length;
 
	Vehicle *v;
 

	
 
	if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
 
		uint length;
 

	
 
		if (!CheckTileOwnership(tile)) return CMD_ERROR;
 

	
 
		if (GetRailType(tile) == totype) return CMD_ERROR;
 

	
 
		endtile = CheckTunnelBusy(tile, &length);
 
		if (endtile == INVALID_TILE) return CMD_ERROR;
 

	
 
		if (exec) {
 
			Track track, endtrack;
 
			SetRailType(tile, totype);
 
			SetRailType(endtile, totype);
 
			MarkTileDirtyByTile(tile);
 
			MarkTileDirtyByTile(endtile);
 

	
 
			// notify YAPF about the track layout change
 
			track = TrackdirToTrack(DiagdirToDiagTrackdir(GetTunnelDirection(tile)));
 
			endtrack = TrackdirToTrack(DiagdirToDiagTrackdir(GetTunnelDirection(endtile)));
 
			YapfNotifyTrackLayoutChange(tile, track);
 
			YapfNotifyTrackLayoutChange(endtile, endtrack);
 
		}
 
		return (length + 1) * (_price.build_rail >> 1);
 
	} else if (IsBridge(tile) &&
 
			IsBridgeMiddle(tile) &&
 
			IsTransportUnderBridge(tile) &&
 
			GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
 
		// only check for train under bridge
 
		if (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile))
 
			return CMD_ERROR;
 

	
 
		if (GetRailType(tile) == totype) return CMD_ERROR;
 

	
 
		if (exec) {
 
			TrackBits tracks;
 
			SetRailType(tile, totype);
 
			MarkTileDirtyByTile(tile);
 

	
 
			// notify YAPF about the track layout change
 
			for (tracks = GetRailBitsUnderBridge(tile); tracks != TRACK_BIT_NONE; tracks = KILL_FIRST_BIT(tracks))
 
				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(tracks));
 
		}
 
		return _price.build_rail >> 1;
 
	} else if (IsBridge(tile) && IsBridgeRamp(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
 
		uint z = TilePixelHeight(tile) + TILE_HEIGHT;
 
		const Vehicle* v;
 
		TileIndexDiff delta;
 
		int32 cost;
 
		uint z = TilePixelHeight(tile);
 

	
 
		z += TILE_HEIGHT;
 

	
 
		if (!CheckTileOwnership(tile)) return CMD_ERROR;
 

	
 
		endtile = GetOtherBridgeEnd(tile);
 
		// Make sure there's no vehicle on the bridge
 
		v = FindVehicleBetween(tile, endtile, z);
 
		if (v != NULL) {
 
			return_cmd_error(VehicleInTheWayErrMsg(v));
 
		}
 

	
 
		if (!EnsureNoVehicle(tile) || !EnsureNoVehicle(endtile)) {
 
			return_cmd_error(STR_8803_TRAIN_IN_THE_WAY);
 
		}
 

	
 
		if (GetRailType(tile) == totype) return CMD_ERROR;
 

	
 
		if (exec) {
 
			Track track, endtrack;
 
			SetRailType(tile, totype);
 
			SetRailType(endtile, totype);
 
			MarkTileDirtyByTile(tile);
 
			MarkTileDirtyByTile(endtile);
 

	
 
			// notify YAPF about the track layout change
 
			track = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(tile)));
 
			endtrack = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(endtile)));
 
			YapfNotifyTrackLayoutChange(tile, track);
 
			YapfNotifyTrackLayoutChange(endtile, endtrack);
 
		}
 
		cost = 2 * (_price.build_rail >> 1);
 
		delta = TileOffsByDir(GetBridgeRampDirection(tile));
 
		for (tile += delta; tile != endtile; tile += delta) {
 
			if (exec) {
 
				SetRailTypeOnBridge(tile, totype);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			cost += _price.build_rail >> 1;
 
		}
 

	
 
		return cost;
 
	} else
 
	} else {
 
		return CMD_ERROR;
 
}
 
}
 

	
 

	
 
// fast routine for getting the height of a middle bridge tile. 'tile' MUST be a middle bridge tile.
 
uint GetBridgeHeight(TileIndex t)
 
{
 
	return GetBridgeHeightRamp(GetSouthernBridgeEnd(t));
 
}
 

	
 
static const byte _bridge_foundations[2][16] = {
 
// 0 1  2  3  4 5 6 7  8 9 10 11 12 13 14 15
 
	{0,16,18,3,20,5,0,7,22,0,10,11,12,13,14},
 
	{0,15,17,0,19,5,6,7,21,9,10,11, 0,13,14},
 
};
 

	
 
extern const byte _road_sloped_sprites[14];
 

	
 
static void DrawBridgePillars(PalSpriteID image, const TileInfo *ti, int x, int y, int z)
 
{
 
	if (image != 0) {
 
		Axis axis = GetBridgeAxis(ti->tile);
 
		bool drawfarpillar = !HASBIT(GetBridgeFlags(GetBridgeType(ti->tile)), 0);
 
		int back_height, front_height;
 
		int i = z;
 
		const byte *p;
video/cocoa_v.m
Show inline comments
 
@@ -643,50 +643,48 @@ static bool QZ_PollEvent(void)
 
					}
 
					break;
 
			}
 

	
 
			chars = [ event characters ];
 
			QZ_KeyEvent([event keyCode], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, NO);
 
			break;
 

	
 
		case NSScrollWheel:
 
			if ([ event deltaX ] > 0.0 || [ event deltaY ] > 0.0) { /* Scroll up */
 
				_cursor.wheel--;
 
			} else { /* Scroll down */
 
				_cursor.wheel++;
 
			}
 
			break;
 

	
 
		default:
 
			[NSApp sendEvent:event];
 
	}
 

	
 
	return true;
 
}
 

	
 

	
 

	
 

	
 
static void QZ_GameLoop(void)
 
{
 
	uint32 next_tick = GetTick() + 30;
 
	uint32 cur_ticks;
 
	uint32 pal_tick = 0;
 
#ifdef _DEBUG
 
	uint32 et0, et, st0, st;
 
#endif
 
	int i;
 

	
 
	DEBUG(driver, 1)("cocoa_v: QZ_GameLoop");
 

	
 
#ifdef _DEBUG
 
	et0 = GetTick();
 
	st = 0;
 
#endif
 

	
 
	_screen.dst_ptr = _cocoa_video_data.pixels;
 
	DisplaySplashImage();
 
	QZ_CheckPaletteAnim();
 
	QZ_Draw();
 
	CSleep(1);
 

	
 
	for (i = 0; i < 2; i++) GameLoop();
video/win32_v.c
Show inline comments
 
@@ -628,55 +628,57 @@ static bool AllocateDibSection(int w, in
 
	ReleaseDC(0, dc);
 

	
 
	if (!_wnd.double_size)
 
		_wnd.buffer_bits = _wnd.bitmap_bits;
 

	
 
	return true;
 
}
 

	
 
static const uint16 default_resolutions[][2] = {
 
	{ 640,  480},
 
	{ 800,  600},
 
	{1024,  768},
 
	{1152,  864},
 
	{1280,  800},
 
	{1280,  960},
 
	{1280, 1024},
 
	{1400, 1050},
 
	{1600, 1200},
 
	{1680, 1050},
 
	{1920, 1200}
 
};
 

	
 
static void FindResolutions(void)
 
{
 
	int i = 0, n = 0;
 
	uint n = 0;
 
	uint i;
 
	DEVMODE dm;
 

	
 
	while (EnumDisplaySettings(NULL, i++, &dm) != 0) {
 
	for (i = 0; EnumDisplaySettings(NULL, i, &dm) != 0; i++) {
 
		if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
 
				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)){
 
			int j;
 
			uint j;
 

	
 
			for (j = 0; j < n; j++) {
 
				if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break;
 
			}
 

	
 
			/* In the previous loop we have checked already existing/added resolutions if
 
			 * they are the same as the new ones. If this is not the case (j == n); we have
 
			 * looped all and found none, add the new one to the list. If we have reached the
 
			 * maximum amount of resolutions, then quit querying the display */
 
			if (j == n) {
 
				_resolutions[j][0] = dm.dmPelsWidth;
 
				_resolutions[j][1] = dm.dmPelsHeight;
 
				if (++n == lengthof(_resolutions)) break;
 
			}
 
		}
 
	}
 

	
 
	/* We have found no resolutions, show the default list */
 
	if (n == 0) {
 
		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
 
		n = lengthof(default_resolutions);
 
	}
 

	
 
	_num_resolutions = n;
 
	SortResolutions(_num_resolutions);
viewport.c
Show inline comments
 
@@ -525,48 +525,49 @@ void *AddStringToDraw(int x, int y, Stri
 

	
 
	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
 
		DEBUG(misc, 0) ("Out of sprite mem");
 
		return NULL;
 
	}
 
	ss = (StringSpriteToDraw*)vd->spritelist_mem;
 

	
 
	vd->spritelist_mem += sizeof(StringSpriteToDraw);
 

	
 
	ss->string = string;
 
	ss->next = NULL;
 
	ss->x = x;
 
	ss->y = y;
 
	ss->params[0] = params_1;
 
	ss->params[1] = params_2;
 
	ss->params[2] = params_3;
 
	ss->width = 0;
 

	
 
	*vd->last_string = ss;
 
	vd->last_string = &ss->next;
 

	
 
	return ss;
 
}
 

	
 

	
 
static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
 
{
 
	if (_added_tile_sprite && !(_thd.drawstyle & HT_LINE)) { // draw on real ground
 
		DrawGroundSpriteAt(image, ti->x, ti->y, ti->z + 7);
 
	} else { // draw on top of foundation
 
		AddSortableSpriteToDraw(image, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
 
	}
 
}
 

	
 
static bool IsPartOfAutoLine(int px, int py)
 
{
 
	px -= _thd.selstart.x;
 
	py -= _thd.selstart.y;
 

	
 
	switch (_thd.drawstyle) {
 
	case HT_LINE | HT_DIR_X:  return py == 0; // x direction
 
	case HT_LINE | HT_DIR_Y:  return px == 0; // y direction
 
	case HT_LINE | HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
 
	case HT_LINE | HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
 
	case HT_LINE | HT_DIR_VL: return px == py || px == py + 16; // vertival left
 
	case HT_LINE | HT_DIR_VR: return px == py || px == py - 16; // vertical right
 
	default:
 
		NOT_REACHED();
 
	}
waypoint.c
Show inline comments
 
@@ -196,70 +196,70 @@ int32 CmdBuildTrainWaypoint(TileIndex ti
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 

	
 
	tileh = GetTileSlope(tile, NULL);
 
	if (tileh != SLOPE_FLAT) {
 
		if (!_patches.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))
 
			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 
	}
 

	
 
	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
 
	wp = FindDeletedWaypointCloseTo(tile);
 
	if (wp == NULL) {
 
		wp = AllocateWaypoint();
 
		if (wp == NULL) return CMD_ERROR;
 

	
 
		wp->town_index = 0;
 
		wp->string = STR_NULL;
 
		wp->town_cn = 0;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		const StationSpec *statspec = NULL;
 
		MakeRailWaypoint(tile, GetTileOwner(tile), axis, GetRailType(tile), wp->index);
 
		MarkTileDirtyByTile(tile);
 

	
 
		if (GB(p1, 0, 8) < GetNumCustomStations(STAT_CLASS_WAYP))
 
		if (GB(p1, 0, 8) < GetNumCustomStations(STAT_CLASS_WAYP)) {
 
			statspec = GetCustomStationSpec(STAT_CLASS_WAYP, GB(p1, 0, 8));
 
		}
 

	
 
		if (statspec != NULL) {
 
			SetCustomWaypointSprite(tile);
 
			wp->stat_id = GB(p1, 0, 8);
 
			wp->grfid = statspec->grfid;
 
			wp->localidx = statspec->localidx;
 
		} else {
 
			// Specified custom graphics do not exist, so use default.
 
			ClearCustomWaypointSprite(tile);
 
			wp->stat_id = 0;
 
			wp->grfid = 0;
 
			wp->localidx = 0;
 
		}
 

	
 
		wp->deleted = 0;
 
		wp->xy = tile;
 
		wp->build_date = _date;
 

	
 
		if (wp->town_index == 0)
 
			MakeDefaultWaypointName(wp);
 
		if (wp->town_index == 0) MakeDefaultWaypointName(wp);
 

	
 
		UpdateWaypointSign(wp);
 
		RedrawWaypointSign(wp);
 
	}
 

	
 
	return _price.build_train_depot;
 
}
 

	
 
/* Internal handler to delete a waypoint */
 
static void DoDeleteWaypoint(Waypoint *wp)
 
{
 
	Order order;
 

	
 
	wp->xy = 0;
 

	
 
	order.type = OT_GOTO_WAYPOINT;
 
	order.station = wp->index;
 
	DeleteDestinationFromVehicleOrder(order);
 

	
 
	if (wp->string != STR_NULL)
 
		DeleteName(wp->string);
 

	
 
	RedrawWaypointSign(wp);
 
}
window.c
Show inline comments
 
@@ -1435,51 +1435,51 @@ static void MouseLoop(int click, int mou
 
			if (!(w->flags4 & WF_DISABLE_VP_SCROLL)) {
 
				_scrolling_viewport = true;
 
				_cursor.fix_at = true;
 
			}
 
		}
 
	} else {
 
		if (mousewheel)
 
			DispatchMouseWheelEvent(w, GetWidgetFromPos(w, x - w->left, y - w->top), mousewheel);
 

	
 
		switch (click) {
 
			case 1: DispatchLeftClickEvent(w, x - w->left, y - w->top);  break;
 
			case 2: DispatchRightClickEvent(w, x - w->left, y - w->top); break;
 
		}
 
	}
 
}
 

	
 
void InputLoop(void)
 
{
 
	int click;
 
	int mousewheel;
 

	
 
	_current_player = _local_player;
 

	
 
	// Handle pressed keys
 
	if (_pressed_key) {
 
		uint32 key = _pressed_key; _pressed_key = 0;
 
		HandleKeypress(key);
 
	if (_pressed_key != 0) {
 
		HandleKeypress(_pressed_key);
 
		_pressed_key = 0;
 
	}
 

	
 
	// Mouse event?
 
	click = 0;
 
	if (_left_button_down && !_left_button_clicked) {
 
		_left_button_clicked = true;
 
		click = 1;
 
	} else if (_right_button_clicked) {
 
		_right_button_clicked = false;
 
		click = 2;
 
	}
 

	
 
	mousewheel = 0;
 
	if (_cursor.wheel) {
 
		mousewheel = _cursor.wheel;
 
		_cursor.wheel = 0;
 
	}
 

	
 
	MouseLoop(click, mousewheel);
 
}
 

	
 

	
 
static int _we4_timer;
 

	
0 comments (0 inline, 0 general)