bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback) { if (!AIObject::CanSuspend()) { throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator."); } /* Set the default callback to return a true/false result of the DoCommand */ if (callback == NULL) callback = &AIInstance::DoCommandReturn; /* Are we only interested in the estimate costs? */ bool estimate_only = GetDoCommandMode() != NULL && !GetDoCommandMode()(); #ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX; #endif /* Try to perform the command. */ CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, _networking ? CcAI : NULL, text, false, estimate_only); /* We failed; set the error and bail out */ if (res.Failed()) { SetLastError(AIError::StringToError(res.GetErrorMessage())); return false; } /* No error, then clear it. */ SetLastError(AIError::ERR_NONE); /* Estimates, update the cost for the estimate and be done */ if (estimate_only) { IncreaseDoCommandCosts(res.GetCost()); return true; } /* Costs of this operation. */ SetLastCost(res.GetCost()); SetLastCommandRes(true); if (_networking) { /* Suspend the AI till the command is really executed. */ throw AI_VMSuspend(-(int)GetDoCommandDelay(), callback); } else { IncreaseDoCommandCosts(res.GetCost()); /* Suspend the AI player for 1+ ticks, so it simulates multiplayer. This * both avoids confusion when a developer launched his AI in a * multiplayer game, but also gives time for the GUI and human player * to interact with the game. */ throw AI_VMSuspend(GetDoCommandDelay(), callback); } NOT_REACHED(); }
/* static */ bool ScriptObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, Script_SuspendCallbackProc *callback) { if (!ScriptObject::CanSuspend()) { throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator."); } if (ScriptObject::GetCompany() != OWNER_DEITY && !::Company::IsValidID(ScriptObject::GetCompany())) { ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY); return false; } assert(StrEmpty(text) || (GetCommandFlags(cmd) & CMD_STR_CTRL) != 0 || StrValid(text, text + strlen(text))); /* Set the default callback to return a true/false result of the DoCommand */ if (callback == NULL) callback = &ScriptInstance::DoCommandReturn; /* Are we only interested in the estimate costs? */ bool estimate_only = GetDoCommandMode() != NULL && !GetDoCommandMode()(); #ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX; #endif /* Try to perform the command. */ CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only); /* We failed; set the error and bail out */ if (res.Failed()) { SetLastError(ScriptError::StringToError(res.GetErrorMessage())); return false; } /* No error, then clear it. */ SetLastError(ScriptError::ERR_NONE); /* Estimates, update the cost for the estimate and be done */ if (estimate_only) { IncreaseDoCommandCosts(res.GetCost()); return true; } /* Costs of this operation. */ SetLastCost(res.GetCost()); SetLastCommandRes(true); if (_generating_world) { IncreaseDoCommandCosts(res.GetCost()); if (callback != NULL) { /* Insert return value into to stack and throw a control code that * the return value in the stack should be used. */ callback(GetActiveInstance()); throw SQInteger(1); } return true; } else if (_networking) { /* Suspend the script till the command is really executed. */ throw Script_Suspend(-(int)GetDoCommandDelay(), callback); } else { IncreaseDoCommandCosts(res.GetCost()); /* Suspend the script player for 1+ ticks, so it simulates multiplayer. This * both avoids confusion when a developer launched his script in a * multiplayer game, but also gives time for the GUI and human player * to interact with the game. */ throw Script_Suspend(GetDoCommandDelay(), callback); } NOT_REACHED(); }