00001
00002
00005 #include "train.h"
00006 #include "roadveh.h"
00007 #include "ship.h"
00008 #include "aircraft.h"
00009 #include "articulated_vehicles.h"
00010 #include "textbuf_gui.h"
00011 #include "command_func.h"
00012 #include "company_func.h"
00013 #include "vehicle_gui.h"
00014 #include "newgrf_engine.h"
00015 #include "group.h"
00016 #include "strings_func.h"
00017 #include "window_func.h"
00018 #include "date_func.h"
00019 #include "vehicle_func.h"
00020 #include "gfx_func.h"
00021 #include "widgets/dropdown_func.h"
00022 #include "window_gui.h"
00023 #include "engine_gui.h"
00024 #include "settings_type.h"
00025
00026 #include "table/sprites.h"
00027 #include "table/strings.h"
00028
00029 enum BuildVehicleWidgets {
00030 BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
00031 BUILD_VEHICLE_WIDGET_CAPTION,
00032 BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
00033 BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
00034 BUILD_VEHICLE_WIDGET_LIST,
00035 BUILD_VEHICLE_WIDGET_SCROLLBAR,
00036 BUILD_VEHICLE_WIDGET_PANEL,
00037 BUILD_VEHICLE_WIDGET_BUILD,
00038 BUILD_VEHICLE_WIDGET_RENAME,
00039 BUILD_VEHICLE_WIDGET_RESIZE,
00040 BUILD_VEHICLE_WIDGET_END
00041 };
00042
00043 static const Widget _build_vehicle_widgets[] = {
00044 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
00045 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 239, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS },
00046 { WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
00047 { WWT_DROPDOWN, RESIZE_RIGHT, COLOUR_GREY, 81, 239, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
00048 { WWT_MATRIX, RESIZE_RB, COLOUR_GREY, 0, 227, 26, 39, 0x101, STR_NULL },
00049 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 228, 239, 26, 39, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST },
00050 { WWT_PANEL, RESIZE_RTB, COLOUR_GREY, 0, 239, 40, 161, 0x0, STR_NULL },
00051
00052 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 0, 114, 162, 173, 0x0, STR_NULL },
00053 { WWT_PUSHTXTBTN, RESIZE_RTB, COLOUR_GREY, 115, 227, 162, 173, 0x0, STR_NULL },
00054 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 228, 239, 162, 173, 0x0, STR_RESIZE_BUTTON },
00055 { WIDGETS_END},
00056 };
00057
00058
00059 static bool _internal_sort_order;
00060 static byte _last_sort_criteria[] = {0, 0, 0, 0};
00061 static bool _last_sort_order[] = {false, false, false, false};
00062
00063 static int CDECL EngineNumberSorter(const void *a, const void *b)
00064 {
00065 const EngineID va = *(const EngineID*)a;
00066 const EngineID vb = *(const EngineID*)b;
00067 int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
00068
00069 return _internal_sort_order ? -r : r;
00070 }
00071
00072 static int CDECL EngineIntroDateSorter(const void *a, const void *b)
00073 {
00074 const int va = GetEngine(*(const EngineID*)a)->intro_date;
00075 const int vb = GetEngine(*(const EngineID*)b)->intro_date;
00076 const int r = va - vb;
00077
00078
00079 if (r == 0) return EngineNumberSorter(a, b);
00080 return _internal_sort_order ? -r : r;
00081 }
00082
00083 static int CDECL EngineNameSorter(const void *a, const void *b)
00084 {
00085 static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
00086 static char last_name[2][64] = { "\0", "\0" };
00087
00088 const EngineID va = *(const EngineID*)a;
00089 const EngineID vb = *(const EngineID*)b;
00090
00091 if (va != last_engine[0]) {
00092 last_engine[0] = va;
00093 SetDParam(0, va);
00094 GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0]));
00095 }
00096
00097 if (vb != last_engine[1]) {
00098 last_engine[1] = vb;
00099 SetDParam(0, vb);
00100 GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1]));
00101 }
00102
00103 int r = strcmp(last_name[0], last_name[1]);
00104
00105
00106 if (r == 0) return EngineNumberSorter(a, b);
00107 return _internal_sort_order ? -r : r;
00108 }
00109
00110 static int CDECL EngineReliabilitySorter(const void *a, const void *b)
00111 {
00112 const int va = GetEngine(*(const EngineID*)a)->reliability;
00113 const int vb = GetEngine(*(const EngineID*)b)->reliability;
00114 const int r = va - vb;
00115
00116
00117 if (r == 0) return EngineNumberSorter(a, b);
00118 return _internal_sort_order ? -r : r;
00119 }
00120
00121 static int CDECL EngineCostSorter(const void *a, const void *b)
00122 {
00123 Money va = GetEngine(*(const EngineID*)a)->GetCost();
00124 Money vb = GetEngine(*(const EngineID*)b)->GetCost();
00125 int r = ClampToI32(va - vb);
00126
00127
00128 if (r == 0) return EngineNumberSorter(a, b);
00129 return _internal_sort_order ? -r : r;
00130 }
00131
00132 static int CDECL EngineSpeedSorter(const void *a, const void *b)
00133 {
00134 int va = GetEngine(*(const EngineID*)a)->GetDisplayMaxSpeed();
00135 int vb = GetEngine(*(const EngineID*)b)->GetDisplayMaxSpeed();
00136 int r = va - vb;
00137
00138
00139 if (r == 0) return EngineNumberSorter(a, b);
00140 return _internal_sort_order ? -r : r;
00141 }
00142
00143 static int CDECL EnginePowerSorter(const void *a, const void *b)
00144 {
00145 int va = GetEngine(*(const EngineID*)a)->GetPower();
00146 int vb = GetEngine(*(const EngineID*)b)->GetPower();
00147 int r = va - vb;
00148
00149
00150 if (r == 0) return EngineNumberSorter(a, b);
00151 return _internal_sort_order ? -r : r;
00152 }
00153
00154 static int CDECL EngineRunningCostSorter(const void *a, const void *b)
00155 {
00156 Money va = GetEngine(*(const EngineID*)a)->GetRunningCost();
00157 Money vb = GetEngine(*(const EngineID*)b)->GetRunningCost();
00158 int r = ClampToI32(va - vb);
00159
00160
00161 if (r == 0) return EngineNumberSorter(a, b);
00162 return _internal_sort_order ? -r : r;
00163 }
00164
00165
00166 static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b)
00167 {
00168 const Engine *e_a = GetEngine(*(const EngineID*)a);
00169 const Engine *e_b = GetEngine(*(const EngineID*)b);
00170
00171
00172
00173
00174
00175
00176
00177 Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower());
00178 Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower());
00179 int r = ClampToI32(vb - va);
00180
00181
00182 if (r == 0) return EngineNumberSorter(a, b);
00183 return _internal_sort_order ? -r : r;
00184 }
00185
00186 static int CDECL TrainEngineCapacitySorter(const void *a, const void *b)
00187 {
00188 const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
00189 const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
00190
00191 int va = GetTotalCapacityOfArticulatedParts(*(const EngineID*)a, VEH_TRAIN) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00192 int vb = GetTotalCapacityOfArticulatedParts(*(const EngineID*)b, VEH_TRAIN) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00193 int r = va - vb;
00194
00195
00196 if (r == 0) return EngineNumberSorter(a, b);
00197 return _internal_sort_order ? -r : r;
00198 }
00199
00200 static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b)
00201 {
00202 EngineID va = *(const EngineID*)a;
00203 EngineID vb = *(const EngineID*)b;
00204 int val_a = (RailVehInfo(va)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00205 int val_b = (RailVehInfo(vb)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00206 int r = val_a - val_b;
00207
00208
00209 if (r == 0) return EngineNumberSorter(a, b);
00210 return _internal_sort_order ? -r : r;
00211 }
00212
00213
00214 static int CDECL RoadVehEngineCapacitySorter(const void *a, const void *b)
00215 {
00216 int va = GetTotalCapacityOfArticulatedParts(*(const EngineID*)a, VEH_ROAD);
00217 int vb = GetTotalCapacityOfArticulatedParts(*(const EngineID*)b, VEH_ROAD);
00218 int r = va - vb;
00219
00220
00221 if (r == 0) return EngineNumberSorter(a, b);
00222 return _internal_sort_order ? -r : r;
00223 }
00224
00225
00226 static int CDECL ShipEngineCapacitySorter(const void *a, const void *b)
00227 {
00228 const Engine *e_a = GetEngine(*(const EngineID*)a);
00229 const Engine *e_b = GetEngine(*(const EngineID*)b);
00230
00231 int va = e_a->GetDisplayDefaultCapacity();
00232 int vb = e_b->GetDisplayDefaultCapacity();
00233 int r = va - vb;
00234
00235
00236 if (r == 0) return EngineNumberSorter(a, b);
00237 return _internal_sort_order ? -r : r;
00238 }
00239
00240
00241 static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
00242 {
00243 const Engine *e_a = GetEngine(*(const EngineID*)a);
00244 const Engine *e_b = GetEngine(*(const EngineID*)b);
00245
00246 int va = e_a->GetDisplayDefaultCapacity();
00247 int vb = e_b->GetDisplayDefaultCapacity();
00248 int r = va - vb;
00249
00250 if (r == 0) {
00251
00252 va = AircraftVehInfo(*(const EngineID*)a)->mail_capacity;
00253 vb = AircraftVehInfo(*(const EngineID*)b)->mail_capacity;
00254 r = va - vb;
00255
00256 if (r == 0) {
00257
00258 return EngineNumberSorter(a, b);
00259 }
00260 }
00261 return _internal_sort_order ? -r : r;
00262 }
00263
00264 static EngList_SortTypeFunction * const _sorter[][10] = {{
00265
00266 &EngineNumberSorter,
00267 &EngineCostSorter,
00268 &EngineSpeedSorter,
00269 &EnginePowerSorter,
00270 &EngineIntroDateSorter,
00271 &EngineNameSorter,
00272 &EngineRunningCostSorter,
00273 &TrainEnginePowerVsRunningCostSorter,
00274 &EngineReliabilitySorter,
00275 &TrainEngineCapacitySorter,
00276 }, {
00277
00278 &EngineNumberSorter,
00279 &EngineCostSorter,
00280 &EngineSpeedSorter,
00281 &EngineIntroDateSorter,
00282 &EngineNameSorter,
00283 &EngineRunningCostSorter,
00284 &EngineReliabilitySorter,
00285 &RoadVehEngineCapacitySorter,
00286 }, {
00287
00288 &EngineNumberSorter,
00289 &EngineCostSorter,
00290 &EngineSpeedSorter,
00291 &EngineIntroDateSorter,
00292 &EngineNameSorter,
00293 &EngineRunningCostSorter,
00294 &EngineReliabilitySorter,
00295 &ShipEngineCapacitySorter,
00296 }, {
00297
00298 &EngineNumberSorter,
00299 &EngineCostSorter,
00300 &EngineSpeedSorter,
00301 &EngineIntroDateSorter,
00302 &EngineNameSorter,
00303 &EngineRunningCostSorter,
00304 &EngineReliabilitySorter,
00305 &AircraftEngineCargoSorter,
00306 }};
00307
00308 static const StringID _sort_listing[][11] = {{
00309
00310 STR_ENGINE_SORT_ENGINE_ID,
00311 STR_ENGINE_SORT_COST,
00312 STR_SORT_BY_MAX_SPEED,
00313 STR_ENGINE_SORT_POWER,
00314 STR_ENGINE_SORT_INTRO_DATE,
00315 STR_SORT_BY_DROPDOWN_NAME,
00316 STR_ENGINE_SORT_RUNNING_COST,
00317 STR_ENGINE_SORT_POWER_VS_RUNNING_COST,
00318 STR_SORT_BY_RELIABILITY,
00319 STR_ENGINE_SORT_CARGO_CAPACITY,
00320 INVALID_STRING_ID
00321 }, {
00322
00323 STR_ENGINE_SORT_ENGINE_ID,
00324 STR_ENGINE_SORT_COST,
00325 STR_SORT_BY_MAX_SPEED,
00326 STR_ENGINE_SORT_INTRO_DATE,
00327 STR_SORT_BY_DROPDOWN_NAME,
00328 STR_ENGINE_SORT_RUNNING_COST,
00329 STR_SORT_BY_RELIABILITY,
00330 STR_ENGINE_SORT_CARGO_CAPACITY,
00331 INVALID_STRING_ID
00332 }, {
00333
00334 STR_ENGINE_SORT_ENGINE_ID,
00335 STR_ENGINE_SORT_COST,
00336 STR_SORT_BY_MAX_SPEED,
00337 STR_ENGINE_SORT_INTRO_DATE,
00338 STR_SORT_BY_DROPDOWN_NAME,
00339 STR_ENGINE_SORT_RUNNING_COST,
00340 STR_SORT_BY_RELIABILITY,
00341 STR_ENGINE_SORT_CARGO_CAPACITY,
00342 INVALID_STRING_ID
00343 }, {
00344
00345 STR_ENGINE_SORT_ENGINE_ID,
00346 STR_ENGINE_SORT_COST,
00347 STR_SORT_BY_MAX_SPEED,
00348 STR_ENGINE_SORT_INTRO_DATE,
00349 STR_SORT_BY_DROPDOWN_NAME,
00350 STR_ENGINE_SORT_RUNNING_COST,
00351 STR_SORT_BY_RELIABILITY,
00352 STR_ENGINE_SORT_CARGO_CAPACITY,
00353 INVALID_STRING_ID
00354 }};
00355
00356 static int DrawCargoCapacityInfo(int x, int y, EngineID engine, VehicleType type, bool refittable)
00357 {
00358 uint16 *cap = GetCapacityOfArticulatedParts(engine, type);
00359
00360 for (uint c = 0; c < NUM_CARGO; c++) {
00361 if (cap[c] == 0) continue;
00362
00363 SetDParam(0, c);
00364 SetDParam(1, cap[c]);
00365 SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
00366 DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00367 y += 10;
00368
00369
00370 refittable = false;
00371 }
00372
00373 return y;
00374 }
00375
00376
00377 static int DrawRailWagonPurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00378 {
00379 const Engine *e = GetEngine(engine_number);
00380
00381
00382 SetDParam(0, e->GetCost());
00383 DrawString(x, y, STR_PURCHASE_INFO_COST, TC_FROMSTRING);
00384 y += 10;
00385
00386
00387 uint weight = e->GetDisplayWeight();
00388 SetDParam(0, weight);
00389 uint cargo_weight = (e->CanCarryCargo() ? GetCargo(e->GetDefaultCargoType())->weight * e->GetDisplayDefaultCapacity() >> 4 : 0);
00390 SetDParam(1, cargo_weight + weight);
00391 DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, TC_FROMSTRING);
00392 y += 10;
00393
00394
00395 if (_settings_game.vehicle.wagon_speed_limits) {
00396 uint max_speed = e->GetDisplayMaxSpeed();
00397 if (max_speed > 0) {
00398 SetDParam(0, max_speed);
00399 DrawString(x, y, STR_PURCHASE_INFO_SPEED, TC_FROMSTRING);
00400 y += 10;
00401 }
00402 }
00403
00404
00405 if (rvi->running_cost_class != 0xFF) {
00406 SetDParam(0, e->GetRunningCost());
00407 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00408 y += 10;
00409 }
00410
00411 return y;
00412 }
00413
00414
00415 static int DrawRailEnginePurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00416 {
00417 const Engine *e = GetEngine(engine_number);
00418
00419
00420 SetDParam(0, e->GetCost());
00421 SetDParam(1, e->GetDisplayWeight());
00422 DrawString(x, y, STR_PURCHASE_INFO_COST_WEIGHT, TC_FROMSTRING);
00423 y += 10;
00424
00425
00426 SetDParam(0, e->GetDisplayMaxSpeed());
00427 SetDParam(1, e->GetPower());
00428 DrawString(x, y, STR_PURCHASE_INFO_SPEED_POWER, TC_FROMSTRING);
00429 y += 10;
00430
00431
00432 if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && rvi->railtype != RAILTYPE_MAGLEV) {
00433 SetDParam(0, e->GetDisplayMaxTractiveEffort());
00434 DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, TC_FROMSTRING);
00435 y += 10;
00436 }
00437
00438
00439 if (rvi->running_cost_class != 0xFF) {
00440 SetDParam(0, e->GetRunningCost());
00441 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00442 y += 10;
00443 }
00444
00445
00446 if (rvi->pow_wag_power != 0) {
00447 SetDParam(0, rvi->pow_wag_power);
00448 SetDParam(1, rvi->pow_wag_weight);
00449 DrawString(x, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, TC_FROMSTRING);
00450 y += 10;
00451 };
00452
00453 return y;
00454 }
00455
00456
00457 static int DrawRoadVehPurchaseInfo(int x, int y, EngineID engine_number)
00458 {
00459 const Engine *e = GetEngine(engine_number);
00460
00461
00462 SetDParam(0, e->GetCost());
00463 SetDParam(1, e->GetDisplayMaxSpeed());
00464 DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00465 y += 10;
00466
00467
00468 SetDParam(0, e->GetRunningCost());
00469 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00470 y += 10;
00471
00472 return y;
00473 }
00474
00475
00476 static int DrawShipPurchaseInfo(int x, int y, EngineID engine_number, const ShipVehicleInfo *svi, bool refittable)
00477 {
00478 const Engine *e = GetEngine(engine_number);
00479
00480
00481 SetDParam(0, e->GetCost());
00482 SetDParam(1, e->GetDisplayMaxSpeed());
00483 DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00484 y += 10;
00485
00486
00487 SetDParam(0, e->GetDefaultCargoType());
00488 SetDParam(1, e->GetDisplayDefaultCapacity());
00489 SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
00490 DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00491 y += 10;
00492
00493
00494 SetDParam(0, e->GetRunningCost());
00495 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00496 y += 10;
00497
00498 return y;
00499 }
00500
00501
00502 static int DrawAircraftPurchaseInfo(int x, int y, EngineID engine_number, const AircraftVehicleInfo *avi, bool refittable)
00503 {
00504 const Engine *e = GetEngine(engine_number);
00505 CargoID cargo = e->GetDefaultCargoType();
00506
00507
00508 SetDParam(0, e->GetCost());
00509 SetDParam(1, e->GetDisplayMaxSpeed());
00510 DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00511 y += 10;
00512
00513
00514 if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
00515 SetDParam(0, e->GetDisplayDefaultCapacity());
00516 SetDParam(1, avi->mail_capacity);
00517 DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, TC_FROMSTRING);
00518 } else {
00519
00520
00521 SetDParam(0, cargo);
00522 SetDParam(1, e->GetDisplayDefaultCapacity());
00523 SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
00524 DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00525 }
00526 y += 10;
00527
00528
00529 SetDParam(0, e->GetRunningCost());
00530 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00531 y += 10;
00532
00533 return y;
00534 }
00535
00543 int DrawVehiclePurchaseInfo(int x, int y, uint w, EngineID engine_number)
00544 {
00545 const Engine *e = GetEngine(engine_number);
00546 YearMonthDay ymd;
00547 ConvertDateToYMD(e->intro_date, &ymd);
00548 bool refittable = IsArticulatedVehicleRefittable(engine_number);
00549
00550 switch (e->type) {
00551 default: NOT_REACHED();
00552 case VEH_TRAIN: {
00553 const RailVehicleInfo *rvi = RailVehInfo(engine_number);
00554 if (rvi->railveh_type == RAILVEH_WAGON) {
00555 y = DrawRailWagonPurchaseInfo(x, y, engine_number, rvi);
00556 } else {
00557 y = DrawRailEnginePurchaseInfo(x, y, engine_number, rvi);
00558 }
00559
00560
00561 int new_y = DrawCargoCapacityInfo(x, y, engine_number, VEH_TRAIN, refittable);
00562
00563 if (new_y == y) {
00564 SetDParam(0, CT_INVALID);
00565 SetDParam(2, STR_EMPTY);
00566 DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00567 y += 10;
00568 } else {
00569 y = new_y;
00570 }
00571 break;
00572 }
00573 case VEH_ROAD: {
00574 y = DrawRoadVehPurchaseInfo(x, y, engine_number);
00575
00576
00577 int new_y = DrawCargoCapacityInfo(x, y, engine_number, VEH_ROAD, refittable);
00578
00579 if (new_y == y) {
00580 SetDParam(0, CT_INVALID);
00581 SetDParam(2, STR_EMPTY);
00582 DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00583 y += 10;
00584 } else {
00585 y = new_y;
00586 }
00587 break;
00588 }
00589 case VEH_SHIP:
00590 y = DrawShipPurchaseInfo(x, y, engine_number, ShipVehInfo(engine_number), refittable);
00591 break;
00592 case VEH_AIRCRAFT:
00593 y = DrawAircraftPurchaseInfo(x, y, engine_number, AircraftVehInfo(engine_number), refittable);
00594 break;
00595 }
00596
00597
00598 if (e->type != VEH_TRAIN || RailVehInfo(engine_number)->railveh_type != RAILVEH_WAGON) {
00599
00600 SetDParam(0, ymd.year);
00601 SetDParam(1, e->lifelength);
00602 DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, TC_FROMSTRING);
00603 y += 10;
00604
00605
00606 SetDParam(0, e->reliability * 100 >> 16);
00607 DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, TC_FROMSTRING);
00608 y += 10;
00609 }
00610
00611
00612 y += ShowAdditionalText(x, y, w, engine_number);
00613 if (refittable) y += ShowRefitOptionsList(x, y, w, engine_number);
00614
00615 return y;
00616 }
00617
00618 static void DrawVehicleEngine(VehicleType type, int x, int y, EngineID engine, SpriteID pal)
00619 {
00620 switch (type) {
00621 case VEH_TRAIN: DrawTrainEngine( x, y, engine, pal); break;
00622 case VEH_ROAD: DrawRoadVehEngine( x, y, engine, pal); break;
00623 case VEH_SHIP: DrawShipEngine( x, y, engine, pal); break;
00624 case VEH_AIRCRAFT: DrawAircraftEngine(x, y, engine, pal); break;
00625 default: NOT_REACHED();
00626 }
00627 }
00628
00638 void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, int count_location, GroupID selected_group)
00639 {
00640 byte step_size = GetVehicleListHeight(type);
00641 byte x_offset = 0;
00642 byte y_offset = 0;
00643
00644 assert(max <= eng_list->Length());
00645
00646 switch (type) {
00647 case VEH_TRAIN:
00648 x++;
00649
00650 case VEH_ROAD:
00651 x += 26;
00652 x_offset = 30;
00653 y += 2;
00654 y_offset = 4;
00655 break;
00656 case VEH_SHIP:
00657 x += 35;
00658 x_offset = 40;
00659 y += 7;
00660 y_offset = 3;
00661 break;
00662 case VEH_AIRCRAFT:
00663 x += 27;
00664 x_offset = 33;
00665 y += 7;
00666 y_offset = 3;
00667 break;
00668 default: NOT_REACHED();
00669 }
00670
00671 uint maxw = r - x - x_offset;
00672
00673 for (; min < max; min++, y += step_size) {
00674 const EngineID engine = (*eng_list)[min];
00675
00676 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
00677
00678 SetDParam(0, engine);
00679 DrawStringTruncated(x + x_offset, y, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK, maxw);
00680 DrawVehicleEngine(type, x, y + y_offset, engine, (count_location != 0 && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company));
00681 if (count_location != 0) {
00682 SetDParam(0, num_engines);
00683 DrawStringRightAligned(count_location, y + (GetVehicleListHeight(type) == 14 ? 3 : 8), STR_TINY_BLACK, TC_FROMSTRING);
00684 }
00685 }
00686 }
00687
00688
00689 struct BuildVehicleWindow : Window {
00690 VehicleType vehicle_type;
00691 union {
00692 RailTypeByte railtype;
00693 AirportFTAClass::Flags flags;
00694 RoadTypes roadtypes;
00695 } filter;
00696 bool descending_sort_order;
00697 byte sort_criteria;
00698 bool regenerate_list;
00699 bool listview_mode;
00700 EngineID sel_engine;
00701 EngineID rename_engine;
00702 GUIEngineList eng_list;
00703
00704 BuildVehicleWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile == INVALID_TILE ? (int)type : tile)
00705 {
00706 this->vehicle_type = type;
00707 int vlh = GetVehicleListHeight(this->vehicle_type);
00708
00709 ResizeWindow(this, 0, vlh - 14);
00710 this->resize.step_height = vlh;
00711 this->vscroll.cap = 1;
00712 this->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
00713
00714 this->resize.width = this->width;
00715 this->resize.height = this->height;
00716
00717 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
00718
00719 this->sel_engine = INVALID_ENGINE;
00720 this->regenerate_list = false;
00721
00722 this->sort_criteria = _last_sort_criteria[type];
00723 this->descending_sort_order = _last_sort_order[type];
00724
00725 switch (type) {
00726 default: NOT_REACHED();
00727 case VEH_TRAIN:
00728 this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile);
00729 break;
00730 case VEH_ROAD:
00731 this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile);
00732 case VEH_SHIP:
00733 break;
00734 case VEH_AIRCRAFT:
00735 this->filter.flags =
00736 tile == INVALID_TILE ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
00737 break;
00738 }
00739 this->SetupWindowStrings(type);
00740
00741 this->listview_mode = (this->window_number <= VEH_END);
00742
00743
00744 if (this->listview_mode) {
00745 this->HideWidget(BUILD_VEHICLE_WIDGET_BUILD);
00746 this->widget[BUILD_VEHICLE_WIDGET_RENAME].left = this->widget[BUILD_VEHICLE_WIDGET_BUILD].left;
00747 } else {
00748
00749 ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
00750 }
00751
00752 this->GenerateBuildList();
00753
00754 if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0];
00755
00756 this->FindWindowPlacementAndResize(desc);
00757 }
00758
00759
00760 void SetupWindowStrings(VehicleType type)
00761 {
00762 switch (type) {
00763 default: NOT_REACHED();
00764
00765 case VEH_TRAIN:
00766 this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = this->listview_mode ? STR_AVAILABLE_TRAINS : STR_JUST_STRING;
00767 this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_8843_TRAIN_VEHICLE_SELECTION;
00768 this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_881F_BUILD_VEHICLE;
00769 this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
00770 this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_8820_RENAME;
00771 this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
00772 break;
00773
00774 case VEH_ROAD:
00775 this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = this->listview_mode ? STR_AVAILABLE_ROAD_VEHICLES : STR_9006_NEW_ROAD_VEHICLES;
00776 this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9026_ROAD_VEHICLE_SELECTION;
00777 this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9007_BUILD_VEHICLE;
00778 this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
00779 this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9034_RENAME;
00780 this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
00781 break;
00782
00783 case VEH_SHIP:
00784 this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = this->listview_mode ? STR_AVAILABLE_SHIPS : STR_9808_NEW_SHIPS;
00785 this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9825_SHIP_SELECTION_LIST_CLICK;
00786 this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9809_BUILD_SHIP;
00787 this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
00788 this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9836_RENAME;
00789 this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
00790 break;
00791
00792 case VEH_AIRCRAFT:
00793 this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = this->listview_mode ? STR_AVAILABLE_AIRCRAFT : STR_A005_NEW_AIRCRAFT;
00794 this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_A025_AIRCRAFT_SELECTION_LIST;
00795 this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_A006_BUILD_AIRCRAFT;
00796 this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
00797 this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_A037_RENAME;
00798 this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
00799 break;
00800 }
00801 }
00802
00803
00804 void GenerateBuildTrainList()
00805 {
00806 EngineID sel_id = INVALID_ENGINE;
00807 int num_engines = 0;
00808 int num_wagons = 0;
00809
00810 this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number);
00811
00812 this->eng_list.Clear();
00813
00814
00815
00816
00817
00818 const Engine *e;
00819 FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
00820 EngineID eid = e->index;
00821 const RailVehicleInfo *rvi = &e->u.rail;
00822
00823 if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
00824 if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
00825
00826 *this->eng_list.Append() = eid;
00827
00828 if (rvi->railveh_type != RAILVEH_WAGON) {
00829 num_engines++;
00830 } else {
00831 num_wagons++;
00832 }
00833
00834 if (eid == this->sel_engine) sel_id = eid;
00835 }
00836
00837 this->sel_engine = sel_id;
00838
00839
00840 _internal_sort_order = false;
00841 EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
00842
00843
00844 _internal_sort_order = this->descending_sort_order;
00845 EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines);
00846
00847
00848 EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons);
00849 }
00850
00851
00852 void GenerateBuildRoadVehList()
00853 {
00854 EngineID sel_id = INVALID_ENGINE;
00855
00856 this->eng_list.Clear();
00857
00858 const Engine *e;
00859 FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
00860 EngineID eid = e->index;
00861 if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
00862 if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
00863 *this->eng_list.Append() = eid;
00864
00865 if (eid == this->sel_engine) sel_id = eid;
00866 }
00867 this->sel_engine = sel_id;
00868 }
00869
00870
00871 void GenerateBuildShipList()
00872 {
00873 EngineID sel_id = INVALID_ENGINE;
00874 this->eng_list.Clear();
00875
00876 const Engine *e;
00877 FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
00878 EngineID eid = e->index;
00879 if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
00880 *this->eng_list.Append() = eid;
00881
00882 if (eid == this->sel_engine) sel_id = eid;
00883 }
00884 this->sel_engine = sel_id;
00885 }
00886
00887
00888 void GenerateBuildAircraftList()
00889 {
00890 EngineID sel_id = INVALID_ENGINE;
00891
00892 this->eng_list.Clear();
00893
00894 const Station *st = this->listview_mode ? NULL : GetStationByTile(this->window_number);
00895
00896
00897
00898
00899
00900 const Engine *e;
00901 FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
00902 EngineID eid = e->index;
00903 if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
00904
00905 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
00906
00907 *this->eng_list.Append() = eid;
00908 if (eid == this->sel_engine) sel_id = eid;
00909 }
00910
00911 this->sel_engine = sel_id;
00912 }
00913
00914
00915 void GenerateBuildList()
00916 {
00917 switch (this->vehicle_type) {
00918 default: NOT_REACHED();
00919 case VEH_TRAIN:
00920 this->GenerateBuildTrainList();
00921 return;
00922 case VEH_ROAD:
00923 this->GenerateBuildRoadVehList();
00924 break;
00925 case VEH_SHIP:
00926 this->GenerateBuildShipList();
00927 break;
00928 case VEH_AIRCRAFT:
00929 this->GenerateBuildAircraftList();
00930 break;
00931 }
00932 _internal_sort_order = this->descending_sort_order;
00933 EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]);
00934 }
00935
00936 void OnClick(Point pt, int widget)
00937 {
00938 switch (widget) {
00939 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
00940 this->descending_sort_order ^= true;
00941 _last_sort_order[this->vehicle_type] = this->descending_sort_order;
00942 this->regenerate_list = true;
00943 this->SetDirty();
00944 break;
00945
00946 case BUILD_VEHICLE_WIDGET_LIST: {
00947 uint i = (pt.y - this->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(this->vehicle_type) + this->vscroll.pos;
00948 size_t num_items = this->eng_list.Length();
00949 this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
00950 this->SetDirty();
00951 break;
00952 }
00953
00954 case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:
00955 ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
00956 break;
00957
00958 case BUILD_VEHICLE_WIDGET_BUILD: {
00959 EngineID sel_eng = this->sel_engine;
00960 if (sel_eng != INVALID_ENGINE) {
00961 switch (this->vehicle_type) {
00962 default: NOT_REACHED();
00963 case VEH_TRAIN:
00964 DoCommandP(this->window_number, sel_eng, 0,
00965 CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE),
00966 (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco);
00967 break;
00968 case VEH_ROAD:
00969 DoCommandP(this->window_number, sel_eng, 0, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE), CcBuildRoadVeh);
00970 break;
00971 case VEH_SHIP:
00972 DoCommandP(this->window_number, sel_eng, 0, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP), CcBuildShip);
00973 break;
00974 case VEH_AIRCRAFT:
00975 DoCommandP(this->window_number, sel_eng, 0, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT), CcBuildAircraft);
00976 break;
00977 }
00978 }
00979 break;
00980 }
00981
00982 case BUILD_VEHICLE_WIDGET_RENAME: {
00983 EngineID sel_eng = this->sel_engine;
00984 if (sel_eng != INVALID_ENGINE) {
00985 StringID str = STR_NULL;
00986
00987 this->rename_engine = sel_eng;
00988 switch (this->vehicle_type) {
00989 default: NOT_REACHED();
00990 case VEH_TRAIN: str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
00991 case VEH_ROAD: str = STR_9036_RENAME_ROAD_VEHICLE_TYPE; break;
00992 case VEH_SHIP: str = STR_9838_RENAME_SHIP_TYPE; break;
00993 case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE; break;
00994 }
00995 SetDParam(0, sel_eng);
00996 ShowQueryString(STR_ENGINE_NAME, str, MAX_LENGTH_ENGINE_NAME_BYTES, MAX_LENGTH_ENGINE_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
00997 }
00998 break;
00999 }
01000 }
01001 }
01002
01003 virtual void OnInvalidateData(int data)
01004 {
01005 this->regenerate_list = true;
01006 }
01007
01008 virtual void OnPaint()
01009 {
01010 if (this->regenerate_list) {
01011 this->regenerate_list = false;
01012 this->GenerateBuildList();
01013 }
01014
01015 uint max = min(this->vscroll.pos + this->vscroll.cap, this->eng_list.Length());
01016
01017 SetVScrollCount(this, this->eng_list.Length());
01018 if (this->vehicle_type == VEH_TRAIN) {
01019 if (this->filter.railtype == RAILTYPE_END) {
01020 SetDParam(0, STR_ALL_AVAIL_RAIL_VEHICLES);
01021 } else {
01022 const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
01023 SetDParam(0, rti->strings.build_caption);
01024 }
01025 }
01026
01027
01028 this->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[this->vehicle_type][this->sort_criteria];
01029
01030 this->DrawWidgets();
01031
01032 DrawEngineList(this->vehicle_type, this->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, this->widget[BUILD_VEHICLE_WIDGET_LIST].right, this->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, &this->eng_list, this->vscroll.pos, max, this->sel_engine, 0, DEFAULT_GROUP);
01033
01034 if (this->sel_engine != INVALID_ENGINE) {
01035 const Widget *wi = &this->widget[BUILD_VEHICLE_WIDGET_PANEL];
01036 int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, this->sel_engine);
01037
01038 if (text_end > wi->bottom) {
01039 this->SetDirty();
01040 ResizeWindowForWidget(this, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
01041 this->SetDirty();
01042 }
01043 }
01044
01045 this->DrawSortButtonState(BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
01046 }
01047
01048 virtual void OnDoubleClick(Point pt, int widget)
01049 {
01050 if (widget == BUILD_VEHICLE_WIDGET_LIST) {
01051
01052 this->OnClick(pt, BUILD_VEHICLE_WIDGET_BUILD);
01053 }
01054 }
01055
01056 virtual void OnQueryTextFinished(char *str)
01057 {
01058 if (str == NULL) return;
01059
01060 StringID err_str = STR_NULL;
01061 switch (this->vehicle_type) {
01062 default: NOT_REACHED();
01063 case VEH_TRAIN: err_str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break;
01064 case VEH_ROAD: err_str = STR_9037_CAN_T_RENAME_ROAD_VEHICLE; break;
01065 case VEH_SHIP: err_str = STR_9839_CAN_T_RENAME_SHIP_TYPE; break;
01066 case VEH_AIRCRAFT: err_str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break;
01067 }
01068 DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(err_str), NULL, str);
01069 }
01070
01071 virtual void OnDropdownSelect(int widget, int index)
01072 {
01073 if (this->sort_criteria != index) {
01074 this->sort_criteria = index;
01075 _last_sort_criteria[this->vehicle_type] = this->sort_criteria;
01076 this->regenerate_list = true;
01077 }
01078 this->SetDirty();
01079 }
01080
01081 virtual void OnResize(Point new_size, Point delta)
01082 {
01083 if (delta.x != 0 && !this->listview_mode) {
01084 ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
01085 }
01086 if (delta.y == 0) return;
01087
01088 this->vscroll.cap += delta.y / (int)GetVehicleListHeight(this->vehicle_type);
01089 this->widget[BUILD_VEHICLE_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
01090 }
01091 };
01092
01093 static const WindowDesc _build_vehicle_desc(
01094 WDP_AUTO, WDP_AUTO, 240, 174, 240, 256,
01095 WC_BUILD_VEHICLE, WC_NONE,
01096 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE | WDF_CONSTRUCTION,
01097 _build_vehicle_widgets
01098 );
01099
01100 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
01101 {
01102
01103
01104
01105
01106 uint num = (tile == INVALID_TILE) ? (int)type : tile;
01107
01108 assert(IsCompanyBuildableVehicleType(type));
01109
01110 DeleteWindowById(WC_BUILD_VEHICLE, num);
01111
01112 new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
01113 }