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
00455 uint16 Engine::GetRange() const
00456 {
00457 switch (this->type) {
00458 case VEH_AIRCRAFT:
00459 return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
00460
00461 default: NOT_REACHED();
00462 }
00463 }
00464
00468 void EngineOverrideManager::ResetToDefaultMapping()
00469 {
00470 this->Clear();
00471 for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
00472 for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
00473 EngineIDMapping *eid = this->Append();
00474 eid->type = type;
00475 eid->grfid = INVALID_GRFID;
00476 eid->internal_id = internal_id;
00477 eid->substitute_id = internal_id;
00478 }
00479 }
00480 }
00481
00491 EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
00492 {
00493 const EngineIDMapping *end = this->End();
00494 EngineID index = 0;
00495 for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
00496 if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
00497 return index;
00498 }
00499 }
00500 return INVALID_ENGINE;
00501 }
00502
00508 bool EngineOverrideManager::ResetToCurrentNewGRFConfig()
00509 {
00510 const Vehicle *v;
00511 FOR_ALL_VEHICLES(v) {
00512 if (IsCompanyBuildableVehicleType(v)) return false;
00513 }
00514
00515
00516 _engine_mngr.ResetToDefaultMapping();
00517 ReloadNewGRFData();
00518
00519 return true;
00520 }
00521
00525 void SetupEngines()
00526 {
00527 DeleteWindowByClass(WC_ENGINE_PREVIEW);
00528 _engine_pool.CleanPool();
00529
00530 assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
00531 const EngineIDMapping *end = _engine_mngr.End();
00532 uint index = 0;
00533 for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
00534
00535
00536 assert(Engine::CanAllocateItem());
00537 const Engine *e = new Engine(eid->type, eid->internal_id);
00538 assert(e->index == index);
00539 }
00540
00541 _introduced_railtypes = 0;
00542 }
00543
00547 static void CheckRailIntroduction()
00548 {
00549
00550 if (_introduced_railtypes == UINT16_MAX || Company::GetPoolSize() == 0) return;
00551
00552
00553 RailTypes rts = (RailTypes)UINT16_MAX;
00554
00555
00556 Company *c;
00557 FOR_ALL_COMPANIES(c) {
00558 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date);
00559 rts &= c->avail_railtypes;
00560 }
00561
00562 _introduced_railtypes |= rts;
00563 }
00564
00565 void ShowEnginePreviewWindow(EngineID engine);
00566
00572 static bool IsWagon(EngineID index)
00573 {
00574 const Engine *e = Engine::Get(index);
00575 return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
00576 }
00577
00582 static void CalcEngineReliability(Engine *e)
00583 {
00584 uint age = e->age;
00585
00586
00587 if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
00588 int retire_early = e->info.retire_early;
00589 uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
00590 if (retire_early != 0 && age >= retire_early_max_age) {
00591
00592 e->company_avail = 0;
00593 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00594 }
00595 }
00596
00597 if (age < e->duration_phase_1) {
00598 uint start = e->reliability_start;
00599 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
00600 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
00601
00602
00603 e->reliability = e->reliability_max;
00604 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
00605 uint max = e->reliability_max;
00606 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
00607 } else {
00608
00609
00610 e->company_avail = 0;
00611 e->reliability = e->reliability_final;
00612
00613 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00614 }
00615 SetWindowClassesDirty(WC_BUILD_VEHICLE);
00616 SetWindowClassesDirty(WC_REPLACE_VEHICLE);
00617 }
00618
00620 void SetYearEngineAgingStops()
00621 {
00622
00623 _year_engine_aging_stops = 2050;
00624
00625 const Engine *e;
00626 FOR_ALL_ENGINES(e) {
00627 const EngineInfo *ei = &e->info;
00628
00629
00630 if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
00631 if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
00632
00633
00634 YearMonthDay ymd;
00635 ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd);
00636
00637 _year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year);
00638 }
00639 }
00640
00646 void StartupOneEngine(Engine *e, Date aging_date)
00647 {
00648 const EngineInfo *ei = &e->info;
00649
00650 e->age = 0;
00651 e->flags = 0;
00652 e->company_avail = 0;
00653
00654
00655
00656
00657 uint32 r = Random();
00658 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;
00659 if (e->intro_date <= _date) {
00660 e->age = (aging_date - e->intro_date) >> 5;
00661 e->company_avail = (CompanyMask)-1;
00662 e->flags |= ENGINE_AVAILABLE;
00663 }
00664
00665 e->reliability_start = GB(r, 16, 14) + 0x7AE0;
00666 r = Random();
00667 e->reliability_max = GB(r, 0, 14) + 0xBFFF;
00668 e->reliability_final = GB(r, 16, 14) + 0x3FFF;
00669
00670 r = Random();
00671 e->duration_phase_1 = GB(r, 0, 5) + 7;
00672 e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
00673 e->duration_phase_3 = GB(r, 9, 7) + 120;
00674
00675 e->reliability_spd_dec = ei->decay_speed << 2;
00676
00677 CalcEngineReliability(e);
00678
00679
00680 if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) {
00681 e->flags |= ENGINE_AVAILABLE;
00682 e->company_avail = 0;
00683 }
00684 }
00685
00690 void StartupEngines()
00691 {
00692 Engine *e;
00693
00694 const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
00695
00696 FOR_ALL_ENGINES(e) {
00697 StartupOneEngine(e, aging_date);
00698 }
00699
00700
00701 Company *c;
00702 FOR_ALL_COMPANIES(c) {
00703 c->avail_railtypes = GetCompanyRailtypes(c->index);
00704 c->avail_roadtypes = GetCompanyRoadtypes(c->index);
00705 }
00706
00707
00708
00709
00710
00711 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00712 const RailtypeInfo *rti = GetRailTypeInfo(rt);
00713 if (rti->label != 0 && IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue;
00714
00715 SetBit(_introduced_railtypes, rt);
00716 }
00717
00718 CheckRailIntroduction();
00719
00720
00721 InvalidateWindowClassesData(WC_BUILD_VEHICLE);
00722 }
00723
00729 static void AcceptEnginePreview(EngineID eid, CompanyID company)
00730 {
00731 Engine *e = Engine::Get(eid);
00732 Company *c = Company::Get(company);
00733
00734 SetBit(e->company_avail, company);
00735 if (e->type == VEH_TRAIN) {
00736 assert(e->u.rail.railtype < RAILTYPE_END);
00737 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
00738 } else if (e->type == VEH_ROAD) {
00739 SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00740 }
00741
00742 e->preview_company_rank = 0xFF;
00743 if (company == _local_company) {
00744 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00745 }
00746
00747
00748 if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD);
00749 if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER);
00750 }
00751
00757 static CompanyID GetBestCompany(uint8 pp)
00758 {
00759 CompanyID best_company;
00760 CompanyMask mask = 0;
00761
00762 do {
00763 int32 best_hist = -1;
00764 best_company = INVALID_COMPANY;
00765
00766 const Company *c;
00767 FOR_ALL_COMPANIES(c) {
00768 if (c->block_preview == 0 && !HasBit(mask, c->index) &&
00769 c->old_economy[0].performance_history > best_hist) {
00770 best_hist = c->old_economy[0].performance_history;
00771 best_company = c->index;
00772 }
00773 }
00774
00775 if (best_company == INVALID_COMPANY) return INVALID_COMPANY;
00776
00777 SetBit(mask, best_company);
00778 } while (--pp != 0);
00779
00780 return best_company;
00781 }
00782
00784 void EnginesDailyLoop()
00785 {
00786 CheckRailIntroduction();
00787
00788 if (_cur_year >= _year_engine_aging_stops) return;
00789
00790 Engine *e;
00791 FOR_ALL_ENGINES(e) {
00792 EngineID i = e->index;
00793 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00794 if (e->flags & ENGINE_OFFER_WINDOW_OPEN) {
00795 if (e->preview_company_rank != 0xFF && !--e->preview_wait) {
00796 e->flags &= ~ENGINE_OFFER_WINDOW_OPEN;
00797 DeleteWindowById(WC_ENGINE_PREVIEW, i);
00798 e->preview_company_rank++;
00799 }
00800 } else if (e->preview_company_rank != 0xFF) {
00801 CompanyID best_company = GetBestCompany(e->preview_company_rank);
00802
00803 if (best_company == INVALID_COMPANY) {
00804 e->preview_company_rank = 0xFF;
00805 continue;
00806 }
00807
00808 e->flags |= ENGINE_OFFER_WINDOW_OPEN;
00809 e->preview_wait = 20;
00810 AI::NewEvent(best_company, new ScriptEventEnginePreview(i));
00811 if (IsInteractiveCompany(best_company)) ShowEnginePreviewWindow(i);
00812 }
00813 }
00814 }
00815 }
00816
00827 CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00828 {
00829 Engine *e = Engine::GetIfValid(p1);
00830 if (e == NULL || GetBestCompany(e->preview_company_rank) != _current_company) return CMD_ERROR;
00831
00832 if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company);
00833
00834 return CommandCost();
00835 }
00836
00842 static void NewVehicleAvailable(Engine *e)
00843 {
00844 Vehicle *v;
00845 Company *c;
00846 EngineID index = e->index;
00847
00848
00849
00850 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
00851 FOR_ALL_COMPANIES(c) {
00852 uint block_preview = c->block_preview;
00853
00854 if (!HasBit(e->company_avail, c->index)) continue;
00855
00856
00857 c->block_preview = 20;
00858
00859 FOR_ALL_VEHICLES(v) {
00860 if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP ||
00861 (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft())) {
00862 if (v->owner == c->index && v->engine_type == index) {
00863
00864 c->block_preview = block_preview;
00865 break;
00866 }
00867 }
00868 }
00869 }
00870 }
00871
00872 e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
00873 AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
00874
00875
00876 e->company_avail = (CompanyMask)-1;
00877
00878
00879 if (IsWagon(index)) return;
00880
00881 if (e->type == VEH_TRAIN) {
00882
00883 RailType railtype = e->u.rail.railtype;
00884 assert(railtype < RAILTYPE_END);
00885 FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
00886 } else if (e->type == VEH_ROAD) {
00887
00888 FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
00889 }
00890
00891 AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
00892
00893 SetDParam(0, GetEngineCategoryName(index));
00894 SetDParam(1, index);
00895 AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, NR_ENGINE, index);
00896
00897
00898 if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD);
00899 if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER);
00900 }
00901
00902 void EnginesMonthlyLoop()
00903 {
00904 if (_cur_year < _year_engine_aging_stops) {
00905 Engine *e;
00906 FOR_ALL_ENGINES(e) {
00907
00908 if ((e->flags & ENGINE_AVAILABLE) && e->age != MAX_DAY) {
00909 e->age++;
00910 CalcEngineReliability(e);
00911 }
00912
00913
00914 if (!e->IsEnabled()) continue;
00915
00916 if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) {
00917
00918 NewVehicleAvailable(e);
00919 } else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
00920
00921 e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
00922
00923
00924 if (!IsWagon(e->index)) {
00925 e->preview_company_rank = 1;
00926 }
00927 }
00928 }
00929 }
00930 }
00931
00932 static bool IsUniqueEngineName(const char *name)
00933 {
00934 const Engine *e;
00935
00936 FOR_ALL_ENGINES(e) {
00937 if (e->name != NULL && strcmp(e->name, name) == 0) return false;
00938 }
00939
00940 return true;
00941 }
00942
00952 CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00953 {
00954 Engine *e = Engine::GetIfValid(p1);
00955 if (e == NULL) return CMD_ERROR;
00956
00957 bool reset = StrEmpty(text);
00958
00959 if (!reset) {
00960 if (Utf8StringLength(text) >= MAX_LENGTH_ENGINE_NAME_CHARS) return CMD_ERROR;
00961 if (!IsUniqueEngineName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
00962 }
00963
00964 if (flags & DC_EXEC) {
00965 free(e->name);
00966
00967 if (reset) {
00968 e->name = NULL;
00969 } else {
00970 e->name = strdup(text);
00971 }
00972
00973 MarkWholeScreenDirty();
00974 }
00975
00976 return CommandCost();
00977 }
00978
00979
00988 bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
00989 {
00990 const Engine *e = Engine::GetIfValid(engine);
00991
00992
00993 if (e == NULL) return false;
00994
00995
00996 if (e->type != type) return false;
00997
00998
00999 if (company != OWNER_DEITY && !HasBit(e->company_avail, company)) return false;
01000
01001 if (!e->IsEnabled()) return false;
01002
01003 if (type == VEH_TRAIN && company != OWNER_DEITY) {
01004
01005 const Company *c = Company::Get(company);
01006 if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false;
01007 }
01008
01009 return true;
01010 }
01011
01018 bool IsEngineRefittable(EngineID engine)
01019 {
01020 const Engine *e = Engine::GetIfValid(engine);
01021
01022
01023 if (e == NULL) return false;
01024
01025 if (!e->CanCarryCargo()) return false;
01026
01027 const EngineInfo *ei = &e->info;
01028 if (ei->refit_mask == 0) return false;
01029
01030
01031
01032 if (HasBit(ei->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) return true;
01033
01034
01035 CargoID default_cargo = e->GetDefaultCargoType();
01036 return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo;
01037 }