00001
00002
00003
00004
00005
00006
00007
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 "core/random_func.hpp"
00022 #include "window_func.h"
00023 #include "date_func.h"
00024 #include "autoreplace_gui.h"
00025 #include "string_func.h"
00026 #include "ai/ai.hpp"
00027 #include "core/pool_func.hpp"
00028 #include "engine_gui.h"
00029 #include "engine_func.h"
00030 #include "engine_base.h"
00031 #include "company_base.h"
00032 #include "vehicle_func.h"
00033
00034 #include "table/strings.h"
00035 #include "table/engines.h"
00036
00037 EnginePool _engine_pool("Engine");
00038 INSTANTIATE_POOL_METHODS(Engine)
00039
00040 EngineOverrideManager _engine_mngr;
00041
00046 static Year _year_engine_aging_stops;
00047
00051 static uint16 _introduced_railtypes;
00052
00054 const uint8 _engine_counts[4] = {
00055 lengthof(_orig_rail_vehicle_info),
00056 lengthof(_orig_road_vehicle_info),
00057 lengthof(_orig_ship_vehicle_info),
00058 lengthof(_orig_aircraft_vehicle_info),
00059 };
00060
00062 const uint8 _engine_offsets[4] = {
00063 0,
00064 lengthof(_orig_rail_vehicle_info),
00065 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
00066 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
00067 };
00068
00069 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));
00070
00071 const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT];
00072
00073 Engine::Engine() :
00074 name(NULL),
00075 overrides_count(0),
00076 overrides(NULL)
00077 {
00078 }
00079
00080 Engine::Engine(VehicleType type, EngineID base)
00081 {
00082 this->type = type;
00083 this->grf_prop.local_id = base;
00084 this->list_position = base;
00085
00086
00087 if (base >= _engine_counts[type]) {
00088
00089 this->info.base_life = 0xFF;
00090
00091 if (type == VEH_ROAD) this->u.road.tractive_effort = 0x4C;
00092
00093 if (type == VEH_AIRCRAFT) this->info.cargo_type = CT_INVALID;
00094
00095 switch (type) {
00096 case VEH_TRAIN: this->u.rail.visual_effect = VE_DEFAULT; break;
00097 case VEH_ROAD: this->u.road.visual_effect = VE_DEFAULT; break;
00098 case VEH_SHIP: this->u.ship.visual_effect = VE_DEFAULT; break;
00099 default: break;
00100 }
00101
00102 this->info.cargo_age_period = CARGO_AGING_TICKS;
00103 return;
00104 }
00105
00106
00107 this->info = _orig_engine_info[_engine_offsets[type] + base];
00108
00109
00110 switch (type) {
00111 default: NOT_REACHED();
00112
00113 case VEH_TRAIN:
00114 this->u.rail = _orig_rail_vehicle_info[base];
00115 this->original_image_index = this->u.rail.image_index;
00116 this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + base;
00117
00118
00119 if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = 0xFF;
00120
00121 break;
00122
00123 case VEH_ROAD:
00124 this->u.road = _orig_road_vehicle_info[base];
00125 this->original_image_index = this->u.road.image_index;
00126 this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + base;
00127 break;
00128
00129 case VEH_SHIP:
00130 this->u.ship = _orig_ship_vehicle_info[base];
00131 this->original_image_index = this->u.ship.image_index;
00132 this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + base;
00133 break;
00134
00135 case VEH_AIRCRAFT:
00136 this->u.air = _orig_aircraft_vehicle_info[base];
00137 this->original_image_index = this->u.air.image_index;
00138 this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + base;
00139 break;
00140 }
00141 }
00142
00143 Engine::~Engine()
00144 {
00145 UnloadWagonOverrides(this);
00146 free(this->name);
00147 }
00148
00153 bool Engine::IsEnabled() const
00154 {
00155 return this->info.string_id != STR_NEWGRF_INVALID_ENGINE;
00156 }
00157
00163 uint32 Engine::GetGRFID() const
00164 {
00165 const GRFFile *file = this->GetGRF();
00166 return file == NULL ? 0 : file->grfid;
00167 }
00168
00174 bool Engine::CanCarryCargo() const
00175 {
00176
00177
00178
00179
00180
00181 switch (this->type) {
00182 case VEH_TRAIN:
00183 if (this->u.rail.capacity == 0) return false;
00184 break;
00185
00186 case VEH_ROAD:
00187 if (this->u.road.capacity == 0) return false;
00188 break;
00189
00190 case VEH_SHIP:
00191 case VEH_AIRCRAFT:
00192 break;
00193
00194 default: NOT_REACHED();
00195 }
00196 return this->GetDefaultCargoType() != CT_INVALID;
00197 }
00198
00199
00207 uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const
00208 {
00209 assert(v == NULL || this->index == v->engine_type);
00210 if (mail_capacity != NULL) *mail_capacity = 0;
00211
00212 if (!this->CanCarryCargo()) return 0;
00213
00214 CargoID default_cargo = this->GetDefaultCargoType();
00215 CargoID cargo_type = (v != NULL) ? v->cargo_type : default_cargo;
00216
00217 if (mail_capacity != NULL && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) {
00218 *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
00219 }
00220
00221
00222
00223 if (HasBit(this->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
00224 (default_cargo != cargo_type || (v != NULL && v->cargo_subtype != 0))) {
00225 uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
00226 if (callback != CALLBACK_FAILED) return callback;
00227 }
00228
00229
00230 uint capacity;
00231 switch (this->type) {
00232 case VEH_TRAIN:
00233 capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v);
00234
00235
00236 if (v == NULL && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity;
00237 break;
00238
00239 case VEH_ROAD:
00240 capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v);
00241 break;
00242
00243 case VEH_SHIP:
00244 capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v);
00245 break;
00246
00247 case VEH_AIRCRAFT:
00248 capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v);
00249 if (!IsCargoInClass(cargo_type, CC_PASSENGERS)) {
00250 capacity += GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
00251 }
00252 if (cargo_type == CT_MAIL) return capacity;
00253 default_cargo = CT_PASSENGERS;
00254 break;
00255
00256 default: NOT_REACHED();
00257 }
00258
00259
00260
00261 if (this->type != VEH_SHIP && default_cargo != cargo_type) {
00262 switch (default_cargo) {
00263 case CT_PASSENGERS: break;
00264 case CT_MAIL:
00265 case CT_GOODS: capacity *= 2; break;
00266 default: capacity *= 4; break;
00267 }
00268 switch (cargo_type) {
00269 case CT_PASSENGERS: break;
00270 case CT_MAIL:
00271 case CT_GOODS: capacity /= 2; break;
00272 default: capacity /= 4; break;
00273 }
00274 }
00275
00276 return capacity;
00277 }
00278
00283 Money Engine::GetRunningCost() const
00284 {
00285 Price base_price;
00286 uint cost_factor;
00287 switch (this->type) {
00288 case VEH_ROAD:
00289 base_price = this->u.road.running_cost_class;
00290 if (base_price == INVALID_PRICE) return 0;
00291 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
00292 break;
00293
00294 case VEH_TRAIN:
00295 base_price = this->u.rail.running_cost_class;
00296 if (base_price == INVALID_PRICE) return 0;
00297 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
00298 break;
00299
00300 case VEH_SHIP:
00301 base_price = PR_RUNNING_SHIP;
00302 cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
00303 break;
00304
00305 case VEH_AIRCRAFT:
00306 base_price = PR_RUNNING_AIRCRAFT;
00307 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
00308 break;
00309
00310 default: NOT_REACHED();
00311 }
00312
00313 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
00314 }
00315
00320 Money Engine::GetCost() const
00321 {
00322 Price base_price;
00323 uint cost_factor;
00324 switch (this->type) {
00325 case VEH_ROAD:
00326 base_price = PR_BUILD_VEHICLE_ROAD;
00327 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor);
00328 break;
00329
00330 case VEH_TRAIN:
00331 if (this->u.rail.railveh_type == RAILVEH_WAGON) {
00332 base_price = PR_BUILD_VEHICLE_WAGON;
00333 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
00334 } else {
00335 base_price = PR_BUILD_VEHICLE_TRAIN;
00336 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
00337 }
00338 break;
00339
00340 case VEH_SHIP:
00341 base_price = PR_BUILD_VEHICLE_SHIP;
00342 cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor);
00343 break;
00344
00345 case VEH_AIRCRAFT:
00346 base_price = PR_BUILD_VEHICLE_AIRCRAFT;
00347 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor);
00348 break;
00349
00350 default: NOT_REACHED();
00351 }
00352
00353 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
00354 }
00355
00360 uint Engine::GetDisplayMaxSpeed() const
00361 {
00362 switch (this->type) {
00363 case VEH_TRAIN:
00364 return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed);
00365
00366 case VEH_ROAD: {
00367 uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
00368 return (max_speed != 0) ? max_speed * 2 : this->u.road.max_speed / 2;
00369 }
00370
00371 case VEH_SHIP:
00372 return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2;
00373
00374 case VEH_AIRCRAFT: {
00375 uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
00376 if (max_speed != 0) {
00377 return (max_speed * 128) / 10;
00378 }
00379 return this->u.air.max_speed;
00380 }
00381
00382 default: NOT_REACHED();
00383 }
00384 }
00385
00392 uint Engine::GetPower() const
00393 {
00394
00395 switch (this->type) {
00396 case VEH_TRAIN:
00397 return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power);
00398 case VEH_ROAD:
00399 return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->u.road.power) * 10;
00400
00401 default: NOT_REACHED();
00402 }
00403 }
00404
00410 uint Engine::GetDisplayWeight() const
00411 {
00412
00413 switch (this->type) {
00414 case VEH_TRAIN:
00415 return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
00416 case VEH_ROAD:
00417 return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->u.road.weight) / 4;
00418
00419 default: NOT_REACHED();
00420 }
00421 }
00422
00428 uint Engine::GetDisplayMaxTractiveEffort() const
00429 {
00430
00431 switch (this->type) {
00432 case VEH_TRAIN:
00433 return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
00434 case VEH_ROAD:
00435 return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
00436
00437 default: NOT_REACHED();
00438 }
00439 }
00440
00445 Date Engine::GetLifeLengthInDays() const
00446 {
00447
00448 return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * DAYS_IN_LEAP_YEAR;
00449 }
00450
00454 void EngineOverrideManager::ResetToDefaultMapping()
00455 {
00456 this->Clear();
00457 for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
00458 for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
00459 EngineIDMapping *eid = this->Append();
00460 eid->type = type;
00461 eid->grfid = INVALID_GRFID;
00462 eid->internal_id = internal_id;
00463 eid->substitute_id = internal_id;
00464 }
00465 }
00466 }
00467
00477 EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
00478 {
00479 const EngineIDMapping *end = this->End();
00480 EngineID index = 0;
00481 for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
00482 if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
00483 return index;
00484 }
00485 }
00486 return INVALID_ENGINE;
00487 }
00488
00494 bool EngineOverrideManager::ResetToCurrentNewGRFConfig()
00495 {
00496 const Vehicle *v;
00497 FOR_ALL_VEHICLES(v) {
00498 if (IsCompanyBuildableVehicleType(v)) return false;
00499 }
00500
00501
00502 _engine_mngr.ResetToDefaultMapping();
00503 ReloadNewGRFData();
00504
00505 return true;
00506 }
00507
00511 void SetupEngines()
00512 {
00513 DeleteWindowByClass(WC_ENGINE_PREVIEW);
00514 _engine_pool.CleanPool();
00515
00516 assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
00517 const EngineIDMapping *end = _engine_mngr.End();
00518 uint index = 0;
00519 for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
00520
00521
00522 assert(Engine::CanAllocateItem());
00523 const Engine *e = new Engine(eid->type, eid->internal_id);
00524 assert(e->index == index);
00525 }
00526
00527 _introduced_railtypes = 0;
00528 }
00529
00533 static void CheckRailIntroduction()
00534 {
00535
00536 if (_introduced_railtypes == UINT16_MAX || Company::GetPoolSize() == 0) return;
00537
00538
00539 RailTypes rts = (RailTypes)UINT16_MAX;
00540
00541
00542 Company *c;
00543 FOR_ALL_COMPANIES(c) {
00544 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date);
00545 rts &= c->avail_railtypes;
00546 }
00547
00548 _introduced_railtypes |= rts;
00549 }
00550
00551 void ShowEnginePreviewWindow(EngineID engine);
00552
00558 static bool IsWagon(EngineID index)
00559 {
00560 const Engine *e = Engine::Get(index);
00561 return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
00562 }
00563
00568 static void CalcEngineReliability(Engine *e)
00569 {
00570 uint age = e->age;
00571
00572
00573 if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
00574 int retire_early = e->info.retire_early;
00575 uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
00576 if (retire_early != 0 && age >= retire_early_max_age) {
00577
00578 e->company_avail = 0;
00579 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00580 }
00581 }
00582
00583 if (age < e->duration_phase_1) {
00584 uint start = e->reliability_start;
00585 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
00586 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
00587
00588
00589 e->reliability = e->reliability_max;
00590 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
00591 uint max = e->reliability_max;
00592 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
00593 } else {
00594
00595
00596 e->company_avail = 0;
00597 e->reliability = e->reliability_final;
00598
00599 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00600 }
00601 SetWindowClassesDirty(WC_BUILD_VEHICLE);
00602 SetWindowClassesDirty(WC_REPLACE_VEHICLE);
00603 }
00604
00606 void SetYearEngineAgingStops()
00607 {
00608
00609 _year_engine_aging_stops = 2050;
00610
00611 const Engine *e;
00612 FOR_ALL_ENGINES(e) {
00613 const EngineInfo *ei = &e->info;
00614
00615
00616 if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
00617 if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
00618
00619
00620 YearMonthDay ymd;
00621 ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd);
00622
00623 _year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year);
00624 }
00625 }
00626
00632 void StartupOneEngine(Engine *e, Date aging_date)
00633 {
00634 const EngineInfo *ei = &e->info;
00635
00636 e->age = 0;
00637 e->flags = 0;
00638 e->company_avail = 0;
00639
00640
00641
00642
00643 uint32 r = Random();
00644 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;
00645 if (e->intro_date <= _date) {
00646 e->age = (aging_date - e->intro_date) >> 5;
00647 e->company_avail = (CompanyMask)-1;
00648 e->flags |= ENGINE_AVAILABLE;
00649 }
00650
00651 e->reliability_start = GB(r, 16, 14) + 0x7AE0;
00652 r = Random();
00653 e->reliability_max = GB(r, 0, 14) + 0xBFFF;
00654 e->reliability_final = GB(r, 16, 14) + 0x3FFF;
00655
00656 r = Random();
00657 e->duration_phase_1 = GB(r, 0, 5) + 7;
00658 e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
00659 e->duration_phase_3 = GB(r, 9, 7) + 120;
00660
00661 e->reliability_spd_dec = ei->decay_speed << 2;
00662
00663 CalcEngineReliability(e);
00664
00665
00666 if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) {
00667 e->flags |= ENGINE_AVAILABLE;
00668 e->company_avail = 0;
00669 }
00670 }
00671
00676 void StartupEngines()
00677 {
00678 Engine *e;
00679
00680 const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
00681
00682 FOR_ALL_ENGINES(e) {
00683 StartupOneEngine(e, aging_date);
00684 }
00685
00686
00687 Company *c;
00688 FOR_ALL_COMPANIES(c) {
00689 c->avail_railtypes = GetCompanyRailtypes(c->index);
00690 c->avail_roadtypes = GetCompanyRoadtypes(c->index);
00691 }
00692
00693
00694
00695
00696
00697 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00698 const RailtypeInfo *rti = GetRailTypeInfo(rt);
00699 if (rti->label != 0 && IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue;
00700
00701 SetBit(_introduced_railtypes, rt);
00702 }
00703
00704 CheckRailIntroduction();
00705
00706
00707 InvalidateWindowClassesData(WC_BUILD_VEHICLE);
00708 }
00709
00715 static void AcceptEnginePreview(EngineID eid, CompanyID company)
00716 {
00717 Engine *e = Engine::Get(eid);
00718 Company *c = Company::Get(company);
00719
00720 SetBit(e->company_avail, company);
00721 if (e->type == VEH_TRAIN) {
00722 assert(e->u.rail.railtype < RAILTYPE_END);
00723 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
00724 } else if (e->type == VEH_ROAD) {
00725 SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00726 }
00727
00728 e->preview_company_rank = 0xFF;
00729 if (company == _local_company) {
00730 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00731 }
00732
00733
00734 if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD);
00735 if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER);
00736 }
00737
00743 static CompanyID GetBestCompany(uint8 pp)
00744 {
00745 CompanyID best_company;
00746 CompanyMask mask = 0;
00747
00748 do {
00749 int32 best_hist = -1;
00750 best_company = INVALID_COMPANY;
00751
00752 const Company *c;
00753 FOR_ALL_COMPANIES(c) {
00754 if (c->block_preview == 0 && !HasBit(mask, c->index) &&
00755 c->old_economy[0].performance_history > best_hist) {
00756 best_hist = c->old_economy[0].performance_history;
00757 best_company = c->index;
00758 }
00759 }
00760
00761 if (best_company == INVALID_COMPANY) return INVALID_COMPANY;
00762
00763 SetBit(mask, best_company);
00764 } while (--pp != 0);
00765
00766 return best_company;
00767 }
00768
00770 void EnginesDailyLoop()
00771 {
00772 CheckRailIntroduction();
00773
00774 if (_cur_year >= _year_engine_aging_stops) return;
00775
00776 Engine *e;
00777 FOR_ALL_ENGINES(e) {
00778 EngineID i = e->index;
00779 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00780 if (e->flags & ENGINE_OFFER_WINDOW_OPEN) {
00781 if (e->preview_company_rank != 0xFF && !--e->preview_wait) {
00782 e->flags &= ~ENGINE_OFFER_WINDOW_OPEN;
00783 DeleteWindowById(WC_ENGINE_PREVIEW, i);
00784 e->preview_company_rank++;
00785 }
00786 } else if (e->preview_company_rank != 0xFF) {
00787 CompanyID best_company = GetBestCompany(e->preview_company_rank);
00788
00789 if (best_company == INVALID_COMPANY) {
00790 e->preview_company_rank = 0xFF;
00791 continue;
00792 }
00793
00794 e->flags |= ENGINE_OFFER_WINDOW_OPEN;
00795 e->preview_wait = 20;
00796 AI::NewEvent(best_company, new ScriptEventEnginePreview(i));
00797 if (IsInteractiveCompany(best_company)) ShowEnginePreviewWindow(i);
00798 }
00799 }
00800 }
00801 }
00802
00813 CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00814 {
00815 Engine *e = Engine::GetIfValid(p1);
00816 if (e == NULL || GetBestCompany(e->preview_company_rank) != _current_company) return CMD_ERROR;
00817
00818 if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company);
00819
00820 return CommandCost();
00821 }
00822
00828 static void NewVehicleAvailable(Engine *e)
00829 {
00830 Vehicle *v;
00831 Company *c;
00832 EngineID index = e->index;
00833
00834
00835
00836 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00837 FOR_ALL_COMPANIES(c) {
00838 uint block_preview = c->block_preview;
00839
00840 if (!HasBit(e->company_avail, c->index)) continue;
00841
00842
00843 c->block_preview = 20;
00844
00845 FOR_ALL_VEHICLES(v) {
00846 if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP ||
00847 (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft())) {
00848 if (v->owner == c->index && v->engine_type == index) {
00849
00850 c->block_preview = block_preview;
00851 break;
00852 }
00853 }
00854 }
00855 }
00856 }
00857
00858 e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
00859 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00860
00861
00862 e->company_avail = (CompanyMask)-1;
00863
00864
00865 if (IsWagon(index)) return;
00866
00867 if (e->type == VEH_TRAIN) {
00868
00869 RailType railtype = e->u.rail.railtype;
00870 assert(railtype < RAILTYPE_END);
00871 FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
00872 } else if (e->type == VEH_ROAD) {
00873
00874 FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00875 }
00876
00877 AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
00878
00879 SetDParam(0, GetEngineCategoryName(index));
00880 SetDParam(1, index);
00881 AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, NR_ENGINE, index);
00882
00883
00884 if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD);
00885 if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER);
00886 }
00887
00888 void EnginesMonthlyLoop()
00889 {
00890 if (_cur_year < _year_engine_aging_stops) {
00891 Engine *e;
00892 FOR_ALL_ENGINES(e) {
00893
00894 if ((e->flags & ENGINE_AVAILABLE) && e->age != MAX_DAY) {
00895 e->age++;
00896 CalcEngineReliability(e);
00897 }
00898
00899
00900 if (!e->IsEnabled()) continue;
00901
00902 if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) {
00903
00904 NewVehicleAvailable(e);
00905 } else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
00906
00907 e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
00908
00909
00910 if (!IsWagon(e->index)) {
00911 e->preview_company_rank = 1;
00912 }
00913 }
00914 }
00915 }
00916 }
00917
00918 static bool IsUniqueEngineName(const char *name)
00919 {
00920 const Engine *e;
00921
00922 FOR_ALL_ENGINES(e) {
00923 if (e->name != NULL && strcmp(e->name, name) == 0) return false;
00924 }
00925
00926 return true;
00927 }
00928
00938 CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00939 {
00940 Engine *e = Engine::GetIfValid(p1);
00941 if (e == NULL) return CMD_ERROR;
00942
00943 bool reset = StrEmpty(text);
00944
00945 if (!reset) {
00946 if (Utf8StringLength(text) >= MAX_LENGTH_ENGINE_NAME_CHARS) return CMD_ERROR;
00947 if (!IsUniqueEngineName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
00948 }
00949
00950 if (flags & DC_EXEC) {
00951 free(e->name);
00952
00953 if (reset) {
00954 e->name = NULL;
00955 } else {
00956 e->name = strdup(text);
00957 }
00958
00959 MarkWholeScreenDirty();
00960 }
00961
00962 return CommandCost();
00963 }
00964
00965
00974 bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
00975 {
00976 const Engine *e = Engine::GetIfValid(engine);
00977
00978
00979 if (e == NULL) return false;
00980
00981
00982 if (e->type != type) return false;
00983
00984
00985 if (!HasBit(e->company_avail, company)) return false;
00986
00987 if (!e->IsEnabled()) return false;
00988
00989 if (type == VEH_TRAIN) {
00990
00991 const Company *c = Company::Get(company);
00992 if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false;
00993 }
00994
00995 return true;
00996 }
00997
01004 bool IsEngineRefittable(EngineID engine)
01005 {
01006 const Engine *e = Engine::GetIfValid(engine);
01007
01008
01009 if (e == NULL) return false;
01010
01011 if (!e->CanCarryCargo()) return false;
01012
01013 const EngineInfo *ei = &e->info;
01014 if (ei->refit_mask == 0) return false;
01015
01016
01017
01018 if (HasBit(ei->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) return true;
01019
01020
01021 CargoID default_cargo = e->GetDefaultCargoType();
01022 return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo;
01023 }