engine.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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 "company_func.h"
00014 #include "command_func.h"
00015 #include "news_func.h"
00016 #include "aircraft.h"
00017 #include "newgrf.h"
00018 #include "newgrf_engine.h"
00019 #include "group.h"
00020 #include "strings_func.h"
00021 #include "gfx_func.h"
00022 #include "core/random_func.hpp"
00023 #include "window_func.h"
00024 #include "date_func.h"
00025 #include "autoreplace_gui.h"
00026 #include "string_func.h"
00027 #include "ai/ai.hpp"
00028 #include "core/pool_func.hpp"
00029 #include "engine_gui.h"
00030 
00031 #include "table/strings.h"
00032 #include "table/engines.h"
00033 
00034 EnginePool _engine_pool("Engine");
00035 INSTANTIATE_POOL_METHODS(Engine)
00036 
00037 EngineOverrideManager _engine_mngr;
00038 
00041 static Year _year_engine_aging_stops;
00042 
00044 const uint8 _engine_counts[4] = {
00045   lengthof(_orig_rail_vehicle_info),
00046   lengthof(_orig_road_vehicle_info),
00047   lengthof(_orig_ship_vehicle_info),
00048   lengthof(_orig_aircraft_vehicle_info),
00049 };
00050 
00052 const uint8 _engine_offsets[4] = {
00053   0,
00054   lengthof(_orig_rail_vehicle_info),
00055   lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
00056   lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
00057 };
00058 
00059 assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info));
00060 
00061 const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT];
00062 
00063 Engine::Engine() :
00064   name(NULL),
00065   overrides_count(0),
00066   overrides(NULL)
00067 {
00068 }
00069 
00070 Engine::Engine(VehicleType type, EngineID base)
00071 {
00072   this->type = type;
00073   this->internal_id = base;
00074   this->list_position = base;
00075 
00076   /* Check if this base engine is within the original engine data range */
00077   if (base >= _engine_counts[type]) {
00078     /* Mark engine as valid anyway */
00079     this->info.climates = 0x80;
00080     /* Set model life to maximum to make wagons available */
00081     this->info.base_life = 0xFF;
00082     return;
00083   }
00084 
00085   /* Copy the original engine info for this slot */
00086   this->info = _orig_engine_info[_engine_offsets[type] + base];
00087 
00088   /* Copy the original engine data for this slot */
00089   switch (type) {
00090     default: NOT_REACHED();
00091 
00092     case VEH_TRAIN:
00093       this->u.rail = _orig_rail_vehicle_info[base];
00094       this->original_image_index = this->u.rail.image_index;
00095       this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + base;
00096 
00097       /* Set the default model life of original wagons to "infinite" */
00098       if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = 0xFF;
00099 
00100       break;
00101 
00102     case VEH_ROAD:
00103       this->u.road = _orig_road_vehicle_info[base];
00104       this->original_image_index = this->u.road.image_index;
00105       this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + base;
00106       break;
00107 
00108     case VEH_SHIP:
00109       this->u.ship = _orig_ship_vehicle_info[base];
00110       this->original_image_index = this->u.ship.image_index;
00111       this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + base;
00112       break;
00113 
00114     case VEH_AIRCRAFT:
00115       this->u.air = _orig_aircraft_vehicle_info[base];
00116       this->original_image_index = this->u.air.image_index;
00117       this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + base;
00118       break;
00119   }
00120 }
00121 
00122 Engine::~Engine()
00123 {
00124   UnloadWagonOverrides(this);
00125   free(this->name);
00126 }
00127 
00133 bool Engine::CanCarryCargo() const
00134 {
00135   /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
00136    * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
00137    * for livery selection etc.
00138    * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
00139    */
00140   switch (this->type) {
00141     case VEH_TRAIN:
00142       if (this->u.rail.capacity == 0) return false;
00143       break;
00144 
00145     case VEH_ROAD:
00146       if (this->u.road.capacity == 0) return false;
00147       break;
00148 
00149     case VEH_SHIP:
00150     case VEH_AIRCRAFT:
00151       break;
00152 
00153     default: NOT_REACHED();
00154   }
00155   return this->GetDefaultCargoType() != CT_INVALID;
00156 }
00157 
00170 uint Engine::GetDisplayDefaultCapacity(uint16 *mail_capacity) const
00171 {
00172   if (mail_capacity != NULL) *mail_capacity = 0;
00173   if (!this->CanCarryCargo()) return 0;
00174   switch (type) {
00175     case VEH_TRAIN:
00176       return GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity) + (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? this->u.rail.capacity : 0);
00177 
00178     case VEH_ROAD:
00179       return GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity);
00180 
00181     case VEH_SHIP:
00182       return GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity);
00183 
00184     case VEH_AIRCRAFT: {
00185       uint capacity = this->u.air.passenger_capacity;
00186       CargoID cargo = this->GetDefaultCargoType();
00187       if (IsCargoInClass(cargo, CC_PASSENGERS)) {
00188         if (mail_capacity != NULL) *mail_capacity = this->u.air.mail_capacity;
00189       } else {
00190         capacity += this->u.air.mail_capacity;
00191       }
00192       switch (cargo) {
00193         case CT_PASSENGERS:
00194         case CT_MAIL:       return capacity;
00195         case CT_GOODS:      return capacity / 2;
00196         default:            return capacity / 4;
00197       }
00198     }
00199 
00200     default: NOT_REACHED();
00201   }
00202 }
00203 
00204 Money Engine::GetRunningCost() const
00205 {
00206   Price base_price;
00207   uint cost_factor;
00208   switch (this->type) {
00209     case VEH_ROAD:
00210       base_price = this->u.road.running_cost_class;
00211       if (base_price == INVALID_PRICE) return 0;
00212       cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
00213       break;
00214 
00215     case VEH_TRAIN:
00216       base_price = this->u.rail.running_cost_class;
00217       if (base_price == INVALID_PRICE) return 0;
00218       cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
00219       break;
00220 
00221     case VEH_SHIP:
00222       base_price = PR_RUNNING_SHIP;
00223       cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
00224       break;
00225 
00226     case VEH_AIRCRAFT:
00227       base_price = PR_RUNNING_AIRCRAFT;
00228       cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
00229       break;
00230 
00231     default: NOT_REACHED();
00232   }
00233 
00234   return GetPrice(base_price, cost_factor, this->grffile, -8);
00235 }
00236 
00237 Money Engine::GetCost() const
00238 {
00239   Price base_price;
00240   uint cost_factor;
00241   switch (this->type) {
00242     case VEH_ROAD:
00243       base_price = PR_BUILD_VEHICLE_ROAD;
00244       cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor);
00245       break;
00246 
00247     case VEH_TRAIN:
00248       if (this->u.rail.railveh_type == RAILVEH_WAGON) {
00249         base_price = PR_BUILD_VEHICLE_WAGON;
00250         cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
00251       } else {
00252         base_price = PR_BUILD_VEHICLE_TRAIN;
00253         cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
00254       }
00255       break;
00256 
00257     case VEH_SHIP:
00258       base_price = PR_BUILD_VEHICLE_SHIP;
00259       cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor);
00260       break;
00261 
00262     case VEH_AIRCRAFT:
00263       base_price = PR_BUILD_VEHICLE_AIRCRAFT;
00264       cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor);
00265       break;
00266 
00267     default: NOT_REACHED();
00268   }
00269 
00270   return GetPrice(base_price, cost_factor, this->grffile, -8);
00271 }
00272 
00277 uint Engine::GetDisplayMaxSpeed() const
00278 {
00279   switch (this->type) {
00280     case VEH_TRAIN:
00281       return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed);
00282 
00283     case VEH_ROAD:
00284       return this->u.road.max_speed / 2;
00285 
00286     case VEH_SHIP:
00287       return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2;
00288 
00289     case VEH_AIRCRAFT:
00290       return this->u.air.max_speed;
00291 
00292     default: NOT_REACHED();
00293   }
00294 }
00295 
00296 uint Engine::GetPower() const
00297 {
00298   /* Currently only trains have 'power' */
00299   switch (this->type) {
00300     case VEH_TRAIN:
00301       return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power);
00302 
00303     default: NOT_REACHED();
00304   }
00305 }
00306 
00312 uint Engine::GetDisplayWeight() const
00313 {
00314   /* Currently only trains have 'weight' */
00315   switch (this->type) {
00316     case VEH_TRAIN:
00317       return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
00318 
00319     default: NOT_REACHED();
00320   }
00321 }
00322 
00328 uint Engine::GetDisplayMaxTractiveEffort() const
00329 {
00330   /* Currently only trains have 'tractive effort' */
00331   switch (this->type) {
00332     case VEH_TRAIN:
00333       return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
00334 
00335     default: NOT_REACHED();
00336   }
00337 }
00338 
00343 Date Engine::GetLifeLengthInDays() const
00344 {
00345   /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
00346   return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * DAYS_IN_LEAP_YEAR;
00347 }
00348 
00352 void EngineOverrideManager::ResetToDefaultMapping()
00353 {
00354   this->Clear();
00355   for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
00356     for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
00357       EngineIDMapping *eid = this->Append();
00358       eid->type            = type;
00359       eid->grfid           = INVALID_GRFID;
00360       eid->internal_id     = internal_id;
00361       eid->substitute_id   = internal_id;
00362     }
00363   }
00364 }
00365 
00375 EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
00376 {
00377   const EngineIDMapping *end = this->End();
00378   EngineID index = 0;
00379   for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
00380     if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
00381       return index;
00382     }
00383   }
00384   return INVALID_ENGINE;
00385 }
00386 
00389 void SetCachedEngineCounts()
00390 {
00391   size_t engines = Engine::GetPoolSize();
00392 
00393   /* Set up the engine count for all companies */
00394   Company *c;
00395   FOR_ALL_COMPANIES(c) {
00396     free(c->num_engines);
00397     c->num_engines = CallocT<EngineID>(engines);
00398   }
00399 
00400   /* Recalculate */
00401   Group *g;
00402   FOR_ALL_GROUPS(g) {
00403     free(g->num_engines);
00404     g->num_engines = CallocT<EngineID>(engines);
00405   }
00406 
00407   const Vehicle *v;
00408   FOR_ALL_VEHICLES(v) {
00409     if (!v->IsEngineCountable()) continue;
00410 
00411     assert(v->engine_type < engines);
00412 
00413     Company::Get(v->owner)->num_engines[v->engine_type]++;
00414 
00415     if (v->group_id == DEFAULT_GROUP) continue;
00416 
00417     g = Group::Get(v->group_id);
00418     assert(v->type == g->vehicle_type);
00419     assert(v->owner == g->owner);
00420 
00421     g->num_engines[v->engine_type]++;
00422   }
00423 }
00424 
00425 void SetupEngines()
00426 {
00427   _engine_pool.CleanPool();
00428 
00429   assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
00430   const EngineIDMapping *end = _engine_mngr.End();
00431   uint index = 0;
00432   for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
00433     const Engine *e = new Engine(eid->type, eid->internal_id);
00434     assert(e->index == index);
00435   }
00436 }
00437 
00438 
00439 void ShowEnginePreviewWindow(EngineID engine);
00440 
00441 /* Determine if an engine type is a wagon (and not a loco) */
00442 static bool IsWagon(EngineID index)
00443 {
00444   const Engine *e = Engine::Get(index);
00445   return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
00446 }
00447 
00448 static void CalcEngineReliability(Engine *e)
00449 {
00450   uint age = e->age;
00451 
00452   /* Check for early retirement */
00453   if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
00454     int retire_early = e->info.retire_early;
00455     uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
00456     if (retire_early != 0 && age >= retire_early_max_age) {
00457       /* Early retirement is enabled and we're past the date... */
00458       e->company_avail = 0;
00459       AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00460     }
00461   }
00462 
00463   if (age < e->duration_phase_1) {
00464     uint start = e->reliability_start;
00465     e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
00466   } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
00467     /* We are at the peak of this engines life. It will have max reliability.
00468      * This is also true if the engines never expire. They will not go bad over time */
00469     e->reliability = e->reliability_max;
00470   } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
00471     uint max = e->reliability_max;
00472     e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
00473   } else {
00474     /* time's up for this engine.
00475      * We will now completely retire this design */
00476     e->company_avail = 0;
00477     e->reliability = e->reliability_final;
00478     /* Kick this engine out of the lists */
00479     AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00480   }
00481   SetWindowClassesDirty(WC_BUILD_VEHICLE); // Update to show the new reliability
00482   SetWindowClassesDirty(WC_REPLACE_VEHICLE);
00483 }
00484 
00485 void SetYearEngineAgingStops()
00486 {
00487   /* Determine last engine aging year, default to 2050 as previously. */
00488   _year_engine_aging_stops = 2050;
00489 
00490   const Engine *e;
00491   FOR_ALL_ENGINES(e) {
00492     const EngineInfo *ei = &e->info;
00493 
00494     /* Exclude certain engines */
00495     if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
00496     if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
00497 
00498     /* Base year ending date on half the model life */
00499     YearMonthDay ymd;
00500     ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd);
00501 
00502     _year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year);
00503   }
00504 }
00505 
00506 void StartupOneEngine(Engine *e, Date aging_date)
00507 {
00508   const EngineInfo *ei = &e->info;
00509   uint32 r;
00510 
00511   e->age = 0;
00512   e->flags = 0;
00513   e->company_avail = 0;
00514 
00515   /* Don't randomise the start-date in the first two years after gamestart to ensure availability
00516    * of engines in early starting games.
00517    * Note: TTDP uses fixed 1922 */
00518   r = Random();
00519   e->intro_date = ei->base_intro <= ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
00520   if (e->intro_date <= _date) {
00521     e->age = (aging_date - e->intro_date) >> 5;
00522     e->company_avail = (CompanyMask)-1;
00523     e->flags |= ENGINE_AVAILABLE;
00524   }
00525 
00526   e->reliability_start = GB(r, 16, 14) + 0x7AE0;
00527   r = Random();
00528   e->reliability_max   = GB(r,  0, 14) + 0xBFFF;
00529   e->reliability_final = GB(r, 16, 14) + 0x3FFF;
00530 
00531   r = Random();
00532   e->duration_phase_1 = GB(r, 0, 5) + 7;
00533   e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
00534   e->duration_phase_3 = GB(r, 9, 7) + 120;
00535 
00536   e->reliability_spd_dec = ei->decay_speed << 2;
00537 
00538   CalcEngineReliability(e);
00539 
00540   /* prevent certain engines from ever appearing. */
00541   if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) {
00542     e->flags |= ENGINE_AVAILABLE;
00543     e->company_avail = 0;
00544   }
00545 }
00546 
00547 void StartupEngines()
00548 {
00549   Engine *e;
00550   /* Aging of vehicles stops, so account for that when starting late */
00551   const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
00552 
00553   FOR_ALL_ENGINES(e) {
00554     StartupOneEngine(e, aging_date);
00555   }
00556 
00557   /* Update the bitmasks for the vehicle lists */
00558   Company *c;
00559   FOR_ALL_COMPANIES(c) {
00560     c->avail_railtypes = GetCompanyRailtypes(c->index);
00561     c->avail_roadtypes = GetCompanyRoadtypes(c->index);
00562   }
00563 }
00564 
00565 static void AcceptEnginePreview(EngineID eid, CompanyID company)
00566 {
00567   Engine *e = Engine::Get(eid);
00568   Company *c = Company::Get(company);
00569 
00570   SetBit(e->company_avail, company);
00571   if (e->type == VEH_TRAIN) {
00572     assert(e->u.rail.railtype < RAILTYPE_END);
00573     SetBit(c->avail_railtypes, e->u.rail.railtype);
00574   } else if (e->type == VEH_ROAD) {
00575     SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00576   }
00577 
00578   e->preview_company_rank = 0xFF;
00579   if (company == _local_company) {
00580     AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00581   }
00582 }
00583 
00584 static CompanyID GetBestCompany(uint8 pp)
00585 {
00586   const Company *c;
00587   int32 best_hist;
00588   CompanyID best_company;
00589   CompanyMask mask = 0;
00590 
00591   do {
00592     best_hist = -1;
00593     best_company = INVALID_COMPANY;
00594     FOR_ALL_COMPANIES(c) {
00595       if (c->block_preview == 0 && !HasBit(mask, c->index) &&
00596           c->old_economy[0].performance_history > best_hist) {
00597         best_hist = c->old_economy[0].performance_history;
00598         best_company = c->index;
00599       }
00600     }
00601 
00602     if (best_company == INVALID_COMPANY) return INVALID_COMPANY;
00603 
00604     SetBit(mask, best_company);
00605   } while (--pp != 0);
00606 
00607   return best_company;
00608 }
00609 
00610 void EnginesDailyLoop()
00611 {
00612   if (_cur_year >= _year_engine_aging_stops) return;
00613 
00614   Engine *e;
00615   FOR_ALL_ENGINES(e) {
00616     EngineID i = e->index;
00617     if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00618       if (e->flags & ENGINE_OFFER_WINDOW_OPEN) {
00619         if (e->preview_company_rank != 0xFF && !--e->preview_wait) {
00620           e->flags &= ~ENGINE_OFFER_WINDOW_OPEN;
00621           DeleteWindowById(WC_ENGINE_PREVIEW, i);
00622           e->preview_company_rank++;
00623         }
00624       } else if (e->preview_company_rank != 0xFF) {
00625         CompanyID best_company = GetBestCompany(e->preview_company_rank);
00626 
00627         if (best_company == INVALID_COMPANY) {
00628           e->preview_company_rank = 0xFF;
00629           continue;
00630         }
00631 
00632         e->flags |= ENGINE_OFFER_WINDOW_OPEN;
00633         e->preview_wait = 20;
00634         AI::NewEvent(best_company, new AIEventEnginePreview(i));
00635         if (IsInteractiveCompany(best_company)) ShowEnginePreviewWindow(i);
00636       }
00637     }
00638   }
00639 }
00640 
00650 CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00651 {
00652   Engine *e = Engine::GetIfValid(p1);
00653   if (e == NULL || GetBestCompany(e->preview_company_rank) != _current_company) return CMD_ERROR;
00654 
00655   if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company);
00656 
00657   return CommandCost();
00658 }
00659 
00660 static void NewVehicleAvailable(Engine *e)
00661 {
00662   Vehicle *v;
00663   Company *c;
00664   EngineID index = e->index;
00665 
00666   /* In case the company didn't build the vehicle during the intro period,
00667    * prevent that company from getting future intro periods for a while. */
00668   if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00669     FOR_ALL_COMPANIES(c) {
00670       uint block_preview = c->block_preview;
00671 
00672       if (!HasBit(e->company_avail, c->index)) continue;
00673 
00674       /* We assume the user did NOT build it.. prove me wrong ;) */
00675       c->block_preview = 20;
00676 
00677       FOR_ALL_VEHICLES(v) {
00678         if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP ||
00679             (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft())) {
00680           if (v->owner == c->index && v->engine_type == index) {
00681             /* The user did prove me wrong, so restore old value */
00682             c->block_preview = block_preview;
00683             break;
00684           }
00685         }
00686       }
00687     }
00688   }
00689 
00690   e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
00691   AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00692 
00693   /* Now available for all companies */
00694   e->company_avail = (CompanyMask)-1;
00695 
00696   /* Do not introduce new rail wagons */
00697   if (IsWagon(index)) return;
00698 
00699   if (e->type == VEH_TRAIN) {
00700     /* maybe make another rail type available */
00701     RailType railtype = e->u.rail.railtype;
00702     assert(railtype < RAILTYPE_END);
00703     FOR_ALL_COMPANIES(c) SetBit(c->avail_railtypes, railtype);
00704   } else if (e->type == VEH_ROAD) {
00705     /* maybe make another road type available */
00706     FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00707   }
00708 
00709   AI::BroadcastNewEvent(new AIEventEngineAvailable(index));
00710 
00711   SetDParam(0, GetEngineCategoryName(index));
00712   SetDParam(1, index);
00713   AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, NR_ENGINE, index);
00714 }
00715 
00716 void EnginesMonthlyLoop()
00717 {
00718   if (_cur_year < _year_engine_aging_stops) {
00719     Engine *e;
00720     FOR_ALL_ENGINES(e) {
00721       /* Age the vehicle */
00722       if ((e->flags & ENGINE_AVAILABLE) && e->age != 0xFFFF) {
00723         e->age++;
00724         CalcEngineReliability(e);
00725       }
00726 
00727       if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) {
00728         /* Introduce it to all companies */
00729         NewVehicleAvailable(e);
00730       } else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
00731         /* Introduction date has passed.. show introducing dialog to one companies. */
00732         e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
00733 
00734         /* Do not introduce new rail wagons */
00735         if (!IsWagon(e->index))
00736           e->preview_company_rank = 1; // Give to the company with the highest rating.
00737       }
00738     }
00739   }
00740 }
00741 
00742 static bool IsUniqueEngineName(const char *name)
00743 {
00744   const Engine *e;
00745 
00746   FOR_ALL_ENGINES(e) {
00747     if (e->name != NULL && strcmp(e->name, name) == 0) return false;
00748   }
00749 
00750   return true;
00751 }
00752 
00761 CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00762 {
00763   Engine *e = Engine::GetIfValid(p1);
00764   if (e == NULL) return CMD_ERROR;
00765 
00766   bool reset = StrEmpty(text);
00767 
00768   if (!reset) {
00769     if (strlen(text) >= MAX_LENGTH_ENGINE_NAME_BYTES) return CMD_ERROR;
00770     if (!IsUniqueEngineName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
00771   }
00772 
00773   if (flags & DC_EXEC) {
00774     free(e->name);
00775 
00776     if (reset) {
00777       e->name = NULL;
00778     } else {
00779       e->name = strdup(text);
00780     }
00781 
00782     MarkWholeScreenDirty();
00783   }
00784 
00785   return CommandCost();
00786 }
00787 
00788 
00796 bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
00797 {
00798   const Engine *e = Engine::GetIfValid(engine);
00799 
00800   /* check if it's an engine that is in the engine array */
00801   if (e == NULL) return false;
00802 
00803   /* check if it's an engine of specified type */
00804   if (e->type != type) return false;
00805 
00806   /* check if it's available */
00807   if (!HasBit(e->company_avail, company)) return false;
00808 
00809   if (type == VEH_TRAIN) {
00810     /* Check if the rail type is available to this company */
00811     const Company *c = Company::Get(company);
00812     if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false;
00813   }
00814 
00815   return true;
00816 }
00817 
00824 bool IsEngineRefittable(EngineID engine)
00825 {
00826   const Engine *e = Engine::GetIfValid(engine);
00827 
00828   /* check if it's an engine that is in the engine array */
00829   if (e == NULL) return false;
00830 
00831   if (!e->CanCarryCargo()) return false;
00832 
00833   const EngineInfo *ei = &e->info;
00834   if (ei->refit_mask == 0) return false;
00835 
00836   /* Are there suffixes?
00837    * Note: This does not mean the suffixes are actually available for every consist at any time. */
00838   if (HasBit(ei->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) return true;
00839 
00840   /* Is there any cargo except the default cargo? */
00841   CargoID default_cargo = e->GetDefaultCargoType();
00842   return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo;
00843 }

Generated on Wed Dec 30 20:40:02 2009 for OpenTTD by  doxygen 1.5.6