(svn r2300) - CodeChange: check the last number of commands, now only the refit ones remain, and some server-only commands.

- CodeChange: remove cmd-misuses CmdStartScenario() and CmdDestroyCompanyHQ()
- Fix (invisible): when parameter checking CmdRestoreOrderIndex() the vehicle did not have its orders yet, so it would fail. So move doing this until AFTER the orders have been added back in RestoreVehicleOrders()
replace/41b28d7194a279bdc17475d4fbe2ea6ec885a466
Darkvater 19 years ago
parent 56e7e4cf25
commit 033995ec6e

@ -322,18 +322,21 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} }
/* /** Levels a selected (rectangle) area of land
* p1 - start * @param x,y end tile of area-drag
* @param p1 start tile of area drag
* @param p2 unused
*/ */
int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2) int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{ {
int size_x, size_y; int size_x, size_y;
int sx, sy; int sx, sy;
uint h, curh; uint h, curh;
uint tile; TileIndex tile;
int32 ret, cost, money; int32 ret, cost, money;
if (p1 > MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// remember level height // remember level height
@ -354,11 +357,11 @@ int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
money = GetAvailableMoneyForCommand(); money = GetAvailableMoneyForCommand();
cost = 0; cost = 0;
BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
curh = TileHeight(tile2); curh = TileHeight(tile2);
while (curh != h) { while (curh != h) {
ret = DoCommandByTile(tile2, 8, (curh > h)?0:1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND); ret = DoCommandByTile(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
if (ret == CMD_ERROR) break; if (CmdFailed(ret)) break;
cost += ret; cost += ret;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
@ -366,15 +369,14 @@ int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
_additional_cash_required = ret; _additional_cash_required = ret;
return cost - ret; return cost - ret;
} }
DoCommandByTile(tile2, 8, (curh > h)?0:1, flags, CMD_TERRAFORM_LAND); DoCommandByTile(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
} }
curh += (curh > h) ? -1 : 1; curh += (curh > h) ? -1 : 1;
} }
END_TILE_LOOP(tile2, size_x, size_y, tile) } END_TILE_LOOP(tile2, size_x, size_y, tile)
if (cost == 0) return CMD_ERROR; return (cost == 0) ? CMD_ERROR : cost;
return cost;
} }
/** Purchase a land area. Actually you only purchase one tile, so /** Purchase a land area. Actually you only purchase one tile, so

@ -77,7 +77,6 @@ DEF_COMMAND(CmdRestoreOrderIndex);
DEF_COMMAND(CmdBuildIndustry); DEF_COMMAND(CmdBuildIndustry);
DEF_COMMAND(CmdBuildCompanyHQ); DEF_COMMAND(CmdBuildCompanyHQ);
DEF_COMMAND(CmdDestroyCompanyHQ);
DEF_COMMAND(CmdSetPlayerFace); DEF_COMMAND(CmdSetPlayerFace);
DEF_COMMAND(CmdSetPlayerColor); DEF_COMMAND(CmdSetPlayerColor);
@ -149,8 +148,6 @@ DEF_COMMAND(CmdLevelLand);
DEF_COMMAND(CmdRefitRailVehicle); DEF_COMMAND(CmdRefitRailVehicle);
DEF_COMMAND(CmdStartScenario);
DEF_COMMAND(CmdBuildSignalTrack); DEF_COMMAND(CmdBuildSignalTrack);
DEF_COMMAND(CmdRemoveSignalTrack); DEF_COMMAND(CmdRemoveSignalTrack);
@ -232,7 +229,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildAircraft, /* 61 */ CmdBuildAircraft, /* 61 */
CmdSendAircraftToHangar, /* 62 */ CmdSendAircraftToHangar, /* 62 */
CmdChangeAircraftServiceInt, /* 63 */ CmdChangeAircraftServiceInt, /* 63 */
CmdRefitAircraft, /* 64 <-- Hackykid */ CmdRefitAircraft, /* 64 <-- REFIT: Hackykid */
CmdPlaceSign, /* 65 */ CmdPlaceSign, /* 65 */
CmdRenameSign, /* 66 */ CmdRenameSign, /* 66 */
@ -250,7 +247,7 @@ static CommandProc * const _command_proc_table[] = {
CmdSellShareInCompany, /* 75 */ CmdSellShareInCompany, /* 75 */
CmdBuyCompany, /* 76 */ CmdBuyCompany, /* 76 */
CmdBuildTown, /* 77 <-- offline / scenario only */ CmdBuildTown, /* 77 <-- offline */
NULL, /* 78 */ NULL, /* 78 */
NULL, /* 79 */ NULL, /* 79 */
CmdRenameTown, /* 80 <-- TODO: check/enforce by server */ CmdRenameTown, /* 80 <-- TODO: check/enforce by server */
@ -266,7 +263,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildShip, /* 88 */ CmdBuildShip, /* 88 */
CmdSendShipToDepot, /* 89 */ CmdSendShipToDepot, /* 89 */
CmdChangeShipServiceInt, /* 90 */ CmdChangeShipServiceInt, /* 90 */
CmdRefitShip, /* 91 <-- Hackykid */ CmdRefitShip, /* 91 <-- REFIT: Hackykid */
NULL, /* 92 */ NULL, /* 92 */
NULL, /* 93 */ NULL, /* 93 */
@ -274,30 +271,29 @@ static CommandProc * const _command_proc_table[] = {
NULL, /* 95 */ NULL, /* 95 */
NULL, /* 96 */ NULL, /* 96 */
NULL, /* 97 */ NULL, /* 97 */
NULL, /* 98 */ NULL, /* 98 */
CmdCloneOrder, /* 99 */ CmdCloneOrder, /* 99 */
CmdClearArea, /* 100 */ CmdClearArea, /* 100 */
NULL, /* 101 */ NULL, /* 101 */
/***************************************************/
CmdMoneyCheat, /* 102 <-- offline only */ CmdMoneyCheat, /* 102 <-- offline (debug) */
CmdBuildCanal, /* 103 */ CmdBuildCanal, /* 103 */
CmdPlayerCtrl, /* 104 <-- TODO: check/enforce by server */ CmdPlayerCtrl, /* 104 */
CmdLevelLand, /* 105 <-- Hackykid */ CmdLevelLand, /* 105 */
CmdRefitRailVehicle, /* 106 <-- Hackykid */ CmdRefitRailVehicle, /* 106 <-- REFIT: Hackykid */
CmdRestoreOrderIndex, /* 107 */ CmdRestoreOrderIndex, /* 107 */
CmdBuildLock, /* 108 <-- Hackykid */ CmdBuildLock, /* 108 */
CmdStartScenario, /* 109 <-- UNNEEDED */ NULL, /* 109 */
CmdBuildSignalTrack, /* 110 <-- Hackykid */ CmdBuildSignalTrack, /* 110 */
CmdRemoveSignalTrack, /* 111 <-- Hackykid */ CmdRemoveSignalTrack, /* 111 */
CmdDestroyCompanyHQ, /* 112 */ NULL, /* 112 */
CmdGiveMoney, /* 113 */ CmdGiveMoney, /* 113 */
CmdChangePatchSetting, /* 114 <-- TODO: check/enforce by server */ CmdChangePatchSetting, /* 114 <-- TODO: check/enforce by server */
CmdReplaceVehicle, /* 115 <-- Hackykid */ CmdReplaceVehicle, /* 115 */
}; };
/* This function range-checks a cmd, and checks if the cmd is not NULL */ /* This function range-checks a cmd, and checks if the cmd is not NULL */

@ -104,8 +104,6 @@ enum {
CMD_DO_TOWN_ACTION = 81, CMD_DO_TOWN_ACTION = 81,
CMD_SET_ROAD_DRIVE_SIDE = 82, CMD_SET_ROAD_DRIVE_SIDE = 82,
CMD_SET_TOWN_NAME_TYPE = 83,
CMD_CHANGE_DIFFICULTY_LEVEL = 85, CMD_CHANGE_DIFFICULTY_LEVEL = 85,
@ -116,13 +114,6 @@ enum {
CMD_CHANGE_SHIP_SERVICE_INT = 90, CMD_CHANGE_SHIP_SERVICE_INT = 90,
CMD_REFIT_SHIP = 91, CMD_REFIT_SHIP = 91,
CMD_START_NEW_GAME = 92,
CMD_CREATE_SCENARIO = 94,
CMD_SET_NEW_LANDSCAPE_TYPE = 97,
CMD_GEN_RANDOM_NEW_GAME = 98,
CMD_CLONE_ORDER = 99, CMD_CLONE_ORDER = 99,
CMD_CLEAR_AREA = 100, CMD_CLEAR_AREA = 100,
@ -136,11 +127,9 @@ enum {
CMD_RESTORE_ORDER_INDEX = 107, CMD_RESTORE_ORDER_INDEX = 107,
CMD_BUILD_LOCK = 108, CMD_BUILD_LOCK = 108,
CMD_START_SCENARIO = 109,
CMD_BUILD_SIGNAL_TRACK = 110, CMD_BUILD_SIGNAL_TRACK = 110,
CMD_REMOVE_SIGNAL_TRACK = 111, CMD_REMOVE_SIGNAL_TRACK = 111,
CMD_DESTROY_COMPANY_HQ = 112,
CMD_GIVE_MONEY = 113, CMD_GIVE_MONEY = 113,
CMD_CHANGE_PATCH_SETTING = 114, CMD_CHANGE_PATCH_SETTING = 114,

@ -229,6 +229,7 @@ int SaveOrLoad(const char *filename, int mode);
void AfterLoadTown(void); void AfterLoadTown(void);
void GenRandomNewGame(uint32 rnd1, uint32 rnd2); void GenRandomNewGame(uint32 rnd1, uint32 rnd2);
void StartScenarioEditor(uint32 rnd1, uint32 rnd2);
void AskExitGame(void); void AskExitGame(void);
void AskExitToGameMenu(void); void AskExitToGameMenu(void);

@ -137,22 +137,14 @@ void GenRandomNewGame(uint32 rnd1, uint32 rnd2)
SwitchMode(SM_NEWGAME); SwitchMode(SM_NEWGAME);
} }
int32 CmdStartScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2) void StartScenarioEditor(uint32 rnd1, uint32 rnd2)
{ {
if (!(flags & DC_EXEC)) _random_seeds[0][0] = rnd1;
return 0; _random_seeds[0][1] = rnd2;
// this forces stuff into test mode.
_docommand_recursive = 0;
_random_seeds[0][0] = p1;
_random_seeds[0][1] = p2;
SwitchMode(SM_START_SCENARIO); SwitchMode(SM_START_SCENARIO);
return 0;
} }
static const Widget _ask_abandon_game_widgets[] = { static const Widget _ask_abandon_game_widgets[] = {
{ WWT_TEXTBTN, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_NULL},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_00C7_QUIT, STR_NULL}, { WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_00C7_QUIT, STR_NULL},

@ -191,31 +191,42 @@ int32 CmdPause(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return 0; return 0;
} }
/** Change the financial flow of your company.
* This is normally only enabled in offline mode, but if there is a debug
* build, you can cheat (to test).
* @param x,y unused
* @param p1 the amount of money to receive (if negative), or spend (if positive)
* @param p2 unused
*/
int32 CmdMoneyCheat(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdMoneyCheat(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
#ifndef _DEBUG
if (_networking) return CMD_ERROR;
#endif
SET_EXPENSES_TYPE(EXPENSES_OTHER); SET_EXPENSES_TYPE(EXPENSES_OTHER);
return (int32)p1; return (int32)p1;
} }
/** Transfer funds (money) from one player to another.
* @param x,y unused
* @param p1 the amount of money to transfer; max 16.000.000
* @param p2 the player to transfer the money to
*/
int32 CmdGiveMoney(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdGiveMoney(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
SET_EXPENSES_TYPE(EXPENSES_OTHER); SET_EXPENSES_TYPE(EXPENSES_OTHER);
p1 = clamp(p1, 0, 0xFFFFFF); // Clamp between 16 million and 0 if (!_networking || (int32)p1 <= 0 || p2 >= MAX_PLAYERS) return CMD_ERROR;
if (p1 == 0)
return CMD_ERROR;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
// Add money to player /* Add money to player (cast to signed to prevent 'stealing' money) */
byte old_cp = _current_player; PlayerID old_cp = _current_player;
_current_player = p2; _current_player = p2;
SubtractMoneyFromPlayer(-(int32)p1); SubtractMoneyFromPlayer(-(int32)p1);
_current_player = old_cp; _current_player = old_cp;
} }
// Subtract money from local-player /* Subtract money from local-player (cast to signed to prevent 'stealing' money) */
return (int32)p1; return (int32)p1;
} }

@ -1496,7 +1496,7 @@ static void SelectScenarioWndProc(Window *w, WindowEvent *e) {
SetFiosType(file->type); SetFiosType(file->type);
strcpy(_file_to_saveload.name, name); strcpy(_file_to_saveload.name, name);
DeleteWindow(w); DeleteWindow(w);
DoCommandP(0, Random(), InteractiveRandom(), NULL, CMD_START_SCENARIO); StartScenarioEditor(Random(), InteractiveRandom());
} }
} }
break; break;

@ -572,7 +572,7 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
strcpy(_file_to_saveload.name, name); strcpy(_file_to_saveload.name, name);
snprintf(_network_game_info.map_name, sizeof(_network_game_info.map_name), "Loaded scenario"); snprintf(_network_game_info.map_name, sizeof(_network_game_info.map_name), "Loaded scenario");
DeleteWindow(w); DeleteWindow(w);
DoCommandP(0, Random(), InteractiveRandom(), NULL, CMD_START_SCENARIO); StartScenarioEditor(Random(), InteractiveRandom());
} }
} }
break; break;

@ -141,7 +141,7 @@ static inline Order UnpackOrder(uint32 packed)
} }
/* Functions */ /* Functions */
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *order); void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *order);
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order); void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order);
void DeleteDestinationFromVehicleOrder(Order dest); void DeleteDestinationFromVehicleOrder(Order dest);
void InvalidateVehicleOrder(const Vehicle *v); void InvalidateVehicleOrder(const Vehicle *v);

@ -697,6 +697,7 @@ int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} break; } break;
case CO_UNSHARE: return DecloneOrder(dst, flags); case CO_UNSHARE: return DecloneOrder(dst, flags);
default: return CMD_ERROR;
} }
return 0; return 0;
@ -708,10 +709,8 @@ int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
* without loosing the order-list * without loosing the order-list
* *
*/ */
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak) void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
{ {
bool shared = IsOrderListShared(v);
/* Save general info */ /* Save general info */
bak->orderindex = v->cur_order_index; bak->orderindex = v->cur_order_index;
bak->service_interval = v->service_interval; bak->service_interval = v->service_interval;
@ -724,19 +723,15 @@ void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
} }
/* If we have shared orders, store it on a special way */ /* If we have shared orders, store it on a special way */
if (shared) { if (IsOrderListShared(v)) {
Vehicle *u; const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
if (v->next_shared)
u = v->next_shared;
else
u = v->prev_shared;
bak->clone = u->index; bak->clone = u->index;
} else { } else {
/* Else copy the orders */ /* Else copy the orders */
Order *order, *dest; Order *order, *dest;
dest = bak->order; dest = bak->order;
/* We do not have shared orders */ /* We do not have shared orders */
bak->clone = INVALID_VEHICLE; bak->clone = INVALID_VEHICLE;
@ -759,7 +754,7 @@ void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
*/ */
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak) void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
{ {
int i; uint i;
/* If we have a custom name, process that */ /* If we have a custom name, process that */
if (bak->name[0] != 0) { if (bak->name[0] != 0) {
@ -767,9 +762,6 @@ void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE); DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
} }
/* Restore vehicle number and service interval */
DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
/* If we had shared orders, recover that */ /* If we had shared orders, recover that */
if (bak->clone != INVALID_VEHICLE) { if (bak->clone != INVALID_VEHICLE) {
DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER); DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
@ -780,31 +772,44 @@ void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
order number is one more than the current amount of orders, and because order number is one more than the current amount of orders, and because
in network the commands are queued before send, the second insert always in network the commands are queued before send, the second insert always
fails in test mode. By bypassing the test-mode, that no longer is a problem. */ fails in test mode. By bypassing the test-mode, that no longer is a problem. */
for (i = 0; bak->order[i].type != OT_NOTHING; i++) for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
break; break;
}
/* Restore vehicle order-index and service interval */
DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
} }
/** /** Restore the current order-index of a vehicle and sets service-interval.
* * @param x,y unused
* Restore the current-order-index of a vehicle and sets service-interval * @param p1 the ID of the vehicle
* * @param p2 various bistuffed elements
* @param vehicle_id The ID of the vehicle * - p2 = (bit 0-15) - current order-index (p2 & 0xFFFF)
* @param data First 16 bits are the current-order-index * - p2 = (bit 16-31) - service interval (p2 >> 16)
* The last 16 bits are the service-interval * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle
* * as far as I can see. We can store it in BackuppedOrders, and restore it, but
* but we have no way of seeing it has been tampered with or not, as we have no
* legit way of knowing what that ID was.@n
* If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and
* restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;"
*/ */
int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 vehicle_id, uint32 data) int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
Vehicle* v; Vehicle *v;
OrderID cur_ord = p2 & 0xFFFF;
uint16 serv_int = p2 >> 16;
if (!IsVehicleIndex(p1)) return CMD_ERROR;
if (!IsVehicleIndex(vehicle_id)) return CMD_ERROR; v = GetVehicle(p1);
v = GetVehicle(vehicle_id); /* Check the vehicle type and ownership, and if the service interval and order are in range */
if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR;
if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
v->service_interval = data >> 16; v->cur_order_index = cur_ord;
v->cur_order_index = data & 0xFFFF; v->service_interval = serv_int;
} }
return 0; return 0;

@ -1,3 +1,6 @@
/** @file,
* sjdlfkasjdf
*/
#include "stdafx.h" #include "stdafx.h"
#include "ttd.h" #include "ttd.h"
#include "string.h" #include "string.h"
@ -217,7 +220,7 @@ static void SubtractMoneyFromAnyPlayer(Player *p, int32 cost)
void SubtractMoneyFromPlayer(int32 cost) void SubtractMoneyFromPlayer(int32 cost)
{ {
uint pid = _current_player; PlayerID pid = _current_player;
if (pid < MAX_PLAYERS) if (pid < MAX_PLAYERS)
SubtractMoneyFromAnyPlayer(DEREF_PLAYER(pid), cost); SubtractMoneyFromAnyPlayer(DEREF_PLAYER(pid), cost);
} }
@ -630,23 +633,36 @@ static void DeletePlayerStuff(int pi)
p->president_name_1 = 0; p->president_name_1 = 0;
} }
// functionality. /** Control the players: add, delete, etc.
// 0 - make new player * @param x,y unused
// 1 - make new AI player * @param p1 various functionality
// 2 - delete player (p2) * - p1 = 0 - create a new player, Which player (network) it will be is in p2
// 3 - join player (p1 >> 8) & 0xFF with (p1 >> 16) & 0xFF * - 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(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int pi; if (flags & DC_EXEC) _current_player = OWNER_NONE;
Player *p;
if (!(flags & DC_EXEC)) switch (p1) {
return 0; case 0: { /* Create a new player */
Player *p;
PlayerID pid = p2;
_current_player = OWNER_NONE; if (!(flags & DC_EXEC) || pid >= MAX_PLAYERS) return 0;
switch(p1 & 0xff) {
case 0: // make new player
p = DoStartupNewPlayer(false); p = DoStartupNewPlayer(false);
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
@ -665,9 +681,9 @@ int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} }
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
if (_network_server) { if (_network_server) {
NetworkClientInfo *ci; /* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at server-side
// UGLY! p2 is mis-used to fetch the client-id * in network_server.c:838, function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
ci = &_network_client_info[p2]; NetworkClientInfo *ci = &_network_client_info[pid];
ci->client_playas = p->index + 1; ci->client_playas = p->index + 1;
NetworkUpdateClientInfo(ci->client_index); NetworkUpdateClientInfo(ci->client_index);
@ -690,47 +706,61 @@ int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_local_player = player_backup; _local_player = player_backup;
} }
} }
} else { } else if (_network_server) {
if (_network_server) { /* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at server-side
NetworkClientInfo *ci; * in network_server.c:838, function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
// UGLY! p2 is mis-used to fetch the client-id NetworkClientInfo *ci = &_network_client_info[pid];
ci = &_network_client_info[p2]; ci->client_playas = OWNER_SPECTATOR;
ci->client_playas = OWNER_SPECTATOR; NetworkUpdateClientInfo(ci->client_index);
NetworkUpdateClientInfo(ci->client_index);
}
#endif /* ENABLE_NETWORK */
} }
break; #endif /* ENABLE_NETWORK */
case 1: // make new ai player } break;
case 1: /* Make a new AI player */
if (!(flags & DC_EXEC)) return 0;
DoStartupNewPlayer(true); DoStartupNewPlayer(true);
break; break;
case 2: // delete player
case 2: { /* Delete a player */
Player *p;
if (p2 >= MAX_PLAYERS) return CMD_ERROR;
if (!(flags & DC_EXEC)) return 0;
p = DEREF_PLAYER(p2); p = DEREF_PLAYER(p2);
/* Only allow removal of HUMAN companies */ /* Only allow removal of HUMAN companies */
if (IS_HUMAN_PLAYER(p2)) { if (IS_HUMAN_PLAYER(p->index)) {
/* Delete any open window of the company */ /* Delete any open window of the company */
DeletePlayerWindows(p2); DeletePlayerWindows(p->index);
/* Show the bankrupt news */ /* Show the bankrupt news */
SetDParam(0, p->name_1); SetDParam(0, p->name_1);
SetDParam(1, p->name_2); SetDParam(1, p->name_2);
AddNewsItem( (StringID)(p2 + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0); AddNewsItem( (StringID)(p->index + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
/* Remove the company */ /* Remove the company */
ChangeOwnershipOfPlayerItems(p2, 255); ChangeOwnershipOfPlayerItems(p->index, OWNER_SPECTATOR);
p->money64 = p->player_money = 100000000; p->money64 = p->player_money = 100000000; // XXX - wtf?
p->is_active = false; p->is_active = false;
} }
break; } break;
case 3: // join player case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
pi = (byte)(p1 >> 8); PlayerID pid_old = p2 & 0xFFFF;
ChangeOwnershipOfPlayerItems(pi, (byte)(p1 >> 16)); PlayerID pid_new = (p2 >> 16) & 0xFFFF;
DeletePlayerStuff(pi);
break; if (pid_old >= MAX_PLAYERS || pid_new >= MAX_PLAYERS) 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; return 0;
} }

@ -555,8 +555,8 @@ static int32 ValidateAutoDrag(byte *railbit, int x, int y, int ex, int ey)
// validate the direction // validate the direction
while (((trdx <= 0) && (dx > 0)) || ((trdx >= 0) && (dx < 0)) || while (((trdx <= 0) && (dx > 0)) || ((trdx >= 0) && (dx < 0)) ||
((trdy <= 0) && (dy > 0)) || ((trdy >= 0) && (dy < 0))) { ((trdy <= 0) && (dy > 0)) || ((trdy >= 0) && (dy < 0))) {
if (*railbit < 8) { // first direction is invalid, try the other if (!HASBIT(*railbit, 3)) { // first direction is invalid, try the other
SETBIT(*railbit, 3); SETBIT(*railbit, 3); // reverse the direction
trdx = -trdx; trdx = -trdx;
trdy = -trdy; trdy = -trdy;
} else // other direction is invalid too, invalid drag } else // other direction is invalid too, invalid drag
@ -625,11 +625,19 @@ static int32 CmdRailTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2
return (total_cost == 0) ? CMD_ERROR : total_cost; return (total_cost == 0) ? CMD_ERROR : total_cost;
} }
/** Build rail on a stretch of track.
* Stub for the unified rail builder/remover
* @see CmdRailTrackHelper
*/
int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
return CmdRailTrackHelper(x, y, flags, p1, CLRBIT(p2, 7)); return CmdRailTrackHelper(x, y, flags, p1, CLRBIT(p2, 7));
} }
/** Build rail on a stretch of track.
* Stub for the unified rail builder/remover
* @see CmdRailTrackHelper
*/
int32 CmdRemoveRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdRemoveRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
return CmdRailTrackHelper(x, y, flags, p1, SETBIT(p2, 7)); return CmdRailTrackHelper(x, y, flags, p1, SETBIT(p2, 7));
@ -813,36 +821,42 @@ int32 CmdBuildSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return cost; return cost;
} }
/* Build many signals by dragging: AutoSignals /** Build many signals by dragging; AutoSignals
* x,y = start tile * @param x,y start tile of drag
* p1 = end tile * @param p1 end tile of drag
* p2 = (bit 0) - 0 = build, 1 = remove signals * @param p2 various bitstuffed elements
* p2 = (bit 3) - 0 = signals, 1 = semaphores * - p2 = (bit 0) - 0 = build, 1 = remove signals
* p2 = (bit 4-6) - track-orientation, valid values: 0-5 * - p2 = (bit 3) - 0 = signals, 1 = semaphores
* p2 = (bit 24-31) - user defined signals_density * - p2 = (bit 4- 6) - track-orientation, valid values: 0-5
* - p2 = (bit 24-31) - user defined signals_density
*/ */
static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2) static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int ex, ey; int ex, ey;
byte railbit = (p2 >> 4) & 7;
bool error = true;
TileIndex tile = TILE_FROM_XY(x, y);
int32 ret, total_cost, signal_ctr; int32 ret, total_cost, signal_ctr;
byte m5, semaphores = (HASBIT(p2, 3)) ? 8 : 0; byte m5, signals;
TileIndex tile = TILE_FROM_XY(x, y);
bool error = true;
int mode = p2 & 0x1; int mode = p2 & 0x1;
// for vertical/horizontal tracks, double the given signals density byte semaphores = (HASBIT(p2, 3)) ? 8 : 0;
// since the original amount will be too dense (shorter tracks) byte railbit = (p2 >> 4) & 0x7;
byte signal_density = (railbit & 0x6) ? (p2 >> 24) * 2: (p2 >> 24); byte signal_density = (p2 >> 24);
byte signals;
if (p1 > MapSize()) return CMD_ERROR;
if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); 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 (railbit & 0x6) signal_density *= 2;
// unpack end tile // unpack end tile
ex = TileX(p1) * 16; ex = TileX(p1) * 16;
ey = TileY(p1) * 16; ey = TileY(p1) * 16;
if (ValidateAutoDrag(&railbit, x, y, ex, ey) == CMD_ERROR) if (CmdFailed(ValidateAutoDrag(&railbit, x, y, ex, ey))) return CMD_ERROR;
return CMD_ERROR;
// copy the signal-style of the first rail-piece if existing // copy the signal-style of the first rail-piece if existing
m5 = _map5[tile]; m5 = _map5[tile];
@ -851,9 +865,8 @@ static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32
if (signals == 0) signals = _signals_table_both[railbit]; if (signals == 0) signals = _signals_table_both[railbit];
semaphores = (_map3_hi[tile] & ~3) ? 8 : 0; // copy signal/semaphores style (independent of CTRL) semaphores = (_map3_hi[tile] & ~3) ? 8 : 0; // copy signal/semaphores style (independent of CTRL)
} else { // no signals exist, drag a two-way signal stretch } else // no signals exist, drag a two-way signal stretch
signals = _signals_table_both[railbit]; signals = _signals_table_both[railbit];
}
/* signal_density_ctr - amount of tiles already processed /* signal_density_ctr - amount of tiles already processed
* signals_density - patch setting to put signal on every Nth tile (double space on |, -- tracks) * signals_density - patch setting to put signal on every Nth tile (double space on |, -- tracks)
@ -864,25 +877,22 @@ static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32
and convert all others to semaphore/signal and convert all others to semaphore/signal
* mode - 1 remove signals, 0 build signals */ * mode - 1 remove signals, 0 build signals */
signal_ctr = total_cost = 0; signal_ctr = total_cost = 0;
for(;;) { for (;;) {
// only build/remove signals with the specified density // only build/remove signals with the specified density
if ((signal_ctr % signal_density) == 0 ) { if ((signal_ctr % signal_density) == 0 ) {
ret = DoCommand(x, y, (railbit & 7) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); ret = DoCommand(x, y, (railbit & 7) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
/* Abort placement for any other error than NOT_SUITABLE_TRACK /* Abort placement for any other error than NOT_SUITABLE_TRACK
* This includes vehicles on track, competitor's tracks, etc. */ * This includes vehicles on track, competitor's tracks, etc. */
if (ret == CMD_ERROR) { if (CmdFailed(ret)) {
if (_error_message != STR_1005_NO_SUITABLE_RAILROAD_TRACK && mode != 1) { if (_error_message != STR_1005_NO_SUITABLE_RAILROAD_TRACK && mode != 1) return CMD_ERROR;
return CMD_ERROR;
}
} else { } else {
error = false; error = false;
total_cost += ret; total_cost += ret;
} }
} }
if (ex == x && ey == y) // reached end of drag if (ex == x && ey == y) break; // reached end of drag
break;
x += _railbit.xinc[railbit]; x += _railbit.xinc[railbit];
y += _railbit.yinc[railbit]; y += _railbit.yinc[railbit];
@ -895,7 +905,10 @@ static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32
return (error) ? CMD_ERROR : total_cost; return (error) ? CMD_ERROR : total_cost;
} }
/* Stub for the unified Signal builder/remover */ /** Build signals on a stretch of track.
* Stub for the unified signal builder/remover
* @see CmdSignalTrackHelper
*/
int32 CmdBuildSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdBuildSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
return CmdSignalTrackHelper(x, y, flags, p1, p2); return CmdSignalTrackHelper(x, y, flags, p1, p2);
@ -941,7 +954,10 @@ int32 CmdRemoveSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return _price.remove_signals; return _price.remove_signals;
} }
/* Stub for the unified Signal builder/remover */ /** Remove signals on a stretch of track.
* Stub for the unified signal builder/remover
* @see CmdSignalTrackHelper
*/
int32 CmdRemoveSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdRemoveSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
return CmdSignalTrackHelper(x, y, flags, p1, SETBIT(p2, 0)); return CmdSignalTrackHelper(x, y, flags, p1, SETBIT(p2, 0));

@ -1017,19 +1017,21 @@ static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
} }
} }
/** /** Network-safe changing of patch-settings.
* Network-safe changing of patch-settings. * @param p1 various bitstuffed elements
* @param p1 bytes 0 - 7: the patches type (page) that is being changed (construction, network, ai) * - p1 = (bit 0- 7) - the patches type (page) that is being changed (construction, network, ai) (p1 & 0xFF)
* @param p1 bytes 8 - ..: the actual patch (entry) being set inside the category * - p2 = (bit 8-15) - the actual patch (entry) being set inside the category ((p1>>8) & 0xFF)
* @param p2 the new value for the patch * @param p2 the new value for the patch
* @todo check that the new value is a valid one. Awful lot of work, but since only
* the server is allowed to do this, we trust it on this one :)
*/ */
int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
byte pcat = p1 & 0xFF; byte pcat = p1 & 0xFF;
byte pel = (p1 >> 8) & 0xFF; byte pel = (p1 >> 8) & 0xFF;
if (pcat >= lengthof(_patches_page)) return 0; if (pcat >= lengthof(_patches_page)) return CMD_ERROR;
if (pel >= _patches_page[pcat].num) return 0; if (pel >= _patches_page[pcat].num) return CMD_ERROR;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
const PatchEntry *pe = &_patches_page[pcat].entries[pel]; const PatchEntry *pe = &_patches_page[pcat].entries[pel];

@ -12,6 +12,94 @@
#include "town.h" #include "town.h"
#include "sprite.h" #include "sprite.h"
/** Destroy a HQ.
* During normal gameplay you can only implicitely destroy a HQ when you are
* rebuilding it. Otherwise, only water can destroy it.
* @param tile tile coordinates where HQ is located to destroy
* @param flags docommand flags of calling function
*/
int32 DestroyCompanyHQ(TileIndex tile, uint32 flags)
{
Player *p;
SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
/* Find player that has HQ flooded, and reset their location_of_house */
if (_current_player == OWNER_WATER) {
bool dodelete = false;
FOR_ALL_PLAYERS(p) {
if (p->location_of_house == tile) {
dodelete = true;
break;
}
}
if (!dodelete) return CMD_ERROR;
} else /* Destruction was initiated by player */
p = DEREF_PLAYER(_current_player);
if (p->location_of_house == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
DoClearSquare(p->location_of_house + TILE_XY(0,0));
DoClearSquare(p->location_of_house + TILE_XY(0,1));
DoClearSquare(p->location_of_house + TILE_XY(1,0));
DoClearSquare(p->location_of_house + TILE_XY(1,1));
p->location_of_house = 0; // reset HQ position
InvalidateWindow(WC_COMPANY, (int)p->index);
}
// cost of relocating company is 1% of company value
return CalculateCompanyValue(p) / 100;
}
/** Build or relocate the HQ. This depends if the HQ is already built or not
* @param x,y the coordinates where the HQ will be built or relocated to
* @param p1 relocate HQ (set to some value, usually 1 or true)
* @param p2 unused
*/
extern int32 CheckFlatLandBelow(uint tile, uint w, uint h, uint flags, uint invalid_dirs, int *);
int32 CmdBuildCompanyHQ(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile = TILE_FROM_XY(x,y);
Player *p = DEREF_PLAYER(_current_player);
int cost;
SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
cost = CheckFlatLandBelow(tile, 2, 2, flags, 0, NULL);
if (CmdFailed(cost)) return CMD_ERROR;
if (p1) { /* Moving HQ */
int32 ret;
if (p->location_of_house == 0) return CMD_ERROR;
ret = DestroyCompanyHQ(p->location_of_house, flags);
if (CmdFailed(ret)) return CMD_ERROR;
cost += ret;
} else { /* Building new HQ */
if (p->location_of_house != 0) return CMD_ERROR;
}
if (flags & DC_EXEC) {
int score = UpdateCompanyRatingAndValue(p, false);
p->location_of_house = tile;
ModifyTile(tile + TILE_XY(0,0), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x80);
ModifyTile(tile + TILE_XY(0,1), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x81);
ModifyTile(tile + TILE_XY(1,0), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x82);
ModifyTile(tile + TILE_XY(1,1), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x83);
UpdatePlayerHouse(p, score);
InvalidateWindow(WC_COMPANY, (int)p->index);
}
return cost;
}
typedef struct DrawTileUnmovableStruct { typedef struct DrawTileUnmovableStruct {
uint16 image; uint16 image;
byte subcoord_x; byte subcoord_x;
@ -110,8 +198,7 @@ static int32 ClearTile_Unmovable(uint tile, byte flags)
byte m5 = _map5[tile]; byte m5 = _map5[tile];
if (m5 & 0x80) { if (m5 & 0x80) {
if (_current_player == OWNER_WATER) if (_current_player == OWNER_WATER) return DestroyCompanyHQ(tile, DC_EXEC);
return DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_DESTROY_COMPANY_HQ);
return_cmd_error(STR_5804_COMPANY_HEADQUARTERS_IN); return_cmd_error(STR_5804_COMPANY_HEADQUARTERS_IN);
} }
@ -307,101 +394,6 @@ restart:
} while (--i); } while (--i);
} }
extern int32 CheckFlatLandBelow(uint tile, uint w, uint h, uint flags, uint invalid_dirs, int *);
/** Build or relocate the HQ. This depends if the HQ is already built or not
* @param x,y the coordinates where the HQ will be built or relocated to
* @param p1 relocate HQ (set to some value, usually 1 or true)
* @param p2 unused
*/
int32 CmdBuildCompanyHQ(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile = TILE_FROM_XY(x,y);
Player *p = DEREF_PLAYER(_current_player);
int cost;
SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
cost = CheckFlatLandBelow(tile, 2, 2, flags, 0, NULL);
if (CmdFailed(cost)) return CMD_ERROR;
if (p1) { /* Moving HQ */
int32 ret;
if (p->location_of_house == 0) return CMD_ERROR;
ret = DoCommandByTile(p->location_of_house, 0, 0, flags, CMD_DESTROY_COMPANY_HQ);
if (CmdFailed(ret)) return CMD_ERROR;
cost += ret;
} else { /* Building new HQ */
if (p->location_of_house != 0) return CMD_ERROR;
}
if (flags & DC_EXEC) {
int score = UpdateCompanyRatingAndValue(p, false);
p->location_of_house = tile;
ModifyTile(tile + TILE_XY(0,0), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x80);
ModifyTile(tile + TILE_XY(0,1), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x81);
ModifyTile(tile + TILE_XY(1,0), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x82);
ModifyTile(tile + TILE_XY(1,1), MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5, 0x83);
UpdatePlayerHouse(p, score);
InvalidateWindow(WC_COMPANY, (int)p->index);
}
return cost;
}
/** Destroy a HQ.
* During normal gameplay you can only implicitely destroy a HQ when you are
* rebuilding it. Otherwise, only water can destroy it. Unfortunately there is
* no safeguard against a hacked client to call this command, unless we also add
* flags to the command table which commands can be called directly and which not.
* @param x,y tile coordinates where HQ is located to destroy
* @param p1 unused
* @param p2 unused
*/
int32 CmdDestroyCompanyHQ(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile;
Player *p;
SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
/* Find player that has HQ flooded, and reset their location_of_house */
if (_current_player == OWNER_WATER) {
bool dodelete = false;
tile = TILE_FROM_XY(x,y);
FOR_ALL_PLAYERS(p) {
if (p->location_of_house == tile) {
dodelete = true;
break;
}
}
if (!dodelete) return CMD_ERROR;
} else /* Destruction was initiated by player */
p = DEREF_PLAYER(_current_player);
if (p->location_of_house == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
DoClearSquare(p->location_of_house + TILE_XY(0,0));
DoClearSquare(p->location_of_house + TILE_XY(0,1));
DoClearSquare(p->location_of_house + TILE_XY(1,0));
DoClearSquare(p->location_of_house + TILE_XY(1,1));
p->location_of_house = 0; // reset HQ position
InvalidateWindow(WC_COMPANY, (int)p->index);
}
// cost of relocating company is 1% of company value
return CalculateCompanyValue(p) / 100;
}
static void ChangeTileOwner_Unmovable(uint tile, byte old_player, byte new_player) static void ChangeTileOwner_Unmovable(uint tile, byte old_player, byte new_player)
{ {
if (_map_owner[tile] != old_player) if (_map_owner[tile] != old_player)

@ -1306,9 +1306,13 @@ extern int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p
extern int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2); extern int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2);
extern int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2); extern int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2);
/* Replaces a vehicle (used to be called autorenew) /** Replaces a vehicle (used to be called autorenew).
p1 - Index of vehicle * @param x,y unused
p2 - Type of new engine */ * @param p1 index of vehicle being replaced
* @param p2 various bitstuffed elements
* - p2 = (bit 0-15) - new engine type for the vehicle (p2 & 0xFFFF)
* - p2 = (bit 16-31) - money the player wants to have left after replacement counted in 100.000 (100K) (p2 >> 16)
*/
int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
/* makesvariables to inform about how much money the player wants to have left after replacing /* makesvariables to inform about how much money the player wants to have left after replacing
@ -1317,11 +1321,11 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches
This is a nice way to send 32 bit and only use 16 bit This is a nice way to send 32 bit and only use 16 bit
the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */ the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */
uint16 new_engine_type = (uint16)(p2 & 0xFFFF); EngineID new_engine_type = (p2 & 0xFFFF);
uint32 autorefit_money = (p2 >> 16) * 100000; uint32 autorefit_money = (p2 >> 16) * 100000;
Vehicle *v, *u, *first; Vehicle *v, *u, *first;
int cost, build_cost, rear_engine_cost = 0; int cost, build_cost, rear_engine_cost = 0;
byte old_engine_type; EngineID old_engine_type;
if (!IsVehicleIndex(p1)) return CMD_ERROR; if (!IsVehicleIndex(p1)) return CMD_ERROR;
@ -1329,9 +1333,9 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
old_engine_type = v->engine_type; old_engine_type = v->engine_type;
// first we make sure that it's a valid type the user requested /* First we make sure that it's a valid type the user requested
// check that it's an engine that is in the engine array * check that it's an engine that is in the engine array */
if (new_engine_type >= TOTAL_NUM_ENGINES ) return CMD_ERROR; if (!IsEngineIndex(new_engine_type)) return CMD_ERROR;
// check that the new vehicle type is the same as the original one // check that the new vehicle type is the same as the original one
if (v->type != DEREF_ENGINE(new_engine_type)->type) return CMD_ERROR; if (v->type != DEREF_ENGINE(new_engine_type)->type) return CMD_ERROR;
@ -1357,8 +1361,7 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
/* In a rare situation, when 2 clients are connected to 1 company and have the same /* In a rare situation, when 2 clients are connected to 1 company and have the same
settings, a vehicle can be replaced twice.. check if this is the situation here */ settings, a vehicle can be replaced twice.. check if this is the situation here */
if (old_engine_type == new_engine_type && v->age == 0) if (old_engine_type == new_engine_type && v->age == 0) return CMD_ERROR;
return CMD_ERROR;
if ( v->type == VEH_Train ) { if ( v->type == VEH_Train ) {
first = GetFirstVehicleInChain(v); first = GetFirstVehicleInChain(v);
@ -1415,8 +1418,7 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
/* We do not really buy a new vehicle, we upgrade the old one */ /* We do not really buy a new vehicle, we upgrade the old one */
Engine *e; Engine *e = DEREF_ENGINE(new_engine_type);
e = DEREF_ENGINE(new_engine_type);
v->reliability = e->reliability; v->reliability = e->reliability;
v->reliability_spd_dec = e->reliability_spd_dec; v->reliability_spd_dec = e->reliability_spd_dec;
@ -1427,7 +1429,6 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->value = build_cost; v->value = build_cost;
if (v->engine_type != new_engine_type) { if (v->engine_type != new_engine_type) {
byte sprite = v->spritenum; byte sprite = v->spritenum;
byte cargo_type = v->cargo_type; byte cargo_type = v->cargo_type;

@ -55,7 +55,7 @@ typedef struct VehicleRail {
// NOSAVE: for wagon override - id of the first engine in train // NOSAVE: for wagon override - id of the first engine in train
// 0xffff == not in train // 0xffff == not in train
uint16 first_engine; EngineID first_engine;
byte track; byte track;
byte force_proceed; byte force_proceed;

@ -159,30 +159,44 @@ static void MarkTilesAroundDirty(uint tile)
MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0)); MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0));
} }
/** Builds a lock (ship-lift)
* @param x,y tile coordinates where to place the lock
* @param p1 unused
* @param p2 unused
*/
int32 CmdBuildLock(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdBuildLock(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
uint tile = TILE_FROM_XY(x,y); TileIndex tile = TILE_FROM_XY(x,y);
int32 ret; uint tileh;
uint th;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
th = GetTileSlope(tile, NULL); tileh = GetTileSlope(tile, NULL);
if (th==3 || th==6 || th==9 || th==12) { if (tileh == 3 || tileh == 6 || tileh == 9 || tileh == 12) {
static const byte _shiplift_dirs[16] = {0,0,0,2,0,0,1,0,0,3,0,0,0}; static const byte _shiplift_dirs[16] = {0, 0, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0};
ret = DoBuildShiplift(tile, _shiplift_dirs[th], flags); return DoBuildShiplift(tile, _shiplift_dirs[tileh], flags);
return ret; }
}
else return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
} }
/** Build a piece of canal.
* @param x,y end tile of stretch-dragging
* @param p1 start tile of stretch-dragging
* @param p2 unused
*/
int32 CmdBuildCanal(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdBuildCanal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int32 ret, cost; int32 ret, cost;
int size_x, size_y; int size_x, size_y;
int sx = TileX((TileIndex)p1); int sx, sy;
int sy = TileY((TileIndex)p1);
if (p1 > MapSize()) return CMD_ERROR;
sx = TileX(p1);
sy = TileY(p1);
/* x,y are in pixel-coordinates, transform to tile-coordinates
* to be able to use the BEGIN_TILE_LOOP() macro */
x >>= 4; y >>= 4; x >>= 4; y >>= 4;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
@ -192,11 +206,13 @@ int32 CmdBuildCanal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
size_x = (x - sx) + 1; size_x = (x - sx) + 1;
size_y = (y - sy) + 1; size_y = (y - sy) + 1;
/* Outside the editor you can only drag canals, and not areas */
if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
cost = 0; cost = 0;
BEGIN_TILE_LOOP(tile, size_x, size_y, TILE_XY(sx, sy)) { BEGIN_TILE_LOOP(tile, size_x, size_y, TILE_XY(sx, sy)) {
ret = 0; ret = 0;
if (GetTileSlope(tile, NULL) != 0) if (GetTileSlope(tile, NULL) != 0) return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
// can't make water of water! // can't make water of water!
if (IsTileType(tile, MP_WATER)) { if (IsTileType(tile, MP_WATER)) {
@ -204,19 +220,16 @@ int32 CmdBuildCanal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} else { } else {
/* is middle piece of a bridge? */ /* is middle piece of a bridge? */
if (IsTileType(tile, MP_TUNNELBRIDGE) && _map5[tile] & 0x40) { /* build under bridge */ if (IsTileType(tile, MP_TUNNELBRIDGE) && _map5[tile] & 0x40) { /* build under bridge */
if (_map5[tile] & 0x20) { // transport route under bridge if (_map5[tile] & 0x20) // transport route under bridge
_error_message = STR_5800_OBJECT_IN_THE_WAY; return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
ret = CMD_ERROR;
} if (_map5[tile] & 0x18) // already water under bridge
else if (_map5[tile] & 0x18) { // already water under bridge return_cmd_error(STR_1007_ALREADY_BUILT);
_error_message = STR_1007_ALREADY_BUILT;
ret = CMD_ERROR;
}
/* no bridge? then try to clear it. */ /* no bridge? then try to clear it. */
} else } else
ret = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); ret = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (ret == CMD_ERROR) return ret; if (CmdFailed(ret)) return CMD_ERROR;
cost += ret; cost += ret;
/* execute modifications */ /* execute modifications */

Loading…
Cancel
Save