script_object.cpp

Go to the documentation of this file.
00001 /* $Id: script_object.cpp 23632 2011-12-19 21:05:25Z truebrain $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "../../script/squirrel.hpp"
00014 #include "../../command_func.h"
00015 #include "../../company_func.h"
00016 #include "../../company_base.h"
00017 #include "../../network/network.h"
00018 #include "../../tunnelbridge.h"
00019 #include "../../genworld.h"
00020 #include "../../goal_type.h"
00021 
00022 #include "../script_storage.hpp"
00023 #include "../script_instance.hpp"
00024 #include "../script_fatalerror.hpp"
00025 #include "../script_suspend.hpp"
00026 #include "script_error.hpp"
00027 
00032 static ScriptStorage *GetStorage()
00033 {
00034   return ScriptObject::GetActiveInstance()->GetStorage();
00035 }
00036 
00037 
00038 /* static */ ScriptInstance *ScriptObject::ActiveInstance::active = NULL;
00039 
00040 ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance)
00041 {
00042   this->last_active = ScriptObject::ActiveInstance::active;
00043   ScriptObject::ActiveInstance::active = instance;
00044 }
00045 
00046 ScriptObject::ActiveInstance::~ActiveInstance()
00047 {
00048   ScriptObject::ActiveInstance::active = this->last_active;
00049 }
00050 
00051 /* static */ ScriptInstance *ScriptObject::GetActiveInstance()
00052 {
00053   assert(ScriptObject::ActiveInstance::active != NULL);
00054   return ScriptObject::ActiveInstance::active;
00055 }
00056 
00057 
00058 /* static */ void ScriptObject::SetDoCommandDelay(uint ticks)
00059 {
00060   assert(ticks > 0);
00061   GetStorage()->delay = ticks;
00062 }
00063 
00064 /* static */ uint ScriptObject::GetDoCommandDelay()
00065 {
00066   return GetStorage()->delay;
00067 }
00068 
00069 /* static */ void ScriptObject::SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance)
00070 {
00071   GetStorage()->mode = proc;
00072   GetStorage()->mode_instance = instance;
00073 }
00074 
00075 /* static */ ScriptModeProc *ScriptObject::GetDoCommandMode()
00076 {
00077   return GetStorage()->mode;
00078 }
00079 
00080 /* static */ ScriptObject *ScriptObject::GetDoCommandModeInstance()
00081 {
00082   return GetStorage()->mode_instance;
00083 }
00084 
00085 /* static */ void ScriptObject::SetDoCommandCosts(Money value)
00086 {
00087   GetStorage()->costs = CommandCost(value);
00088 }
00089 
00090 /* static */ void ScriptObject::IncreaseDoCommandCosts(Money value)
00091 {
00092   GetStorage()->costs.AddCost(value);
00093 }
00094 
00095 /* static */ Money ScriptObject::GetDoCommandCosts()
00096 {
00097   return GetStorage()->costs.GetCost();
00098 }
00099 
00100 /* static */ void ScriptObject::SetLastError(ScriptErrorType last_error)
00101 {
00102   GetStorage()->last_error = last_error;
00103 }
00104 
00105 /* static */ ScriptErrorType ScriptObject::GetLastError()
00106 {
00107   return GetStorage()->last_error;
00108 }
00109 
00110 /* static */ void ScriptObject::SetLastCost(Money last_cost)
00111 {
00112   GetStorage()->last_cost = last_cost;
00113 }
00114 
00115 /* static */ Money ScriptObject::GetLastCost()
00116 {
00117   return GetStorage()->last_cost;
00118 }
00119 
00120 /* static */ void ScriptObject::SetRoadType(RoadType road_type)
00121 {
00122   GetStorage()->road_type = road_type;
00123 }
00124 
00125 /* static */ RoadType ScriptObject::GetRoadType()
00126 {
00127   return GetStorage()->road_type;
00128 }
00129 
00130 /* static */ void ScriptObject::SetRailType(RailType rail_type)
00131 {
00132   GetStorage()->rail_type = rail_type;
00133 }
00134 
00135 /* static */ RailType ScriptObject::GetRailType()
00136 {
00137   return GetStorage()->rail_type;
00138 }
00139 
00140 /* static */ void ScriptObject::SetLastCommandRes(bool res)
00141 {
00142   GetStorage()->last_command_res = res;
00143   /* Also store the results of various global variables */
00144   SetNewVehicleID(_new_vehicle_id);
00145   SetNewSignID(_new_sign_id);
00146   SetNewGroupID(_new_group_id);
00147   SetNewGoalID(_new_goal_id);
00148 }
00149 
00150 /* static */ bool ScriptObject::GetLastCommandRes()
00151 {
00152   return GetStorage()->last_command_res;
00153 }
00154 
00155 /* static */ void ScriptObject::SetNewVehicleID(VehicleID vehicle_id)
00156 {
00157   GetStorage()->new_vehicle_id = vehicle_id;
00158 }
00159 
00160 /* static */ VehicleID ScriptObject::GetNewVehicleID()
00161 {
00162   return GetStorage()->new_vehicle_id;
00163 }
00164 
00165 /* static */ void ScriptObject::SetNewSignID(SignID sign_id)
00166 {
00167   GetStorage()->new_sign_id = sign_id;
00168 }
00169 
00170 /* static */ SignID ScriptObject::GetNewSignID()
00171 {
00172   return GetStorage()->new_sign_id;
00173 }
00174 
00175 /* static */ void ScriptObject::SetNewGroupID(GroupID group_id)
00176 {
00177   GetStorage()->new_group_id = group_id;
00178 }
00179 
00180 /* static */ GroupID ScriptObject::GetNewGroupID()
00181 {
00182   return GetStorage()->new_group_id;
00183 }
00184 
00185 /* static */ void ScriptObject::SetNewGoalID(GoalID goal_id)
00186 {
00187   GetStorage()->new_goal_id = goal_id;
00188 }
00189 
00190 /* static */ GroupID ScriptObject::GetNewGoalID()
00191 {
00192   return GetStorage()->new_goal_id;
00193 }
00194 
00195 /* static */ void ScriptObject::SetAllowDoCommand(bool allow)
00196 {
00197   GetStorage()->allow_do_command = allow;
00198 }
00199 
00200 /* static */ bool ScriptObject::GetAllowDoCommand()
00201 {
00202   return GetStorage()->allow_do_command;
00203 }
00204 
00205 /* static */ void ScriptObject::SetCompany(CompanyID company)
00206 {
00207   if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
00208   GetStorage()->company = company;
00209 
00210   _current_company = company;
00211 }
00212 
00213 /* static */ CompanyID ScriptObject::GetCompany()
00214 {
00215   return GetStorage()->company;
00216 }
00217 
00218 /* static */ CompanyID ScriptObject::GetRootCompany()
00219 {
00220   return GetStorage()->root_company;
00221 }
00222 
00223 /* static */ bool ScriptObject::CanSuspend()
00224 {
00225   Squirrel *squirrel = ScriptObject::GetActiveInstance()->engine;
00226   return GetStorage()->allow_do_command && squirrel->CanSuspend();
00227 }
00228 
00229 /* static */ void *&ScriptObject::GetEventPointer()
00230 {
00231   return GetStorage()->event_data;
00232 }
00233 
00234 /* static */ void *&ScriptObject::GetLogPointer()
00235 {
00236   return GetStorage()->log_data;
00237 }
00238 
00239 /* static */ void ScriptObject::SetCallbackVariable(int index, int value)
00240 {
00241   if ((size_t)index >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
00242   GetStorage()->callback_value[index] = value;
00243 }
00244 
00245 /* static */ int ScriptObject::GetCallbackVariable(int index)
00246 {
00247   return GetStorage()->callback_value[index];
00248 }
00249 
00250 /* static */ bool ScriptObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, Script_SuspendCallbackProc *callback)
00251 {
00252   if (!ScriptObject::CanSuspend()) {
00253     throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
00254   }
00255 
00256   if (ScriptObject::GetCompany() != OWNER_DEITY && !::Company::IsValidID(ScriptObject::GetCompany())) {
00257     ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY);
00258     return false;
00259   }
00260 
00261   /* Set the default callback to return a true/false result of the DoCommand */
00262   if (callback == NULL) callback = &ScriptInstance::DoCommandReturn;
00263 
00264   /* Are we only interested in the estimate costs? */
00265   bool estimate_only = GetDoCommandMode() != NULL && !GetDoCommandMode()();
00266 
00267 #ifdef ENABLE_NETWORK
00268   /* Only set p2 when the command does not come from the network. */
00269   if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX;
00270 #endif
00271 
00272   /* Try to perform the command. */
00273   CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only);
00274 
00275   /* We failed; set the error and bail out */
00276   if (res.Failed()) {
00277     SetLastError(ScriptError::StringToError(res.GetErrorMessage()));
00278     return false;
00279   }
00280 
00281   /* No error, then clear it. */
00282   SetLastError(ScriptError::ERR_NONE);
00283 
00284   /* Estimates, update the cost for the estimate and be done */
00285   if (estimate_only) {
00286     IncreaseDoCommandCosts(res.GetCost());
00287     return true;
00288   }
00289 
00290   /* Costs of this operation. */
00291   SetLastCost(res.GetCost());
00292   SetLastCommandRes(true);
00293 
00294   if (_generating_world) {
00295     IncreaseDoCommandCosts(res.GetCost());
00296     if (callback != NULL) callback(GetActiveInstance());
00297     return true;
00298   } else if (_networking) {
00299     /* Suspend the AI till the command is really executed. */
00300     throw Script_Suspend(-(int)GetDoCommandDelay(), callback);
00301   } else {
00302     IncreaseDoCommandCosts(res.GetCost());
00303 
00304     /* Suspend the AI player for 1+ ticks, so it simulates multiplayer. This
00305      *  both avoids confusion when a developer launched his AI in a
00306      *  multiplayer game, but also gives time for the GUI and human player
00307      *  to interact with the game. */
00308     throw Script_Suspend(GetDoCommandDelay(), callback);
00309   }
00310 
00311   NOT_REACHED();
00312 }