summaryrefslogtreecommitdiff
path: root/src/command.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/command.cpp')
-rw-r--r--src/command.cpp27
1 files changed, 20 insertions, 7 deletions
diff --git a/src/command.cpp b/src/command.cpp
index 19fd1a69c..169c2b6d0 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -26,6 +26,7 @@
#include "company_func.h"
#include "company_base.h"
#include "signal_func.h"
+#include "core/backup_type.hpp"
#include "table/strings.h"
@@ -590,17 +591,18 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR, false);
/* Always execute server and spectator commands as spectator */
- if (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) _current_company = COMPANY_SPECTATOR;
-
- CompanyID old_company = _current_company;
+ bool exec_as_spectator = cmd_flags & (CMD_SPECTATOR | CMD_SERVER);
/* If the company isn't valid it may only do server command or start a new company!
* The server will ditch any server commands a client sends to it, so effectively
* this guards the server from executing functions for an invalid company. */
- if (_game_mode == GM_NORMAL && (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) == 0 && !Company::IsValidID(_current_company)) {
+ if (_game_mode == GM_NORMAL && !exec_as_spectator && !Company::IsValidID(_current_company)) {
return_dcpi(CMD_ERROR, false);
}
+ Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
+ if (exec_as_spectator) cur_company.Change(COMPANY_SPECTATOR);
+
bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0;
bool skip_test = _networking && (cmd & CMD_NO_TEST_IF_IN_NETWORK) != 0;
@@ -622,7 +624,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
SetTownRatingTestMode(false);
/* Make sure we're not messing things up here. */
- assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
+ assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify());
/* If the command fails, we're doing an estimate
* or the player does not have enough money
@@ -631,6 +633,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
* we bail out here. */
if (res.Failed() || estimate_only ||
(!test_and_exec_can_differ && !CheckCompanyHasMoney(res))) {
+ cur_company.Restore();
return_dcpi(res, false);
}
}
@@ -642,6 +645,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
*/
if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
NetworkSend_Command(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company);
+ cur_company.Restore();
/* Don't return anything special here; no error, no costs.
* This way it's not handled by DoCommand and only the
@@ -656,8 +660,17 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
* use the construction one */
CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text);
- /* Make sure nothing bad happened, like changing the current company. */
- assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
+ if (cmd_id == CMD_COMPANY_CTRL) {
+ cur_company.Trash();
+ /* We are a new company -> Switch to new local company.
+ * We were closed down -> Switch to spectator
+ * Some other company opened/closed down -> The outside function will switch back */
+ _current_company = _local_company;
+ } else {
+ /* Make sure nothing bad happened, like changing the current company. */
+ assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify());
+ cur_company.Restore();
+ }
/* If the test and execution can differ, or we skipped the test
* we have to check the return of the command. Otherwise we can