script_event_types.cpp

Go to the documentation of this file.
00001 /* $Id: script_event_types.cpp 23623 2011-12-19 21:00:32Z 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_event_types.hpp"
00014 #include "script_vehicle.hpp"
00015 #include "script_log.hpp"
00016 #include "../../command_type.h"
00017 #include "../../strings_func.h"
00018 #include "../../settings_type.h"
00019 #include "../../engine_base.h"
00020 #include "../../articulated_vehicles.h"
00021 #include "table/strings.h"
00022 
00023 bool ScriptEventEnginePreview::IsEngineValid() const
00024 {
00025   const Engine *e = ::Engine::GetIfValid(this->engine);
00026   return e != NULL && e->IsEnabled();
00027 }
00028 
00029 char *ScriptEventEnginePreview::GetName()
00030 {
00031   if (!this->IsEngineValid()) return NULL;
00032   static const int len = 64;
00033   char *engine_name = MallocT<char>(len);
00034 
00035 	::SetDParam(0, this->engine);
00036   ::GetString(engine_name, STR_ENGINE_NAME, &engine_name[len - 1]);
00037   return engine_name;
00038 }
00039 
00040 CargoID ScriptEventEnginePreview::GetCargoType()
00041 {
00042   if (!this->IsEngineValid()) return CT_INVALID;
00043   CargoArray cap = ::GetCapacityOfArticulatedParts(this->engine);
00044 
00045   CargoID most_cargo = CT_INVALID;
00046   uint amount = 0;
00047   for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00048     if (cap[cid] > amount) {
00049       amount = cap[cid];
00050       most_cargo = cid;
00051     }
00052   }
00053 
00054   return most_cargo;
00055 }
00056 
00057 int32 ScriptEventEnginePreview::GetCapacity()
00058 {
00059   if (!this->IsEngineValid()) return -1;
00060   const Engine *e = ::Engine::Get(this->engine);
00061   switch (e->type) {
00062     case VEH_ROAD:
00063     case VEH_TRAIN: {
00064       CargoArray capacities = GetCapacityOfArticulatedParts(this->engine);
00065       for (CargoID c = 0; c < NUM_CARGO; c++) {
00066         if (capacities[c] == 0) continue;
00067         return capacities[c];
00068       }
00069       return -1;
00070     }
00071 
00072     case VEH_SHIP:
00073     case VEH_AIRCRAFT:
00074       return e->GetDisplayDefaultCapacity();
00075 
00076     default: NOT_REACHED();
00077   }
00078 }
00079 
00080 int32 ScriptEventEnginePreview::GetMaxSpeed()
00081 {
00082   if (!this->IsEngineValid()) return -1;
00083   const Engine *e = ::Engine::Get(this->engine);
00084   int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
00085   if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed;
00086   return max_speed;
00087 }
00088 
00089 Money ScriptEventEnginePreview::GetPrice()
00090 {
00091   if (!this->IsEngineValid()) return -1;
00092   return ::Engine::Get(this->engine)->GetCost();
00093 }
00094 
00095 Money ScriptEventEnginePreview::GetRunningCost()
00096 {
00097   if (!this->IsEngineValid()) return -1;
00098   return ::Engine::Get(this->engine)->GetRunningCost();
00099 }
00100 
00101 int32 ScriptEventEnginePreview::GetVehicleType()
00102 {
00103   if (!this->IsEngineValid()) return ScriptVehicle::VT_INVALID;
00104   switch (::Engine::Get(this->engine)->type) {
00105     case VEH_ROAD:     return ScriptVehicle::VT_ROAD;
00106     case VEH_TRAIN:    return ScriptVehicle::VT_RAIL;
00107     case VEH_SHIP:     return ScriptVehicle::VT_WATER;
00108     case VEH_AIRCRAFT: return ScriptVehicle::VT_AIR;
00109     default: NOT_REACHED();
00110   }
00111 }
00112 
00113 bool ScriptEventEnginePreview::AcceptPreview()
00114 {
00115   if (!this->IsEngineValid()) return false;
00116   return ScriptObject::DoCommand(0, this->engine, 0, CMD_WANT_ENGINE_PREVIEW);
00117 }
00118 
00119 bool ScriptEventCompanyAskMerger::AcceptMerger()
00120 {
00121   return ScriptObject::DoCommand(0, this->owner, 0, CMD_BUY_COMPANY);
00122 }
00123 
00124 #define SKIP_EMPTY(p) while (*(p) == ' ' || *(p) == '\n' || *(p) == '\r') (p)++;
00125 #define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return NULL; }
00126 
00127 SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm)
00128 {
00129   char *p = this->json;
00130 
00131   if (this->ReadTable(vm, p) == NULL) {
00132     sq_pushnull(vm);
00133     return 1;
00134   }
00135 
00136   return 1;
00137 }
00138 
00139 char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, char *p)
00140 {
00141   char *value = p;
00142 
00143   bool escape = false;
00144   for (;;) {
00145     if (*p == '\\') {
00146       escape = true;
00147       p++;
00148       continue;
00149     }
00150     if (*p == '"' && escape) {
00151       escape = false;
00152       p++;
00153       continue;
00154     }
00155     escape = false;
00156 
00157     if (*p == '"') break;
00158     if (*p == '\0') RETURN_ERROR(0);
00159 
00160     p++;
00161   }
00162 
00163   *p = '\0';
00164   sq_pushstring(vm, OTTD2SQ(value), -1);
00165   *p++ = '"';
00166 
00167   return p;
00168 }
00169 
00170 char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, char *p)
00171 {
00172   sq_newtable(vm);
00173 
00174   SKIP_EMPTY(p);
00175   if (*p++ != '{') RETURN_ERROR(1);
00176 
00177   for (;;) {
00178     SKIP_EMPTY(p);
00179     if (*p++ != '"') RETURN_ERROR(1);
00180 
00181     p = ReadString(vm, p);
00182     if (p == NULL) {
00183       sq_pop(vm, 1);
00184       return NULL;
00185     }
00186 
00187     SKIP_EMPTY(p);
00188     if (*p++ != ':') RETURN_ERROR(2);
00189 
00190     p = this->ReadValue(vm, p);
00191     if (p == NULL) {
00192       sq_pop(vm, 2);
00193       return NULL;
00194     }
00195 
00196     sq_rawset(vm, -3);
00197     /* The key (-2) and value (-1) are popped from the stack by squirrel. */
00198 
00199     SKIP_EMPTY(p);
00200     if (*p == ',') {
00201       p++;
00202       continue;
00203     }
00204     break;
00205   }
00206 
00207   SKIP_EMPTY(p);
00208   if (*p++ != '}') RETURN_ERROR(1);
00209 
00210   return p;
00211 }
00212 
00213 char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p)
00214 {
00215   SKIP_EMPTY(p);
00216 
00217   if (strncmp(p, "false", 5) == 0) {
00218     sq_pushinteger(vm, 0);
00219     return p + 5;
00220   }
00221   if (strncmp(p, "true", 4) == 0) {
00222     sq_pushinteger(vm, 1);
00223     return p + 4;
00224   }
00225   if (strncmp(p, "null", 4) == 0) {
00226     sq_pushnull(vm);
00227     return p + 4;
00228   }
00229 
00230   switch (*p) {
00231     case '"': {
00232       /* String */
00233       p = ReadString(vm, ++p);
00234       if (p == NULL) return NULL;
00235 
00236       break;
00237     }
00238 
00239     case '{': {
00240       /* Table */
00241       p = this->ReadTable(vm, p);
00242       if (p == NULL) return NULL;
00243 
00244       break;
00245     }
00246 
00247     case '[': {
00248       /* Array */
00249       sq_newarray(vm, 0);
00250 
00251       while (*p++ != ']') {
00252         p = this->ReadValue(vm, p);
00253         if (p == NULL) {
00254           sq_pop(vm, 1);
00255           return NULL;
00256         }
00257         sq_arrayappend(vm, -2);
00258 
00259         SKIP_EMPTY(p);
00260         if (*p == ',') continue;
00261         if (*p == ']') break;
00262         RETURN_ERROR(1);
00263       }
00264 
00265       p++;
00266 
00267       break;
00268     }
00269 
00270     case '1': case '2': case '3': case '4': case '5':
00271     case '6': case '7': case '8': case '9': case '0':
00272     case '-': {
00273       /* Integer */
00274 
00275       const char *value = p++;
00276       for (;;) {
00277         switch (*p++) {
00278           case '1': case '2': case '3': case '4': case '5':
00279           case '6': case '7': case '8': case '9': case '0':
00280             continue;
00281 
00282           default:
00283             break;
00284         }
00285 
00286         p--;
00287         break;
00288       }
00289 
00290       int res = atoi(value);
00291       sq_pushinteger(vm, (SQInteger)res);
00292 
00293       break;
00294     }
00295 
00296     default:
00297       RETURN_ERROR(0);
00298   }
00299 
00300   return p;
00301 }
00302 
00303 #undef SKIP_EMPTY
00304 #undef RETURN_ERROR