Changeset - r4850:7a78073de588
[Not reviewed]
master
0 15 0
Darkvater - 18 years ago 2006-10-14 22:31:18
darkvater@openttd.org
(svn r6776) -Codechange: Use IsValidPlayer() function to determine of a PlayerID is an
actual playable player (< MAX_PLAYERS) or not.
15 files changed with 49 insertions and 48 deletions:
0 comments (0 inline, 0 general)
ai/ai.c
Show inline comments
 
@@ -192,49 +192,49 @@ void AI_RunGameLoop(void)
 
	} else if (!_networking || _network_server) {
 
		/* Check if we want to run AIs (server or SP only) */
 
		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);
 
	assert(IsValidPlayer(player));
 

	
 
	/* 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) {
 
		_ai.network_playas = PLAYER_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;
command.c
Show inline comments
 
@@ -362,61 +362,61 @@ int32 DoCommand(TileIndex tile, uint32 p
 
		}
 

	
 
		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);
 
		// XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player
 
		if (tile != 0 && _current_player < MAX_PLAYERS) {
 
		if (tile != 0 && IsValidPlayer(_current_player)) {
 
			GetPlayer(_current_player)->last_build_coordinate = tile;
 
		}
 
	}
 

	
 
	_cmd_text = NULL;
 
	return res;
 
}
 

	
 
int32 GetAvailableMoneyForCommand(void)
 
{
 
	PlayerID pid = _current_player;
 
	if (pid >= MAX_PLAYERS) return 0x7FFFFFFF; // max int
 
	if (!IsValidPlayer(pid)) return 0x7FFFFFFF; // max int
 
	return GetPlayer(pid)->player_money;
 
}
 

	
 
// toplevel network safe docommand function for the current player. must not be called recursively.
 
// the callback is called when the command succeeded or failed.
 
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
 
{
 
	int32 res = 0,res2;
 
	CommandProc *proc;
 
	uint32 flags;
 
	bool notest;
 
	StringID error_part1;
 

	
 
	int x = TileX(tile) * TILE_SIZE;
 
	int y = TileY(tile) * TILE_SIZE;
 

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

	
 
	assert(_docommand_recursive == 0);
 

	
 
@@ -487,49 +487,49 @@ 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 = PLAYER_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) {
 
	if (tile != 0 && IsValidPlayer(_current_player)) {
 
		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 (_additional_cash_required) {
console_cmds.c
Show inline comments
 
@@ -1269,54 +1269,54 @@ DEF_CONSOLE_HOOK(ConHookServerPW)
 
		_network_server_password[0] = '\0';
 
		_network_game_info.use_password = 0;
 
	} else {
 
		ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
 
		_network_game_info.use_password = 1;
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_HOOK(ConHookRconPW)
 
{
 
	if (strcmp(_network_rcon_password, "*") == 0)
 
		_network_rcon_password[0] = '\0';
 

	
 
	ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password));
 

	
 
	return true;
 
}
 

	
 
/* Also use from within player_gui to change the password graphically */
 
bool NetworkChangeCompanyPassword(byte argc, char *argv[])
 
{
 
	if (argc == 0) {
 
		if (_local_player >= MAX_PLAYERS) return true; // dedicated server
 
		if (!IsValidPlayer(_local_player)) return true; // dedicated server
 
		IConsolePrintF(_icolour_warn, "Current value for 'company_pw': %s", _network_player_info[_local_player].password);
 
		return true;
 
	}
 

	
 
	if (_local_player >= MAX_PLAYERS) {
 
	if (!IsValidPlayer(_local_player)) {
 
		IConsoleError("You have to own a company to make use of this command.");
 
		return false;
 
	}
 

	
 
	if (argc != 1) return false;
 

	
 
	if (strcmp(argv[0], "*") == 0) argv[0][0] = '\0';
 

	
 
	ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password));
 

	
 
	if (!_network_server)
 
		SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
 

	
 
	IConsolePrintF(_icolour_warn, "'company_pw' changed to:  %s", _network_player_info[_local_player].password);
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_HOOK(ConProcPlayerName)
 
{
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 

	
 
	if (ci == NULL) return false;
 

	
economy.c
Show inline comments
 
@@ -1522,128 +1522,128 @@ static void DoAcquireCompany(Player *p)
 
			owner->yearly_expenses[0][EXPENSES_OTHER] += value;
 
			UpdatePlayerMoney32(owner);
 
		}
 
	}
 

	
 
	p->is_active = false;
 

	
 
	DeletePlayerWindows(pi);
 
	RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
 
}
 

	
 
extern int GetAmountOwnedBy(Player *p, byte owner);
 

	
 
/** Acquire shares in an opposing company.
 
 * @param tile unused
 
 * @param p1 player to buy the shares from
 
 * @param p2 unused
 
 */
 
int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Player *p;
 
	int64 cost;
 

	
 
	/* Check if buying shares is allowed (protection against modified clients */
 
	if (p1 >= MAX_PLAYERS || !_patches.allow_shares) return CMD_ERROR;
 
	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 
	p = GetPlayer(p1);
 

	
 
	/* Protect new companies from hostile takeovers */
 
	if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED);
 

	
 
	/* Those lines are here for network-protection (clients can be slow) */
 
	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return 0;
 

	
 
	/* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
 
	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return 0;
 

	
 
	cost = CalculateCompanyValue(p) >> 2;
 
	if (flags & DC_EXEC) {
 
		PlayerID* b = p->share_owners;
 
		int i;
 

	
 
		while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
 
		*b = _current_player;
 

	
 
		for (i = 0; p->share_owners[i] == _current_player;) {
 
			if (++i == 4) {
 
				p->bankrupt_value = 0;
 
				DoAcquireCompany(p);
 
				break;
 
			}
 
		}
 
		InvalidateWindow(WC_COMPANY, p1);
 
	}
 
	return cost;
 
}
 

	
 
/** Sell shares in an opposing company.
 
 * @param tile unused
 
 * @param p1 player to sell the shares from
 
 * @param p2 unused
 
 */
 
int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Player *p;
 
	int64 cost;
 

	
 
	/* Check if buying shares is allowed (protection against modified clients */
 
	if (p1 >= MAX_PLAYERS || !_patches.allow_shares) return CMD_ERROR;
 
	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 
	p = GetPlayer(p1);
 

	
 
	/* Those lines are here for network-protection (clients can be slow) */
 
	if (GetAmountOwnedBy(p, _current_player) == 0) return 0;
 

	
 
	/* adjust it a little to make it less profitable to sell and buy */
 
	cost = CalculateCompanyValue(p) >> 2;
 
	cost = -(cost - (cost >> 7));
 

	
 
	if (flags & DC_EXEC) {
 
		PlayerID* b = p->share_owners;
 
		while (*b != _current_player) b++; /* share owners is guaranteed to contain player */
 
		*b = PLAYER_SPECTATOR;
 
		InvalidateWindow(WC_COMPANY, p1);
 
	}
 
	return cost;
 
}
 

	
 
/** Buy up another company.
 
 * When a competing company is gone bankrupt you get the chance to purchase
 
 * that company.
 
 * @todo currently this only works for AI players
 
 * @param tile unused
 
 * @param p1 player/company to buy up
 
 * @param p2 unused
 
 */
 
int32 CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Player *p;
 

	
 
	/* Disable takeovers in multiplayer games */
 
	if (p1 >= MAX_PLAYERS || _networking) return CMD_ERROR;
 
	if (!IsValidPlayer((PlayerID)p1) || _networking) return CMD_ERROR;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 
	p = GetPlayer(p1);
 

	
 
	if (!p->is_ai) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		DoAcquireCompany(p);
 
	}
 
	return p->bankrupt_value;
 
}
 

	
 
// Prices
 
static void SaveLoad_PRIC(void)
 
{
 
	SlArray(&_price,      NUM_PRICES, SLE_INT32);
 
	SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
 
}
 

	
 
// Cargo payment rates
 
static void SaveLoad_CAPR(void)
 
{
 
	SlArray(&_cargo_payment_rates,      NUM_CARGO, SLE_INT32);
 
	SlArray(&_cargo_payment_rates_frac, NUM_CARGO, SLE_UINT16);
misc_cmd.c
Show inline comments
 
@@ -270,49 +270,49 @@ int32 CmdMoneyCheat(TileIndex tile, uint
 
#ifndef _DEBUG
 
	if (_networking) return CMD_ERROR;
 
#endif
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 
	return (int32)p1;
 
}
 

	
 
/** Transfer funds (money) from one player to another.
 
 * To prevent abuse in multiplayer games you can only send money to other
 
 * players if you have paid off your loan (either explicitely, or implicitely
 
 * given the fact that you have more money than loan).
 
 * @param tile unused
 
 * @param p1 the amount of money to transfer; max 20.000.000
 
 * @param p2 the player to transfer the money to
 
 */
 
int32 CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	const Player *p = GetPlayer(_current_player);
 
	int32 amount = min((int32)p1, 20000000);
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 

	
 
	/* You can only transfer funds that is in excess of your loan */
 
	if (p->money64 - p->current_loan < amount || amount <= 0) return CMD_ERROR;
 
	if (!_networking || p2 >= MAX_PLAYERS) return CMD_ERROR;
 
	if (!_networking || !IsValidPlayer((PlayerID)p2)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		/* Add money to player */
 
		PlayerID old_cp = _current_player;
 
		_current_player = p2;
 
		SubtractMoneyFromPlayer(-amount);
 
		_current_player = old_cp;
 
	}
 

	
 
	/* Subtract money from local-player */
 
	return amount;
 
}
 

	
 
/** Change difficulty level/settings (server-only).
 
 * We cannot really check for valid values of p2 (too much work mostly); stored
 
 * in file 'settings_gui.c' _game_setting_info[]; we'll just trust the server it knows
 
 * what to do and does this correctly
 
 * @param tile unused
 
 * @param p1 the difficulty setting being changed. If it is -1, the difficulty level
 
 *           itself is changed. The new value is inside p2
 
 * @param p2 new value for a difficulty setting or difficulty level
 
 */
 
int32 CmdChangeDifficultyLevel(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
misc_gui.c
Show inline comments
 
@@ -134,49 +134,49 @@ static const Widget _land_info_widgets[]
 

	
 
static const WindowDesc _land_info_desc = {
 
	-1, -1, 280, 93,
 
	WC_LAND_INFO,0,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	_land_info_widgets,
 
	LandInfoWndProc
 
};
 

	
 
static void Place_LandInfo(TileIndex tile)
 
{
 
	Player *p;
 
	static LandInfoData lid;
 
	Window *w;
 
	int64 old_money;
 

	
 
	DeleteWindowById(WC_LAND_INFO, 0);
 

	
 
	w = AllocateWindowDesc(&_land_info_desc);
 
	WP(w,void_d).data = &lid;
 

	
 
	lid.tile = tile;
 
	lid.town = ClosestTownFromTile(tile, _patches.dist_local_authority);
 

	
 
	p = GetPlayer(_local_player < MAX_PLAYERS ? _local_player : 0);
 
	p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
 

	
 
	old_money = p->money64;
 
	p->money64 = p->player_money = 0x7fffffff;
 
	lid.costclear = DoCommand(tile, 0, 0, 0, CMD_LANDSCAPE_CLEAR);
 
	p->money64 = old_money;
 
	UpdatePlayerMoney32(p);
 

	
 
	// Becuase build_date is not set yet in every TileDesc, we make sure it is empty
 
	lid.td.build_date = 0;
 

	
 
	GetAcceptedCargo(tile, lid.ac);
 
	GetTileDesc(tile, &lid.td);
 

	
 
#if defined(_DEBUG)
 
#	define LANDINFOD_LEVEL 0
 
#else
 
#	define LANDINFOD_LEVEL 1
 
#endif
 
	DEBUG(misc, LANDINFOD_LEVEL) ("TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile));
 
	DEBUG(misc, LANDINFOD_LEVEL) ("type_height  = %#x", _m[tile].type_height);
 
	DEBUG(misc, LANDINFOD_LEVEL) ("m1           = %#x", _m[tile].m1);
 
	DEBUG(misc, LANDINFOD_LEVEL) ("m2           = %#x", _m[tile].m2);
 
	DEBUG(misc, LANDINFOD_LEVEL) ("m3           = %#x", _m[tile].m3);
 
	DEBUG(misc, LANDINFOD_LEVEL) ("m4           = %#x", _m[tile].m4);
 
@@ -1285,49 +1285,49 @@ static void MakeSortedSaveGameList(void)
 
	uint s_amount;
 
	int i;
 

	
 
	/* Directories are always above the files (FIOS_TYPE_DIR)
 
	 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
 
	 * Only sort savegames/scenarios, not directories
 
	 */
 
	for (i = 0; i < _fios_num; i++) {
 
		switch (_fios_list[i].type) {
 
			case FIOS_TYPE_DIR:    sort_start++; break;
 
			case FIOS_TYPE_PARENT: sort_start++; break;
 
			case FIOS_TYPE_DRIVE:  sort_end++;   break;
 
		}
 
	}
 

	
 
	s_amount = _fios_num - sort_start - sort_end;
 
	if (s_amount > 0)
 
		qsort(_fios_list + sort_start, s_amount, sizeof(FiosItem), compare_FiosItems);
 
}
 

	
 
static void GenerateFileName(void)
 
{
 
	/* Check if we are not a specatator who wants to generate a name..
 
	    Let's use the name of player #0 for now. */
 
	const Player *p = GetPlayer(_local_player < MAX_PLAYERS ? _local_player : 0);
 
	const Player *p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
 

	
 
	SetDParam(0, p->name_1);
 
	SetDParam(1, p->name_2);
 
	SetDParam(2, _date);
 
	GetString(_edit_str_buf, STR_4004);
 
}
 

	
 
extern void StartupEngines(void);
 

	
 
static void SaveLoadDlgWndProc(Window *w, WindowEvent *e)
 
{
 
	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:
 
@@ -1615,51 +1615,51 @@ void SetFiosType(const byte fiostype)
 
		case FIOS_TYPE_PNG:
 
			_file_to_saveload.mode = SL_PNG;
 
			break;
 
#endif /* WITH_PNG */
 

	
 
		case FIOS_TYPE_BMP:
 
			_file_to_saveload.mode = SL_BMP;
 
			break;
 

	
 
		default:
 
			_file_to_saveload.mode = SL_INVALID;
 
			break;
 
	}
 
}
 

	
 
static int32 ClickMoneyCheat(int32 p1, int32 p2)
 
{
 
		DoCommandP(0, -10000000, 0, NULL, CMD_MONEY_CHEAT);
 
		return true;
 
}
 

	
 
// p1 player to set to, p2 is -1 or +1 (down/up)
 
static int32 ClickChangePlayerCheat(int32 p1, int32 p2)
 
{
 
	while (p1 >= 0 && p1 < MAX_PLAYERS) {
 
	while (IsValidPlayer((PlayerID)p1)) {
 
		if (_players[p1].is_active) {
 
			_local_player = p1;
 
			_local_player = (PlayerID)p1;
 
			MarkWholeScreenDirty();
 
			return _local_player;
 
		}
 
		p1 += p2;
 
	}
 

	
 
	return _local_player;
 
}
 

	
 
// p1 -1 or +1 (down/up)
 
static int32 ClickChangeClimateCheat(int32 p1, int32 p2)
 
{
 
	if (p1 == -1) p1 = 3;
 
	if (p1 ==  4) p1 = 0;
 
	_opt.landscape = p1;
 
	GfxLoadSprites();
 
	MarkWholeScreenDirty();
 
	return _opt.landscape;
 
}
 

	
 
extern void EnginesMonthlyLoop(void);
 

	
 
// p2 1 (increase) or -1 (decrease)
 
static int32 ClickChangeDateCheat(int32 p1, int32 p2)
network_server.c
Show inline comments
 
@@ -1211,83 +1211,83 @@ void NetworkPopulateCompanyInfo(void)
 
		SetDParam(1, p->name_2);
 
		GetString(_network_player_info[p->index].company_name, STR_JUST_STRING);
 

	
 
		// Check the income
 
		if (_cur_year - 1 == p->inaugurated_year) {
 
			// The player is here just 1 year, so display [2], else display[1]
 
			for (i = 0; i < 13; i++) {
 
				_network_player_info[p->index].income -= p->yearly_expenses[2][i];
 
			}
 
		} else {
 
			for (i = 0; i < 13; i++) {
 
				_network_player_info[p->index].income -= p->yearly_expenses[1][i];
 
			}
 
		}
 

	
 
		// Set some general stuff
 
		_network_player_info[p->index].inaugurated_year = p->inaugurated_year;
 
		_network_player_info[p->index].company_value = p->old_economy[0].company_value;
 
		_network_player_info[p->index].money = p->money64;
 
		_network_player_info[p->index].performance = p->old_economy[0].performance_history;
 
	}
 

	
 
	// Go through all vehicles and count the type of vehicles
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->owner >= MAX_PLAYERS) continue;
 
		if (!IsValidPlayer(v->owner)) continue;
 
		switch (v->type) {
 
			case VEH_Train:
 
				if (IsFrontEngine(v)) {
 
					_network_player_info[v->owner].num_vehicle[0]++;
 
				}
 
				break;
 

	
 
			case VEH_Road:
 
				if (v->cargo_type != CT_PASSENGERS) {
 
					_network_player_info[v->owner].num_vehicle[1]++;
 
				} else {
 
					_network_player_info[v->owner].num_vehicle[2]++;
 
				}
 
				break;
 

	
 
			case VEH_Aircraft:
 
				if (v->subtype <= 2) {
 
					_network_player_info[v->owner].num_vehicle[3]++;
 
				}
 
				break;
 

	
 
			case VEH_Ship:
 
				_network_player_info[v->owner].num_vehicle[4]++;
 
				break;
 

	
 
			case VEH_Special:
 
			case VEH_Disaster:
 
				break;
 
		}
 
	}
 

	
 
	// Go through all stations and count the types of stations
 
	FOR_ALL_STATIONS(s) {
 
		if (s->owner < MAX_PLAYERS) {
 
		if (IsValidPlayer(s->owner)) {
 
			NetworkPlayerInfo* npi = &_network_player_info[s->owner];
 

	
 
			if (s->facilities & FACIL_TRAIN)      npi->num_station[0]++;
 
			if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[1]++;
 
			if (s->facilities & FACIL_BUS_STOP)   npi->num_station[2]++;
 
			if (s->facilities & FACIL_AIRPORT)    npi->num_station[3]++;
 
			if (s->facilities & FACIL_DOCK)       npi->num_station[4]++;
 
		}
 
	}
 

	
 
	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
	// Register local player (if not dedicated)
 
	if (ci != NULL && ci->client_playas > 0  && ci->client_playas <= MAX_PLAYERS)
 
		ttd_strlcpy(_network_player_info[ci->client_playas-1].players, ci->client_name, sizeof(_network_player_info[ci->client_playas-1].players));
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		char client_name[NETWORK_CLIENT_NAME_LENGTH];
 

	
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (ci != NULL && ci->client_playas > 0 && ci->client_playas <= MAX_PLAYERS) {
 
			if (strlen(_network_player_info[ci->client_playas-1].players) != 0)
 
				ttd_strlcat(_network_player_info[ci->client_playas - 1].players, ", ", lengthof(_network_player_info[ci->client_playas - 1].players));
openttd.c
Show inline comments
 
@@ -1236,49 +1236,49 @@ bool AfterLoadGame(void)
 
					}
 
					break;
 

	
 
				default: break;
 
			}
 
		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
 
	}
 

	
 
	/* From version 9.0, we update the max passengers of a town (was sometimes negative
 
	 *  before that. */
 
	if (CheckSavegameVersion(9)) {
 
		Town *t;
 
		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
 
	}
 

	
 
	/* From version 16.0, we included autorenew on engines, which are now saved, but
 
	 *  of course, we do need to initialize them for older savegames. */
 
	if (CheckSavegameVersion(16)) {
 
		FOR_ALL_PLAYERS(p) {
 
			p->engine_renew_list = NULL;
 
			p->engine_renew = false;
 
			p->engine_renew_months = -6;
 
			p->engine_renew_money = 100000;
 
		}
 
		if (_local_player < MAX_PLAYERS) {
 
		if (IsValidPlayer(_local_player)) {
 
			// Set the human controlled player to the patch settings
 
			// Scenario editor do not have any companies
 
			p = GetPlayer(_local_player);
 
			p->engine_renew = _patches.autorenew;
 
			p->engine_renew_months = _patches.autorenew_months;
 
			p->engine_renew_money = _patches.autorenew_money;
 
		}
 
	}
 

	
 
	/* Elrails got added in rev 24 */
 
	if (CheckSavegameVersion(24)) {
 
		Vehicle *v;
 
		uint i;
 
		TileIndex t;
 
		RailType min_rail = RAILTYPE_ELECTRIC;
 

	
 
		for (i = 0; i < lengthof(_engines); i++) {
 
			Engine *e = GetEngine(i);
 
			if (e->type == VEH_Train &&
 
					(e->railtype != RAILTYPE_RAIL || RailVehInfo(i)->engclass == 2)) {
 
				e->railtype++;
 
			}
 
		}
 

	
player.h
Show inline comments
 
@@ -224,48 +224,53 @@ VARDEF byte _player_colors[MAX_PLAYERS];
 

	
 
static inline byte ActivePlayerCount(void)
 
{
 
	const Player *p;
 
	byte count = 0;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active) count++;
 
	}
 

	
 
	return count;
 
}
 

	
 
static inline Player* GetPlayer(PlayerID i)
 
{
 
	assert(i < lengthof(_players));
 
	return &_players[i];
 
}
 

	
 
static inline bool IsLocalPlayer(void)
 
{
 
	return _local_player == _current_player;
 
}
 

	
 
static inline bool IsValidPlayer(PlayerID pi)
 
{
 
	return pi < MAX_PLAYERS;
 
}
 

	
 
void DeletePlayerWindows(PlayerID pi);
 
byte GetPlayerRailtypes(PlayerID p);
 

	
 
/** Finds out if a Player has a certain railtype available */
 
static inline bool HasRailtypeAvail(const Player *p, RailType Railtype)
 
{
 
	return HASBIT(p->avail_railtypes, Railtype);
 
}
 

	
 
static inline bool IsHumanPlayer(PlayerID pi)
 
{
 
	return !GetPlayer(pi)->is_ai;
 
}
 

	
 
static inline bool IsInteractivePlayer(PlayerID pi)
 
{
 
	return pi == _local_player;
 
}
 

	
 
/* Validate functions for rail building */
 
static inline bool ValParamRailtype(uint32 rail) { return HASBIT(GetPlayer(_current_player)->avail_railtypes, rail);}
 

	
 
/** Returns the "best" railtype a player can build.
 
 * As the AI doesn't know what the BEST one is, we have our own priority list
players.c
Show inline comments
 
@@ -183,109 +183,109 @@ void DrawPlayerFace(uint32 face, int col
 
	/* draw the glasses */
 
	{
 
		uint val = GB(face, 28, 3);
 

	
 
		if (flag & 2) {
 
			if (val <= 1) DrawSprite(0x3AE + val, x, y);
 
		} else {
 
			if (val <= 1) DrawSprite(0x347 + val, x, y);
 
		}
 
	}
 
}
 

	
 
void InvalidatePlayerWindows(const Player *p)
 
{
 
	PlayerID pid = p->index;
 

	
 
	if (pid == _local_player) InvalidateWindow(WC_STATUS_BAR, 0);
 
	InvalidateWindow(WC_FINANCES, pid);
 
}
 

	
 
bool CheckPlayerHasMoney(int32 cost)
 
{
 
	if (cost > 0) {
 
		PlayerID pid = _current_player;
 
		if (pid < MAX_PLAYERS && cost > GetPlayer(pid)->player_money) {
 
		if (IsValidPlayer(pid) && cost > GetPlayer(pid)->player_money) {
 
			SetDParam(0, cost);
 
			_error_message = STR_0003_NOT_ENOUGH_CASH_REQUIRES;
 
			return false;
 
		}
 
	}
 
	return true;
 
}
 

	
 
static void SubtractMoneyFromAnyPlayer(Player *p, int32 cost)
 
{
 
	p->money64 -= cost;
 
	UpdatePlayerMoney32(p);
 

	
 
	p->yearly_expenses[0][_yearly_expenses_type] += cost;
 

	
 
	if (HASBIT(1<<7|1<<8|1<<9|1<<10, _yearly_expenses_type)) {
 
		p->cur_economy.income -= cost;
 
	} else if (HASBIT(1<<2|1<<3|1<<4|1<<5|1<<6|1<<11, _yearly_expenses_type)) {
 
		p->cur_economy.expenses -= cost;
 
	}
 

	
 
	InvalidatePlayerWindows(p);
 
}
 

	
 
void SubtractMoneyFromPlayer(int32 cost)
 
{
 
	PlayerID pid = _current_player;
 

	
 
	if (pid < MAX_PLAYERS) SubtractMoneyFromAnyPlayer(GetPlayer(pid), cost);
 
	if (IsValidPlayer(pid)) SubtractMoneyFromAnyPlayer(GetPlayer(pid), cost);
 
}
 

	
 
void SubtractMoneyFromPlayerFract(PlayerID player, int32 cost)
 
{
 
	Player *p = GetPlayer(player);
 
	byte m = p->player_money_fraction;
 

	
 
	p->player_money_fraction = m - (byte)cost;
 
	cost >>= 8;
 
	if (p->player_money_fraction > m) 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(Owner owner, TileIndex tile)
 
{
 
	SetDParam(2, owner);
 

	
 
	if (owner != OWNER_TOWN) {
 
		if (owner >= MAX_PLAYERS) {
 
		if (!IsValidPlayer(owner)) {
 
			SetDParam(0, STR_0150_SOMEONE);
 
		} else {
 
			const Player* p = GetPlayer(owner);
 

	
 
			SetDParam(0, p->name_1);
 
			SetDParam(1, p->name_2);
 
		}
 
	} else {
 
		const Town* t = ClosestTownFromTile(tile, (uint)-1);
 

	
 
		SetDParam(0, STR_TOWN);
 
		SetDParam(1, t->index);
 
	}
 
}
 

	
 

	
 
bool CheckOwnership(PlayerID owner)
 
{
 
	assert(owner < OWNER_END);
 

	
 
	if (owner == _current_player) return true;
 
	_error_message = STR_013B_OWNED_BY;
 
	GetNameOfOwner(owner, 0);
 
	return false;
 
@@ -563,49 +563,49 @@ void InitializePlayers(void)
 
	uint i;
 

	
 
	memset(_players, 0, sizeof(_players));
 
	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;
 

	
 
	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 (IsHumanPlayer(player) && player < MAX_PLAYERS) {
 
	if (IsHumanPlayer(player) && IsValidPlayer(player)) {
 
		SetDParam(index, player+1);
 
		return STR_7002_PLAYER;
 
	}
 
	return STR_EMPTY;
 
}
 

	
 
extern void ShowPlayerFinances(int player);
 

	
 
void PlayersYearlyLoop(void)
 
{
 
	Player *p;
 

	
 
	// Copy statistics
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active) {
 
			memmove(&p->yearly_expenses[1], &p->yearly_expenses[0], sizeof(p->yearly_expenses) - sizeof(p->yearly_expenses[0]));
 
			memset(&p->yearly_expenses[0], 0, sizeof(p->yearly_expenses[0]));
 
			InvalidateWindow(WC_FINANCES, p->index);
 
		}
 
	}
 

	
 
	if (_patches.show_finances && _local_player != PLAYER_SPECTATOR) {
 
		ShowPlayerFinances(_local_player);
 
		p = GetPlayer(_local_player);
 
@@ -670,50 +670,49 @@ static void DeletePlayerStuff(PlayerID p
 
 * - p1 = 2 - change auto renew money
 
 * - p1 = 3 - change auto renew array
 
 * - p1 = 4 - change bool, months & money all together
 
 * - p1 = 5 - change renew_keep_length
 
 * @param p2 value to set
 
 * if p1 = 0, then:
 
 * - p2 = enable engine renewal
 
 * if p1 = 1, then:
 
 * - p2 = months left before engine expires to replace it
 
 * if p1 = 2, then
 
 * - p2 = minimum amount of money available
 
 * if p1 = 3, then:
 
 * - p2 bits  0-15 = old engine type
 
 * - p2 bits 16-31 = new engine type
 
 * if p1 = 4, then:
 
 * - p1 bit     15 = enable engine renewal
 
 * - p1 bits 16-31 = months left before engine expires to replace it
 
 * - p2 bits  0-31 = minimum amount of money available
 
 * if p1 = 5, then
 
 * - p2 = enable renew_keep_length
 
 */
 
int32 CmdSetAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Player *p;
 
	if (!(_current_player < MAX_PLAYERS))
 
		return CMD_ERROR;
 
	if (!IsValidPlayer(_current_player)) return CMD_ERROR;
 

	
 
	p = GetPlayer(_current_player);
 
	switch (GB(p1, 0, 3)) {
 
		case 0:
 
			if (p->engine_renew == (bool)GB(p2, 0, 1))
 
				return CMD_ERROR;
 

	
 
			if (flags & DC_EXEC) {
 
				p->engine_renew = (bool)GB(p2, 0, 1);
 
				if (IsLocalPlayer()) {
 
					_patches.autorenew = p->engine_renew;
 
					InvalidateWindow(WC_GAME_OPTIONS, 0);
 
				}
 
			}
 
			break;
 
		case 1:
 
			if (p->engine_renew_months == (int16)p2)
 
				return CMD_ERROR;
 

	
 
			if (flags & DC_EXEC) {
 
				p->engine_renew_months = (int16)p2;
 
				if (IsLocalPlayer()) {
 
					_patches.autorenew_months = p->engine_renew_months;
 
					InvalidateWindow(WC_GAME_OPTIONS, 0);
 
@@ -803,49 +802,49 @@ int32 CmdSetAutoReplace(TileIndex tile, 
 
 * - p1 = 1 - create a new AI player
 
 * - p1 = 2 - delete a player. Player is identified by p2
 
 * - p1 = 3 - merge two companies together. Player to merge #1 with player #2. Identified by p2
 
 * @param p2 various functionality, dictated by p1
 
 * - p1 = 0 - ClientID of the newly created player
 
 * - 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;
 
		if (!(flags & DC_EXEC) || !IsValidPlayer(pid)) return 0;
 

	
 
		p = DoStartupNewPlayer(false);
 

	
 
#ifdef ENABLE_NETWORK
 
		if (_networking && !_network_server && _local_player == PLAYER_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 == PLAYER_SPECTATOR &&
 
					(!_ai.network_client || _ai.network_playas == PLAYER_SPECTATOR)) {
 
				/* Check if we do not want to be a spectator in network */
 
				if (!_networking ||
 
						(_network_server && !_network_dedicated) ||
 
						_network_playas != PLAYER_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      = PLAYER_SPECTATOR;
 
						if (_ai.network_playas != PLAYER_SPECTATOR) {
 
							/* If we didn't join the game as a spectator, activate the AI */
 
@@ -889,77 +888,77 @@ int32 CmdPlayerCtrl(TileIndex tile, uint
 
					_local_player = player_backup;
 
				}
 
			}
 
		} else if (_network_server) {
 
			// Creating player failed, defer client to spectator
 
			/* 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 = PLAYER_SPECTATOR;
 
			NetworkUpdateClientInfo(ci->client_index);
 
#endif /* ENABLE_NETWORK */
 
		}
 
	} break;
 

	
 
	case 1: /* Make a new AI player */
 
		if (!(flags & DC_EXEC)) return 0;
 

	
 
		DoStartupNewPlayer(true);
 
		break;
 

	
 
	case 2: { /* Delete a player */
 
		Player *p;
 

	
 
		if (p2 >= MAX_PLAYERS) return CMD_ERROR;
 
		if (!IsValidPlayer(p2)) return CMD_ERROR;
 

	
 
		if (!(flags & DC_EXEC)) return 0;
 

	
 
		p = GetPlayer(p2);
 

	
 
		/* Only allow removal of HUMAN companies */
 
		if (IsHumanPlayer(p->index)) {
 
			/* Delete any open window of the company */
 
			DeletePlayerWindows(p->index);
 

	
 
			/* Show the bankrupt news */
 
			SetDParam(0, p->name_1);
 
			SetDParam(1, p->name_2);
 
			AddNewsItem( (StringID)(p->index + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
			/* Remove the company */
 
			ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
 
			p->is_active = false;
 
		}
 
		RemoveAllEngineReplacementForPlayer(p);
 

	
 
	} break;
 

	
 
	case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
 
		PlayerID pid_old = GB(p2,  0, 16);
 
		PlayerID pid_new = GB(p2, 16, 16);
 

	
 
		if (pid_old >= MAX_PLAYERS || pid_new >= MAX_PLAYERS) return CMD_ERROR;
 
		if (!IsValidPlayer(pid_old) || !IsValidPlayer(pid_new)) return CMD_ERROR;
 

	
 
		if (!(flags & DC_EXEC)) return CMD_ERROR;
 

	
 
		ChangeOwnershipOfPlayerItems(pid_old, pid_new);
 
		DeletePlayerStuff(pid_old);
 
	} break;
 
	default: return CMD_ERROR;
 
	}
 

	
 
	return 0;
 
}
 

	
 
static const StringID _endgame_perf_titles[] = {
 
	STR_0213_BUSINESSMAN,
 
	STR_0213_BUSINESSMAN,
 
	STR_0213_BUSINESSMAN,
 
	STR_0213_BUSINESSMAN,
 
	STR_0213_BUSINESSMAN,
 
	STR_0214_ENTREPRENEUR,
 
	STR_0214_ENTREPRENEUR,
 
	STR_0215_INDUSTRIALIST,
 
	STR_0215_INDUSTRIALIST,
 
	STR_0216_CAPITALIST,
 
	STR_0216_CAPITALIST,
road_cmd.c
Show inline comments
 
@@ -24,49 +24,49 @@
 

	
 

	
 
static uint CountRoadBits(RoadBits r)
 
{
 
	uint count = 0;
 

	
 
	if (r & ROAD_NW) ++count;
 
	if (r & ROAD_SW) ++count;
 
	if (r & ROAD_SE) ++count;
 
	if (r & ROAD_NE) ++count;
 
	return count;
 
}
 

	
 

	
 
static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool* edge_road)
 
{
 
	RoadBits present;
 
	RoadBits n;
 
	Owner owner;
 
	*edge_road = true;
 

	
 
	if (_game_mode == GM_EDITOR) return true;
 

	
 
	// Only do the special processing for actual players.
 
	if (_current_player >= MAX_PLAYERS) return true;
 
	if (!IsValidPlayer(_current_player)) return true;
 

	
 
	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
 

	
 
	// Only do the special processing if the road is owned
 
	// by a town
 
	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
 

	
 
	if (_cheats.magic_bulldozer.value) return true;
 

	
 
	// Get a bitmask of which neighbouring roads has a tile
 
	n = 0;
 
	present = GetAnyRoadBits(tile);
 
	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile,-1, 0)) & ROAD_SW) n |= ROAD_NE;
 
	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE;
 
	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW;
 
	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0,-1)) & ROAD_SE) n |= ROAD_NW;
 

	
 
	// If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
 
	// then allow it
 
	if ((n & (n - 1)) != 0 && (n & remove) != 0) {
 
		Town *t;
 
		*edge_road = false;
 
		// you can remove all kind of roads with extra dynamite
 
		if (_patches.extra_dynamite) return true;
 
@@ -268,49 +268,49 @@ static uint32 CheckRoadSlope(Slope tileh
 
		*pieces |= (*pieces & 0xC) >> 2;
 
		*pieces |= (*pieces & 0x3) << 2;
 
		if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
 
	}
 
	return CMD_ERROR;
 
}
 

	
 
/** Build a piece of road.
 
 * @param tile tile where to build road
 
 * @param p1 road piece flags
 
 * @param p2 the town that is building the road (0 if not applicable)
 
 */
 
int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	int32 cost = 0;
 
	int32 ret;
 
	RoadBits existing = 0;
 
	RoadBits pieces;
 
	Slope tileh;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 

	
 
	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
 
	 * if a non-player is building the road */
 
	if ((p1 >> 4) || (_current_player < MAX_PLAYERS && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
 
	if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
 
	pieces = p1;
 

	
 
	tileh = GetTileSlope(tile, NULL);
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_STREET:
 
			switch (GetRoadTileType(tile)) {
 
				case ROAD_TILE_NORMAL:
 
					if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
 

	
 
					existing = GetRoadBits(tile);
 
					if ((existing & pieces) == pieces) {
 
						return_cmd_error(STR_1007_ALREADY_BUILT);
 
					}
 
					if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 
					break;
 

	
 
				case ROAD_TILE_CROSSING:
 
					if (pieces != GetCrossingRoadBits(tile)) { // XXX is this correct?
 
						return_cmd_error(STR_1007_ALREADY_BUILT);
 
					}
 
					goto do_clear;
 

	
 
				default:
station_cmd.c
Show inline comments
 
@@ -1003,49 +1003,49 @@ int32 CmdBuildRailroadStation(TileIndex 
 
		if (st != NULL && st->facilities) st = NULL;
 
	}
 

	
 
	if (st != NULL) {
 
		// Reuse an existing station.
 
		if (st->owner != OWNER_NONE && st->owner != _current_player)
 
			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
 

	
 
		if (st->train_tile != 0) {
 
			// check if we want to expanding an already existing station?
 
			if (_is_old_ai_player || !_patches.join_stations)
 
				return_cmd_error(STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD);
 
			if (!CanExpandRailroadStation(st, finalvalues, axis))
 
				return CMD_ERROR;
 
		}
 

	
 
		//XXX can't we pack this in the "else" part of the if above?
 
		if (!CheckStationSpreadOut(st, tile_org, w_org, h_org)) return CMD_ERROR;
 
	} else {
 
		// Create a new station
 
		st = AllocateStation();
 
		if (st == NULL) return CMD_ERROR;
 

	
 
		st->town = ClosestTownFromTile(tile_org, (uint)-1);
 
		if (_current_player < MAX_PLAYERS && flags & DC_EXEC)
 
		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
 
			SETBIT(st->town->have_ratings, _current_player);
 

	
 
		if (!GenerateStationName(st, tile_org, 0)) return CMD_ERROR;
 

	
 
		if (flags & DC_EXEC) StationInitialize(st, tile_org);
 
	}
 

	
 
	/* Check if the given station class is valid */
 
	if (GB(p2, 8, 8) >= STAT_CLASS_MAX) return CMD_ERROR;
 

	
 
	/* Check if we can allocate a custom stationspec to this station */
 
	statspec = GetCustomStationSpec(GB(p2, 8, 8), GB(p2, 16, 8));
 
	specindex = AllocateSpecToStation(statspec, st, flags & DC_EXEC);
 
	if (specindex == -1) return CMD_ERROR;
 

	
 
	if (statspec != NULL) {
 
		/* Perform NewStation checks */
 

	
 
		/* Check if the station size is permitted */
 
		if (HASBIT(statspec->disallowed_platforms, numtracks - 1) || HASBIT(statspec->disallowed_lengths, plat_len - 1)) {
 
			return CMD_ERROR;
 
		}
 

	
 
		/* Check if the station is buildable */
 
@@ -1431,49 +1431,49 @@ int32 CmdBuildRoadStop(TileIndex tile, u
 

	
 
	if (st != NULL &&
 
			GetNumRoadStopsInStation(st, RS_BUS) + GetNumRoadStopsInStation(st, RS_TRUCK) >= ROAD_STOP_LIMIT) {
 
		return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
 
	}
 

	
 
	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;
 

	
 
		FindRoadStopSpot(type, st, &currstop, &prev);
 
	} else {
 
		Town *t;
 

	
 
		st = AllocateStation();
 
		if (st == NULL) return CMD_ERROR;
 

	
 
		st->town = t = ClosestTownFromTile(tile, (uint)-1);
 

	
 
		FindRoadStopSpot(type, st, &currstop, &prev);
 

	
 
		if (_current_player < MAX_PLAYERS && flags & DC_EXEC) {
 
		if (IsValidPlayer(_current_player) && (flags & DC_EXEC)) {
 
			SETBIT(t->have_ratings, _current_player);
 
		}
 

	
 
		st->sign.width_1 = 0;
 

	
 
		if (!GenerateStationName(st, tile, 0)) return CMD_ERROR;
 

	
 
		if (flags & DC_EXEC) StationInitialize(st, tile);
 
	}
 

	
 
	cost += (type) ? _price.build_truck_station : _price.build_bus_station;
 

	
 
	if (flags & DC_EXEC) {
 
		//point to the correct item in the _busstops or _truckstops array
 
		*currstop = road_stop;
 

	
 
		//initialize an empty station
 
		InitializeRoadStop(road_stop, prev, tile, st->index);
 
		if (!st->facilities) st->xy = tile;
 
		st->facilities |= (type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP;
 
		st->owner = _current_player;
 

	
 
		st->build_date = _date;
 

	
 
@@ -1677,49 +1677,49 @@ int32 CmdBuildAirport(TileIndex tile, ui
 

	
 
	/* 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->airport_tile != 0)
 
			return_cmd_error(STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT);
 
	} else {
 
		airport_upgrade = false;
 

	
 
		st = AllocateStation();
 
		if (st == NULL) return CMD_ERROR;
 

	
 
		st->town = t;
 

	
 
		if (_current_player < MAX_PLAYERS && flags & DC_EXEC)
 
		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
 
			SETBIT(t->have_ratings, _current_player);
 

	
 
		st->sign.width_1 = 0;
 

	
 
		// if airport type equals Heliport then generate
 
		// type 5 name, which is heliport, otherwise airport names (1)
 
		if (!GenerateStationName(st, tile, (p1 == AT_HELIPORT)||(p1 == AT_HELIDEPOT)||(p1 == AT_HELISTATION) ? 5 : 1))
 
			return CMD_ERROR;
 

	
 
		if (flags & DC_EXEC) StationInitialize(st, tile);
 
	}
 

	
 
	cost += _price.build_airport * w * h;
 

	
 
	if (flags & DC_EXEC) {
 
		st->owner = _current_player;
 
		st->airport_tile = tile;
 
		if (!st->facilities) st->xy = tile;
 
		st->facilities |= FACIL_AIRPORT;
 
		st->airport_type = (byte)p1;
 
		st->airport_flags = 0;
 

	
 
		st->build_date = _date;
 

	
 
@@ -1838,52 +1838,50 @@ int32 CmdBuildBuoy(TileIndex tile, uint3
 
	return _price.build_dock;
 
}
 

	
 
/* Checks if any ship is servicing the buoy specified. Returns yes or no */
 
static bool CheckShipsOnBuoy(Station *st)
 
{
 
	const Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_Ship) {
 
			const Order *order;
 
			FOR_VEHICLE_ORDERS(v, order) {
 
				if (order->type == OT_GOTO_STATION && order->dest == st->index) {
 
					return true;
 
				}
 
			}
 
		}
 
	}
 
	return false;
 
}
 

	
 
static int32 RemoveBuoy(Station *st, uint32 flags)
 
{
 
	TileIndex tile;
 

	
 
	if (_current_player >= MAX_PLAYERS) {
 
		/* XXX: strange stuff */
 
		return_cmd_error(INVALID_STRING_ID);
 
	}
 
	if (!IsValidPlayer(_current_player))  return_cmd_error(INVALID_STRING_ID);
 

	
 
	tile = st->dock_tile;
 

	
 
	if (CheckShipsOnBuoy(st))   return_cmd_error(STR_BUOY_IS_IN_USE);
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		st->dock_tile = 0;
 
		/* Buoys are marked in the Station struct by this flag. Yes, it is this
 
		 * braindead.. */
 
		st->facilities &= ~FACIL_DOCK;
 
		st->had_vehicle_of_type &= ~HVOT_BUOY;
 

	
 
		MakeWater(tile);
 
		MarkTileDirtyByTile(tile);
 

	
 
		UpdateStationVirtCoordDirty(st);
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return _price.remove_truck_station;
 
}
 

	
 
static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
 
@@ -1946,49 +1944,49 @@ int32 CmdBuildDock(TileIndex tile, uint3
 
		_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 {
 
		Town *t;
 

	
 
		st = AllocateStation();
 
		if (st == NULL) return CMD_ERROR;
 

	
 
		st->town = t = ClosestTownFromTile(tile, (uint)-1);
 

	
 
		if (_current_player < MAX_PLAYERS && flags&DC_EXEC)
 
		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
 
			SETBIT(t->have_ratings, _current_player);
 

	
 
		st->sign.width_1 = 0;
 

	
 
		if (!GenerateStationName(st, tile, 3)) return CMD_ERROR;
 

	
 
		if (flags & DC_EXEC) StationInitialize(st, tile);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		st->dock_tile = tile;
 
		if (!st->facilities) st->xy = tile;
 
		st->facilities |= FACIL_DOCK;
 
		st->owner = _current_player;
 

	
 
		st->build_date = _date;
 

	
 
		MakeDock(tile, st->owner, st->index, direction);
 

	
 
		UpdateStationVirtCoordDirty(st);
 
		UpdateStationAcceptance(st, false);
 
		RebuildStationLists();
 
		InvalidateWindow(WC_STATION_LIST, st->owner);
 
	}
 
@@ -2023,49 +2021,49 @@ static int32 RemoveDock(Station *st, uin
 

	
 
	return _price.remove_dock;
 
}
 

	
 
#include "table/station_land.h"
 

	
 
const DrawTileSprites *GetStationTileLayout(byte gfx)
 
{
 
	return &_station_display_datas[gfx];
 
}
 

	
 
static void DrawTile_Station(TileInfo *ti)
 
{
 
	uint32 image;
 
	const DrawTileSeqStruct *dtss;
 
	const DrawTileSprites *t = NULL;
 
	RailType railtype = GetRailType(ti->tile);
 
	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
 
	uint32 relocation = 0;
 
	const Station *st = NULL;
 
	const StationSpec *statspec = NULL;
 
	PlayerID owner = GetTileOwner(ti->tile);
 
	uint32 palette;
 

	
 
	if (owner < MAX_PLAYERS) {
 
	if (IsValidPlayer(owner)) {
 
		palette = PLAYER_SPRITE_COLOR(owner);
 
	} else {
 
		// Some stations are not owner by a player, namely oil rigs
 
		palette = PALETTE_TO_GREY;
 
	}
 

	
 
	// don't show foundation for docks
 
	if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile))
 
		DrawFoundation(ti, ti->tileh);
 

	
 
	if (IsCustomStationSpecIndex(ti->tile)) {
 
		// look for customization
 
		st = GetStationByTile(ti->tile);
 
		statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
 

	
 
		//debug("Cust-o-mized %p", statspec);
 

	
 
		if (statspec != NULL) {
 
			uint tile = GetStationGfx(ti->tile);
 

	
 
			relocation = GetCustomStationRelocation(statspec, st, ti->tile);
 

	
 
			if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
 
				uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
 
@@ -2379,98 +2377,97 @@ void DestroyStation(Station *st)
 

	
 
	index = st->index;
 

	
 
	DeleteName(st->string_id);
 
	MarkStationDirty(st);
 
	RebuildStationLists();
 
	InvalidateWindowClasses(WC_STATION_LIST);
 

	
 
	DeleteWindowById(WC_STATION_VIEW, index);
 

	
 
	/* Now delete all orders that go to the station */
 
	RemoveOrderFromAllVehicles(OT_GOTO_STATION, index);
 

	
 
	//Subsidies need removal as well
 
	DeleteSubsidyWithStation(index);
 

	
 
	free(st->speclist);
 
}
 

	
 
void DeleteAllPlayerStations(void)
 
{
 
	Station *st;
 

	
 
	FOR_ALL_STATIONS(st) {
 
		if (st->owner < MAX_PLAYERS) DeleteStation(st);
 
		if (IsValidPlayer(st->owner)) DeleteStation(st);
 
	}
 
}
 

	
 
/* this function is called for one station each tick */
 
static void StationHandleBigTick(Station *st)
 
{
 
	UpdateStationAcceptance(st, true);
 

	
 
	if (st->facilities == 0 && ++st->delete_ctr >= 8) DeleteStation(st);
 

	
 
}
 

	
 
static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; }
 

	
 
static void UpdateStationRating(Station *st)
 
{
 
	GoodsEntry *ge;
 
	int rating;
 
	StationID index;
 
	int waiting;
 
	bool waiting_changed = false;
 

	
 
	byte_inc_sat(&st->time_since_load);
 
	byte_inc_sat(&st->time_since_unload);
 

	
 
	ge = st->goods;
 
	do {
 
		if (ge->enroute_from != INVALID_STATION) {
 
			byte_inc_sat(&ge->enroute_time);
 
			byte_inc_sat(&ge->days_since_pickup);
 

	
 
			rating = 0;
 

	
 
			{
 
				int b = ge->last_speed;
 
				if ((b-=85) >= 0)
 
					rating += b >> 2;
 
			}
 

	
 
			{
 
				byte age = ge->last_age;
 
				(age >= 3) ||
 
				(rating += 10, age >= 2) ||
 
				(rating += 10, age >= 1) ||
 
				(rating += 13, true);
 
			}
 

	
 
			if (st->owner < MAX_PLAYERS && HASBIT(st->town->statues, st->owner))
 
				rating += 26;
 
			if (IsValidPlayer(st->owner) && HASBIT(st->town->statues, st->owner)) rating += 26;
 

	
 
			{
 
				byte days = ge->days_since_pickup;
 
				if (st->last_vehicle_type == VEH_Ship)
 
							days >>= 2;
 
				(days > 21) ||
 
				(rating += 25, days > 12) ||
 
				(rating += 25, days > 6) ||
 
				(rating += 45, days > 3) ||
 
				(rating += 35, true);
 
			}
 

	
 
			{
 
				waiting = GB(ge->waiting_acceptance, 0, 12);
 
				(rating -= 90, waiting > 1500) ||
 
				(rating += 55, waiting > 1000) ||
 
				(rating += 35, waiting > 600) ||
 
				(rating += 10, waiting > 300) ||
 
				(rating += 20, waiting > 100) ||
 
				(rating += 10, true);
 
			}
 

	
 
			{
 
				int or = ge->rating; // old rating
town_cmd.c
Show inline comments
 
@@ -334,49 +334,49 @@ static void TileLoop_Town(TileIndex tile
 
}
 

	
 
static void ClickTile_Town(TileIndex tile)
 
{
 
	/* not used */
 
}
 

	
 
static int32 ClearTile_Town(TileIndex tile, byte flags)
 
{
 
	int house, rating;
 
	int32 cost;
 
	Town *t;
 

	
 
	// safety checks
 
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 
	if (flags&DC_AUTO && !(flags&DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
 

	
 
	house = GetHouseType(tile);
 
	cost = _price.remove_house * _housetype_remove_cost[house] >> 8;
 

	
 
	rating = _housetype_remove_ratingmod[house];
 
	_cleared_town_rating += rating;
 
	_cleared_town = t = GetTownByTile(tile);
 

	
 
	if (_current_player < MAX_PLAYERS) {
 
	if (IsValidPlayer(_current_player)) {
 
		if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
 
			SetDParam(0, t->index);
 
			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM);
 
		ClearTownHouse(t, tile);
 
	}
 

	
 
	return cost;
 
}
 

	
 
static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
 
{
 
	byte type = GetHouseType(tile);
 

	
 
	ac[CT_PASSENGERS] = _housetype_cargo_passengers[type];
 
	ac[CT_MAIL]       = _housetype_cargo_mail[type];
 
	ac[CT_GOODS]      = _housetype_cargo_goods[type];
 
	ac[CT_FOOD]       = _housetype_cargo_food[type];
 
}
 

	
 
@@ -1609,52 +1609,52 @@ int32 CmdDoTownAction(TileIndex tile, ui
 
	}
 

	
 
	return cost;
 
}
 

	
 
static void UpdateTownGrowRate(Town *t)
 
{
 
	int n;
 
	Station *st;
 
	byte m;
 
	Player *p;
 

	
 
	// Reset player ratings if they're low
 
	FOR_ALL_PLAYERS(p) {
 
		if (p->is_active && t->ratings[p->index] <= 200) {
 
			t->ratings[p->index] += 5;
 
		}
 
	}
 

	
 
	n = 0;
 
	FOR_ALL_STATIONS(st) {
 
		if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) {
 
			if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
 
				n++;
 
				if (st->owner < MAX_PLAYERS && t->ratings[st->owner] <= 1000-12)
 
				if (IsValidPlayer(st->owner) && t->ratings[st->owner] <= 1000-12)
 
					t->ratings[st->owner] += 12;
 
			} else {
 
				if (st->owner < MAX_PLAYERS && t->ratings[st->owner] >= -1000+15)
 
				if (IsValidPlayer(st->owner) && t->ratings[st->owner] >= -1000+15)
 
					t->ratings[st->owner] -= 15;
 
			}
 
		}
 
	}
 

	
 
	CLRBIT(t->flags12, TOWN_IS_FUNDED);
 

	
 
	if (t->fund_buildings_months != 0) {
 
		static const byte _grow_count_values[6] = {
 
			60, 60, 60, 50, 40, 30
 
		};
 
		m = _grow_count_values[min(n, 5)];
 
		t->fund_buildings_months--;
 
	} else if (n == 0) {
 
		m = 160;
 
		if (!CHANCE16(1, 12))
 
			return;
 
	} else {
 
		static const byte _grow_count_values[5] = {
 
			210, 150, 110, 80, 50
 
		};
 
		m = _grow_count_values[min(n, 5) - 1];
 
	}
 

	
 
@@ -1683,49 +1683,49 @@ static void UpdateTownAmounts(Town *t)
 
	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)
 
{
 
	const Player* p;
 

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

	
 
bool CheckIfAuthorityAllows(TileIndex tile)
 
{
 
	Town *t;
 

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

	
 
	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 
	if (t == NULL) 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) {
 
		dist = DistanceManhattan(tile, t->xy);
 
		if (dist < best) {
 
			best = dist;
 
			best_town = t;
 
@@ -1734,85 +1734,85 @@ Town* CalcClosestTownFromTile(TileIndex 
 

	
 
	return best_town;
 
}
 

	
 

	
 
Town *ClosestTownFromTile(TileIndex tile, uint threshold)
 
{
 
	if (IsTileType(tile, MP_HOUSE) || (
 
				IsTileType(tile, MP_STREET) &&
 
				(IsLevelCrossing(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile)) == OWNER_TOWN
 
			)) {
 
		return GetTownByTile(tile);
 
	} else {
 
		return CalcClosestTownFromTile(tile, threshold);
 
	}
 
}
 

	
 

	
 
void ChangeTownRating(Town *t, int add, int max)
 
{
 
	int rating;
 

	
 
	// if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff
 
	if (t == NULL ||
 
			_current_player >= MAX_PLAYERS ||
 
			!IsValidPlayer(_current_player) ||
 
			(_cheats.magic_bulldozer.value && add < 0)) {
 
		return;
 
	}
 

	
 
	SETBIT(t->have_ratings, _current_player);
 

	
 
	rating = t->ratings[_current_player];
 

	
 
	if (add < 0) {
 
		if (rating > max) {
 
			rating += add;
 
			if (rating < max) rating = max;
 
		}
 
	} else {
 
		if (rating < max) {
 
			rating += add;
 
			if (rating > max) rating = max;
 
		}
 
	}
 
	t->ratings[_current_player] = rating;
 
}
 

	
 
/* penalty for removing town-owned stuff */
 
static const int _default_rating_settings [3][3] = {
 
	// ROAD_REMOVE, TUNNELBRIDGE_REMOVE, INDUSTRY_REMOVE
 
	{  0, 128, 384}, // Permissive
 
	{ 48, 192, 480}, // Neutral
 
	{ 96, 384, 768}, // Hostile
 
};
 

	
 
bool CheckforTownRating(uint32 flags, Town *t, byte type)
 
{
 
	int modemod;
 

	
 
	// if magic_bulldozer cheat is active, town doesn't restrict your destructive actions
 
	if (t == NULL || _current_player >= MAX_PLAYERS || _cheats.magic_bulldozer.value)
 
	if (t == NULL || !IsValidPlayer(_current_player) || _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->road_build_months != 0) t->road_build_months--;
 

	
tree_cmd.c
Show inline comments
 
@@ -244,49 +244,49 @@ int32 CmdPlantTree(TileIndex tile, uint3
 
					if (flags & DC_EXEC) {
 
						AddTreeCount(tile, 1);
 
						MarkTileDirtyByTile(tile);
 
					}
 
					// 2x as expensive to add more trees to an existing tile
 
					cost += _price.build_trees * 2;
 
					break;
 

	
 
				case MP_CLEAR:
 
					if (!IsTileOwner(tile, OWNER_NONE)) {
 
						msg = STR_2804_SITE_UNSUITABLE;
 
						continue;
 
					}
 

	
 
					switch (GetClearGround(tile)) {
 
						case CLEAR_FIELDS: cost += _price.clear_3; break;
 
						case CLEAR_ROCKS:  cost += _price.clear_2; break;
 
						default: break;
 
					}
 

	
 
					if (flags & DC_EXEC) {
 
						TreeType treetype;
 
						uint growth;
 

	
 
						if (_game_mode != GM_EDITOR && _current_player < MAX_PLAYERS) {
 
						if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) {
 
							Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 
							if (t != NULL)
 
								ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
 
						}
 

	
 
						treetype = p1;
 
						if (treetype == TREE_INVALID) {
 
							treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
 
							if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
 
						}
 

	
 
						growth = _game_mode == GM_EDITOR ? 3 : 0;
 
						switch (GetClearGround(tile)) {
 
							case CLEAR_ROUGH: MakeTree(tile, treetype, 0, growth, TREE_GROUND_ROUGH, 0); break;
 
							case CLEAR_SNOW:  MakeTree(tile, treetype, 0, growth, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
 
							default:          MakeTree(tile, treetype, 0, growth, TREE_GROUND_GRASS, 0); break;
 
						}
 
						MarkTileDirtyByTile(tile);
 

	
 
						if (_game_mode == GM_EDITOR && IS_INT_INSIDE(treetype, TREE_RAINFOREST, TREE_CACTUS))
 
							SetTropicZone(tile, TROPICZONE_RAINFOREST);
 
					}
 
					cost += _price.build_trees;
 
					break;
 
@@ -394,49 +394,49 @@ static void DrawTile_Trees(TileInfo *ti)
 
		}
 
	}
 

	
 
	EndSpriteCombine();
 
}
 

	
 

	
 
static uint GetSlopeZ_Trees(TileIndex tile, uint x, uint y)
 
{
 
	uint z;
 
	uint tileh = GetTileSlope(tile, &z);
 

	
 
	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
 
}
 

	
 
static Slope GetSlopeTileh_Trees(TileIndex tile, Slope tileh)
 
{
 
	return tileh;
 
}
 

	
 
static int32 ClearTile_Trees(TileIndex tile, byte flags)
 
{
 
	uint num;
 

	
 
	if (flags & DC_EXEC && _current_player < MAX_PLAYERS) {
 
	if ((flags & DC_EXEC) && IsValidPlayer(_current_player)) {
 
		Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 
		if (t != NULL)
 
			ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM);
 
	}
 

	
 
	num = GetTreeCount(tile) + 1;
 
	if (IS_INT_INSIDE(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4;
 

	
 
	if (flags & DC_EXEC) DoClearSquare(tile);
 

	
 
	return num * _price.remove_trees;
 
}
 

	
 
static void GetAcceptedCargo_Trees(TileIndex tile, AcceptedCargo ac)
 
{
 
	/* not used */
 
}
 

	
 
static void GetTileDesc_Trees(TileIndex tile, TileDesc *td)
 
{
 
	TreeType tt = GetTreeType(tile);
 

	
 
	if (IS_INT_INSIDE(tt, TREE_RAINFOREST, TREE_CACTUS)) {
 
		td->str = STR_280F_RAINFOREST;
tunnelbridge_cmd.c
Show inline comments
 
@@ -402,49 +402,49 @@ not_valid_below:;
 
					} else {
 
						SetCanalUnderBridge(tile, owner_under);
 
					}
 
					break;
 

	
 
				default: SetClearUnderBridge(tile); break;
 
			}
 

	
 
			MarkTileDirtyByTile(tile);
 
		}
 
	}
 

	
 
	SetSignalsOnBothDir(tile_start, AxisToTrack(direction));
 
	YapfNotifyTrackLayoutChange(tile_start, AxisToTrack(direction));
 

	
 
	/* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
 
	 * It's unnecessary to execute this command every time for every bridge. So it is done only
 
	 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
 
	 */
 
	if (!(flags & DC_QUERY_COST)) {
 
		const Bridge *b = &_bridge[bridge_type];
 

	
 
		bridge_len += 2; // begin and end tiles/ramps
 

	
 
		if (_current_player < MAX_PLAYERS && !_is_old_ai_player)
 
		if (IsValidPlayer(_current_player) && !_is_old_ai_player)
 
			bridge_len = CalcBridgeLenCostFactor(bridge_len);
 

	
 
		cost += (int64)bridge_len * _price.build_bridge * b->price >> 8;
 
	}
 

	
 
	return cost;
 
}
 

	
 

	
 
/** Build Tunnel.
 
 * @param tile start tile of tunnel
 
 * @param p1 railtype, 0x200 for road tunnel
 
 * @param p2 unused
 
 */
 
int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	TileIndexDiff delta;
 
	TileIndex end_tile;
 
	DiagDirection direction;
 
	Slope start_tileh;
 
	Slope end_tileh;
 
	uint start_z;
 
	uint end_z;
 
	int32 cost;
0 comments (0 inline, 0 general)